Skip to content

Commit

Permalink
fix: πŸ› SQFormMultiValue accepts custom initial values
Browse files Browse the repository at this point in the history
SQFormMultiValue now accepts custom initial values as well as avoids
adding custom options to list of options displayed in the autocomplete
dropdown

βœ… Closes: #308
  • Loading branch information
20BBrown14 committed Jun 17, 2021
1 parent b575d9c commit 632ed3c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 8 deletions.
49 changes: 42 additions & 7 deletions src/components/SQForm/SQFormMultiValue.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Autocomplete from '@material-ui/lab/Autocomplete';
import {VariableSizeList} from 'react-window';
import {useField, useFormikContext} from 'formik';
import {useForm} from './useForm';
import {usePrevious} from '@selectquotelabs/sqhooks';

// MUI uses px, a numeric value is needed for calculations
const LISTBOX_PADDING = 8; // px
Expand Down Expand Up @@ -97,7 +98,7 @@ function SQFormMultiValue({
}) {
const classes = useStyles();
const clearButtonClasses = clearButtonStyles();
const [{value: fieldValue}] = useField(name);
const [{value: fieldValue}, {initialValue}] = useField(name);
const {setFieldValue, setTouched, touched} = useFormikContext();
const {
fieldState: {isFieldError},
Expand All @@ -109,8 +110,39 @@ function SQFormMultiValue({

const [inputValue, setInputValue] = React.useState('');
const [customOptions, setCustomOptions] = React.useState([]);
const displayOptions = React.useMemo(() => [...children, ...customOptions], [
children,
customOptions
]);
const previousInitialValue = usePrevious(initialValue);

const initialValue = [];
React.useEffect(() => {
// Don't run this effect every time displayOptions changes
// This also prevents infinite rerenders
if (JSON.stringify(previousInitialValue) === JSON.stringify(initialValue)) {
return;
}

const displayValues = displayOptions.reduce((acc, option) => {
acc.push(option.value);
return acc;
}, []);

const nonOptionValues = initialValue.filter(value => {
return !displayValues.includes(value);
});

const newCustomOptions = nonOptionValues.map(newCustomOptionValue => {
return {
label: newCustomOptionValue,
value: newCustomOptionValue
};
});

setCustomOptions(previousCustomOptions => {
return [...previousCustomOptions, ...newCustomOptions];
});
}, [initialValue, displayOptions, previousInitialValue]);

const handleAutocompleteBlur = React.useCallback(
event => {
Expand Down Expand Up @@ -190,21 +222,24 @@ function SQFormMultiValue({
[onInputChange]
);

const autocompleteOptions = [...children, ...customOptions];

return (
<Grid item sm={size}>
<Autocomplete
classes={classes}
multiple={true}
id={name}
options={autocompleteOptions}
options={children}
freeSolo={true}
renderTags={(value, getTagProps) => {
return value.map((optionValue, index) => {
const tagOption = autocompleteOptions.find(autocompleteOption => {
const tagOption = displayOptions.find(autocompleteOption => {
return autocompleteOption.value === optionValue;
});

if (!tagOption) {
return null;
}

return (
<Chip
variant="outlined"
Expand All @@ -216,7 +251,7 @@ function SQFormMultiValue({
}}
ListboxComponent={ListboxVirtualizedComponent}
getOptionLabel={option => option.label || ''}
value={fieldValue || initialValue || []}
value={fieldValue || []}
inputValue={inputValue}
onBlur={handleAutocompleteBlur}
onChange={handleAutocompleteChange}
Expand Down
2 changes: 1 addition & 1 deletion stories/SQFormMultiValue.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const Template = args => {
return (
<div style={{minWidth: 250}}>
<SQFormStoryWrapper
initialValues={{[defaultArgs.name]: ['red', 'green']}}
initialValues={{[defaultArgs.name]: ['red', 'green', 'Custom Option']}}
validationSchema={validationSchema}
{...SQFormProps}
>
Expand Down

0 comments on commit 632ed3c

Please sign in to comment.