UNPKG

jobiqo-cl

Version:

[![CircleCI](https://circleci.com/gh/jobiqo/jobiqo-cl.svg?style=svg&circle-token=5a24efa5b8bbc4879276123e77d0d3f35ca7144c)](https://circleci.com/gh/jobiqo/jobiqo-cl)

225 lines (219 loc) 9.61 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); var styled = require('styled-components'); var styled__default = _interopDefault(styled); var index = require('../../11-form-item/index.js'); var downshift_esm = require('../../../../../../node_modules/downshift/dist/downshift.esm.js'); var matchSorter_esm = require('../../../../../../node_modules/match-sorter/dist/match-sorter.esm.js'); var subElements = require('./sub-elements/sub-elements.js'); /** * @file index.tsx * * @fileoverview Renders a multi element select component using the downshift library. */ const ItemLabel = styled__default.span ` display: inlineBlock; padding: ${props => props.theme.select.dropMenu.itemSelected.padding}; color: ${props => props.theme.select.dropMenu.itemSelected.color}; background: ${props => props.theme.select.dropMenu.itemSelected.background}; text-transform: uppercase; border-radius: ${props => props.theme.select.dropMenu.itemSelected.borderRadius}; margin-left: auto; font-size: ${props => props.theme.select.dropMenu.itemSelected.fontSize}; margin-left: 0.5rem; `; const InputWrapper = styled__default.div ` outline: 0; display: flex; flex-wrap: wrap; flex-direction: row; align-items: center; transition: box-shadow 0.1s ease, width 0.1s ease; font-size: ${props => props.theme.select.fontSize}; margin: ${props => props.theme.select.margin}; padding: ${props => props.theme.select.multiple.padding}; border-radius: ${props => props.theme.select.borderRadius}; border-width: ${props => props.theme.select.borderWidth}; border-style: ${props => props.theme.select.borderStyle}; border-color: ${props => props.error ? props.theme.colors.danger : props.theme.select.borderColor}; background: ${props => props.theme.select.background}; max-width: ${props => props.theme.select.multiple.input.width}; &:focus-within { outline: 0; border-color: ${props => props.theme.colors.focusRingColor}; box-shadow: ${props => props.theme.select.focus.boxShadowType}, ${props => `${props.theme.select.focus.boxShadowVals} ${props.theme.colors.focusRingColor}`}; } `; const DownshiftInput = styled__default.input ` word-wrap: break-word; outline: 0; background: transparent; display: inline-block; box-shadow: none; border: 0; margin: ${props => props.theme.select.multiple.input.margin}; font-size: ${props => props.theme.select.fontSize}; width: 50%; `; const SpanElement = styled__default.span ` margin: ${props => props.theme.select.multiple.tags.margin}; font-size: ${props => props.theme.select.multiple.tags.fontSize}; padding: ${props => props.theme.tag.padding}; border-radius: ${props => props.theme.tag.borderRadius}; background: ${props => props.theme.tag.background}; border-width: ${props => props.theme.tag.borderWidth}; border-style: ${props => props.theme.tag.borderStyle}; border-color: ${props => props.theme.tag.borderColor}; `; const ItemsWrapper = styled__default.div ` background: ${props => props.theme.select.dropMenu.background}; max-height: ${props => props.theme.select.dropMenu.maxHeight}; border-right-width: ${props => props.theme.select.dropMenu.borderWidth}; border-bottom-width: ${props => props.theme.select.dropMenu.borderWidth}; border-left-width: ${props => props.theme.select.dropMenu.borderWidth}; border-radius: ${props => props.theme.select.dropMenu.borderRadius}; border-color: ${props => props.theme.select.dropMenu.borderColor}; box-shadow: ${props => props.theme.select.dropMenu.boxShadow}; border-top-width: 0; overflow-y: auto; overflow-x: hidden; outline: 0; transition: opacity 0.1s ease; border-style: solid; `; const parentStyle = { width: '100%' }; /** * A multiple autotocomplet widget for when the user needs to select multiple elements in a select-style element. */ class MultipleAutocomplete extends React__default.Component { constructor() { super(...arguments); this.state = { input: '', selectedItems: [] }; /** * handles the key down event which will show all items in the dropdown. * * @param {any} evt * The event of key down. */ this.handleKeyDown = (evt) => { const { values } = this.props; if (values.length && !this.state.input.length && evt.keyCode === 8) { this.props.onChange(values.slice(0, values.length - 1)); } }; /** * Handles an input change when we type something in the input box. * * Will set the internal state with what was typed. * * @param {any} evt * The event. */ this.handleInputChange = (evt) => { this.setState({ input: evt.target.value }); if (this.props.onInputChange) { this.props.onInputChange(evt.target.value); } }; /** * Handles a change event on the dropdwon element. * * When we actually choose something in the dropdown this will set the onChange event (fire external) * and will also clear the input. * * @param {SelectItem} item * The item that was just selected. */ this.handleChange = (item) => { this.props.onChange([...this.props.values, item.code]); this.setState({ input: '' }); }; } /** * Based on the key of a item return its full item with name as well. * * @param {string} key * The key to get the item from. */ getItemNameFormSelectedItem(key) { const items = this.props.items.filter(item => item.code === key); if (items.length > 0) { return items[0].name; } return null; } render() { const { id, values, placeholder, label, required = false, error = false, onBlur } = this.props; // We get a new input from the user. We need to check for the names that match. And then we // map to selectedItem types. const { input } = this.state; const itemNames = input.length ? matchSorter_esm.default(this.props.items.map(i => i.name), input) : this.props.items.map(i => i.name); const items = this.props.items.filter(item => { return itemNames.includes(item.name); }); const indices = mapItemIndex(items, values); return (React__default.createElement(index.FormItem, null, label && (React__default.createElement(index.FormLabel, { error: error, required: required, htmlFor: id }, label)), React__default.createElement(downshift_esm.default, { inputValue: this.state.input, onChange: this.handleChange, selectedItem: values, itemToString: item => (item ? item.code : '') }, ({ getInputProps, getItemProps, getRootProps, getLabelProps, highlightedIndex, isOpen, selectedItem }) => (React__default.createElement("div", { style: parentStyle }, React__default.createElement(InputWrapper, { error: error }, selectedItem.map((value, i) => (React__default.createElement(SpanElement, { key: value }, this.getItemNameFormSelectedItem(value)))), React__default.createElement(DownshiftInput, Object.assign({}, getInputProps({ placeholder, id, onChange: this.handleInputChange, onKeyDown: this.handleKeyDown, onBlur })))), isOpen && (React__default.createElement(ItemsWrapper, null, items.map(item => { const selected = this.props.values.indexOf(item.code) !== -1; const props = selected ? {} : getItemProps({ item, index: indices[item.code], isSelected: selected }); return (React__default.createElement(subElements.Item, Object.assign({}, props, { isActive: highlightedIndex === indices[item.code], key: item.code }), item.name, selected && React__default.createElement(ItemLabel, null, "Selected"))); })))))))); } } MultipleAutocomplete.defaultProps = { placeholder: 'Search something here...', items: [] }; /** * Get the real index of an item. * * It does this filtering out selected values, and mapping the values to the index. * We're doing so that Downshift doesn't recognize selected item, * thus won't highlight the selected item. * * Given that ['Black', 'Blue', 'Green'], and 'Blue' is selected * Output: { 'Black': 0, 'Green': 1 } * * @param {SelectItem[]} items items * @param {String[]} values selected items * @return {Object} Mapping of selected items to their indices */ function mapItemIndex(items, values) { return items .filter(item => values.indexOf(item.code) === -1) .reduce((prev, next, i) => { prev[next.code] = i; return prev; }, {}); } exports.MultipleAutocomplete = MultipleAutocomplete;