diff --git a/packages/react-drylus/src/forms/MultiSelect.tsx b/packages/react-drylus/src/forms/MultiSelect.tsx index 40e44bbf..8985f066 100644 --- a/packages/react-drylus/src/forms/MultiSelect.tsx +++ b/packages/react-drylus/src/forms/MultiSelect.tsx @@ -1,6 +1,6 @@ import sv from '@drawbotics/drylus-style-vars'; import { css, cx } from 'emotion'; -import React, { ReactNode } from 'react'; +import React, { ReactNode, useState } from 'react'; import Select, { ActionMeta, GroupBase, @@ -107,8 +107,11 @@ export interface MultiSelectOption extends Option { } export interface MultiSelectProps { - /** The options to show in the list of options, note that label and value may differ depending on valueKey and labelKey */ - options: Array>; + /** + * The options to show in the list of options, note that label and value may differ depending on valueKey and labelKey + * If this is not provided, the component will behave like as a multiple input field, with dropdown and select functionality disabled + * */ + options?: Array>; /** Determines which values are currently active */ values: @@ -173,6 +176,8 @@ export const MultiSelect = ({ const error = isFunction(props.error) ? props.error(props.name) : props.error; const values = isFunction(props.values) ? props.values(props.name) : props.values; + const [temporaryInput, setTemporaryInput] = useState(""); + const baseProps = { isMulti: true, options: props.options, @@ -181,15 +186,20 @@ export const MultiSelect = ({ isSearchable: true, isClearable: false, defaultValue: null, - value: props.options.filter((o) => { + value: props.options ? props.options.filter((o) => { return values.includes(o.value); - }), + }) : values.map((value) => ({ + label: value, + value: value + } as unknown as MultiSelectOption)), onChange: ( options: MultiValue>, action: ActionMeta>, ) => { + setTemporaryInput(""); + if (props.onChangeOptions && action.action === 'create-option') { - props.onChangeOptions([...props.options, action.option]); + props.onChangeOptions([...(props.options ?? []), action.option]); } if (props.onChange) { @@ -208,6 +218,7 @@ export const MultiSelect = ({ [styles.error]: error != null && error !== false, }), components: { + DropdownIndicator: props.options ? components.DropdownIndicator : null, IndicatorsContainer: ( indicatorContainerProps: React.PropsWithChildren< IndicatorsContainerProps, true, GroupBase>> @@ -243,6 +254,8 @@ export const MultiSelect = ({ ); + } else { + return null } })} @@ -261,14 +274,39 @@ export const MultiSelect = ({ }, props.className, )}> - {props.onChangeOptions ? ( - , true> - {...baseProps} - formatCreateLabel={props.formatCreateLabel ?? ((inputValue) => `+ ${inputValue}`)} - /> - ) : ( - , true> {...baseProps} /> - )} + {run(() => { + if (!props.options) { + return , true> + {...baseProps} + inputValue={temporaryInput} + isClearable={false} + isMulti + menuIsOpen={false} + onInputChange={(inputValue: string) => { + setTemporaryInput(inputValue) + }} + onKeyDown={(event) => { + if (!temporaryInput) return; + switch (event.key) { + case 'Enter': + case 'Tab': + setTemporaryInput(""); + props.onChange?.([...values, temporaryInput as unknown as T], props.name) + event.preventDefault(); + } + }} + formatCreateLabel={props.formatCreateLabel ?? ((inputValue) => `+ ${inputValue}`)} + /> + } else if (props.onChangeOptions) { + return , true> + {...baseProps} + formatCreateLabel={props.formatCreateLabel ?? ((inputValue) => `+ ${inputValue}`)} + /> + } else { + return , true> {...baseProps} /> + + } + })} {run(() => { if (error && typeof error === 'string') { return {error}; diff --git a/packages/styleguide/app/pages/component-kit/forms/multi-select.mdx b/packages/styleguide/app/pages/component-kit/forms/multi-select.mdx index 569714a1..10dd8ba2 100644 --- a/packages/styleguide/app/pages/component-kit/forms/multi-select.mdx +++ b/packages/styleguide/app/pages/component-kit/forms/multi-select.mdx @@ -83,4 +83,16 @@ This can be useful if you want the user to pick all the options (i.e. without de )} - \ No newline at end of file + + +### Multi Select as an input for multiple text + +
+ + } + /> +
+