Improuve multi select

In multi select with acceptNewValues option alway keep the new value as the first item in the list to make it easier to add it
This commit is contained in:
Paul Chavard 2021-02-18 18:38:56 +01:00
parent 20f4ca8512
commit 24f71ccc1a

View file

@ -31,23 +31,46 @@ function ComboMultipleDropdownList({
if (label == undefined) { if (label == undefined) {
label = 'Choisir une option'; label = 'Choisir une option';
} }
if (Array.isArray(options[0]) == false) { if (!Array.isArray(options[0])) {
options = options.map((o) => [o, o]); options = options.filter((o) => o).map((o) => [o, o]);
} }
const inputRef = useRef(); const inputRef = useRef();
const [term, setTerm] = useState(''); const [term, setTerm] = useState('');
const [selections, setSelections] = useState(selected); const [selections, setSelections] = useState(selected);
const [newValues, setNewValues] = useState([]); const [newValues, setNewValues] = useState([]);
const optionValueByLabel = (label) => {
const maybeOption = newValues.includes(label)
? [label, label]
: options.find(([optionLabel]) => optionLabel == label);
return maybeOption ? maybeOption[1] : undefined;
};
const optionLabelByValue = (value) => {
const maybeOption = newValues.includes(value)
? [value, value]
: options.find(([, optionValue]) => optionValue == value);
return maybeOption ? maybeOption[0] : undefined;
};
const extraOptions = useMemo(
() =>
acceptNewValues && term && term.length > 2 && !optionLabelByValue(term)
? [[term, term]]
: [],
[acceptNewValues, term, newValues.join(',')]
);
const results = useMemo( const results = useMemo(
() => () =>
(term [
? matchSorter( ...extraOptions,
options.filter((o) => !o[0].startsWith('--')), ...(term
term ? matchSorter(
) options.filter(([label]) => !label.startsWith('--')),
: options term
).filter((o) => o[0] && !selections.includes(o[1])), )
[term, selections.join(',')] : options)
].filter(([, value]) => !selections.includes(value)),
[term, selections.join(','), newValues.join(',')]
); );
const hiddenField = useMemo( const hiddenField = useMemo(
() => document.querySelector(`input[data-uuid="${hiddenFieldId}"]`), () => document.querySelector(`input[data-uuid="${hiddenFieldId}"]`),
@ -60,22 +83,12 @@ function ComboMultipleDropdownList({
const onKeyDown = (event) => { const onKeyDown = (event) => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
if (term && options.map((o) => o[0]).includes(term)) {
event.preventDefault();
return onSelect(term);
}
if ( if (
acceptNewValues &&
term && term &&
matchSorter( [...extraOptions, ...options].map(([label]) => label).includes(term)
options.map((o) => o[0]),
term
).length == 0 // ignore when was pressed for selecting popover option
) { ) {
event.preventDefault(); event.preventDefault();
setNewValues([...newValues, term]); return onSelect(term);
saveSelection([...selections, term]);
setTerm('');
} }
} }
}; };
@ -89,19 +102,23 @@ function ComboMultipleDropdownList({
}; };
const onSelect = (value) => { const onSelect = (value) => {
let sel = options.find((o) => o[0] == value)[1]; const maybeValue = [...extraOptions, ...options].find(
saveSelection([...selections, sel]); ([val]) => val == value
);
const selectedValue = maybeValue && maybeValue[1];
if (value) {
setNewValues([...newValues, selectedValue]);
saveSelection([...selections, selectedValue]);
}
setTerm(''); setTerm('');
}; };
const onRemove = (value) => { const onRemove = (label) => {
saveSelection( const optionValue = optionValueByLabel(label);
selections.filter((s) => if (optionValue) {
newValues.includes(value) saveSelection(selections.filter((value) => value != optionValue));
? s != value setNewValues(newValues.filter((value) => value != optionValue));
: s !== options.find((o) => o[0] == value)[1] }
)
);
inputRef.current.focus(); inputRef.current.focus();
}; };
@ -116,10 +133,7 @@ function ComboMultipleDropdownList({
{selections.map((selection) => ( {selections.map((selection) => (
<ComboboxToken <ComboboxToken
key={selection} key={selection}
value={ value={optionLabelByValue(selection)}
newValues.find((newValue) => newValue == selection) ||
options.find((o) => o[1] == selection)[0]
}
/> />
))} ))}
</ul> </ul>
@ -136,21 +150,15 @@ function ComboMultipleDropdownList({
{results.length === 0 && ( {results.length === 0 && (
<p> <p>
Aucun résultat{' '} Aucun résultat{' '}
<button <button onClick={() => setTerm('')}>Effacer</button>
onClick={() => {
setTerm('');
}}
>
Effacer
</button>
</p> </p>
)} )}
<ComboboxList> <ComboboxList>
{results.map((value, index) => { {results.map(([label], index) => {
if (value[0].startsWith('--')) { if (label.startsWith('--')) {
return <ComboboxSeparator key={index} value={value[0]} />; return <ComboboxSeparator key={index} value={label} />;
} }
return <ComboboxOption key={index} value={value[0]} />; return <ComboboxOption key={index} value={label} />;
})} })}
</ComboboxList> </ComboboxList>
</ComboboxPopover> </ComboboxPopover>