SelectTree: Handle react-select defaultValue

This commit is contained in:
Gustav Hansen 2022-04-08 15:54:43 +02:00
parent 447713434f
commit 07737dad1a
4 changed files with 91 additions and 10 deletions

View File

@ -5,23 +5,22 @@ import { ReactSelect as Select } from '@strapi/helper-plugin';
import Option from './Option';
import flattenTree from './utils/flattenTree';
import getOpenValues from './utils/getOpenValues';
const hasParent = option => !option.parent;
const hasParentOrMatchesValue = (option, value) =>
option.value === value || option.parent === value;
const SelectTree = ({ options: defaultOptions, maxDisplayDepth, ...props }) => {
const SelectTree = ({ options: defaultOptions, maxDisplayDepth, defaultValue, ...props }) => {
const flatDefaultOptions = useMemo(() => flattenTree(defaultOptions), [defaultOptions]);
const toplevelDefaultOptions = useMemo(() => flatDefaultOptions.filter(hasParent), [
flatDefaultOptions,
]);
const [options, setOptions] = useState(toplevelDefaultOptions);
const [openValues, setOpenValues] = useState([]);
const optionsFiltered = useMemo(() => flatDefaultOptions.filter(hasParent), [flatDefaultOptions]);
const [options, setOptions] = useState(optionsFiltered);
const [openValues, setOpenValues] = useState(getOpenValues(flatDefaultOptions, defaultValue));
useEffect(() => {
if (openValues.length === 0) {
setOptions(toplevelDefaultOptions);
setOptions(optionsFiltered);
}
openValues.forEach(value => {
@ -31,7 +30,7 @@ const SelectTree = ({ options: defaultOptions, maxDisplayDepth, ...props }) => {
setOptions(filtered);
});
}, [openValues, flatDefaultOptions, toplevelDefaultOptions]);
}, [openValues, flatDefaultOptions, optionsFiltered]);
function handleToggle(e, value) {
e.preventDefault();
@ -58,13 +57,14 @@ const SelectTree = ({ options: defaultOptions, maxDisplayDepth, ...props }) => {
),
}}
options={options}
defaultValue={defaultValue}
{...props}
/>
);
};
const OptionShape = PropTypes.shape({
value: PropTypes.number.isRequired,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
label: PropTypes.string.isRequired,
children: PropTypes.array,
});
@ -76,10 +76,14 @@ OptionShape.defaultProps = {
};
SelectTree.defaultProps = {
defaultValue: undefined,
maxDisplayDepth: 5,
};
SelectTree.propTypes = {
defaultValue: PropTypes.shape({
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
}),
maxDisplayDepth: PropTypes.number,
options: PropTypes.arrayOf(OptionShape).isRequired,
};

View File

@ -1,3 +1,4 @@
import { useState } from 'react';
import { Meta, ArgsTable, Canvas, Story } from '@storybook/addon-docs';
import SelectTree from './index';
@ -13,6 +14,7 @@ into `react-select` are forwarded.
<Canvas>
<Story name="base">
{() => {
const [value, setValue] = useState(null);
const options = [
{
value: 1,
@ -47,7 +49,12 @@ into `react-select` are forwarded.
label: 'Folder 3'
}
];
return (<SelectTree options={options} onChange={props => console.log(props)} />)
return (
<>
<SelectTree options={options} defaultValue={{ value: 22 }} onChange={({ value }) => setValue(value)} />
<p>Selected Value: {value}</p>
</>
)
}}
</Story>
</Canvas>

View File

@ -0,0 +1,25 @@
function getOpenValues(options, defaultValue) {
let values = [];
const { value } = defaultValue;
const option = options.find(option => option.value === value);
if (!option) {
return values;
}
values.push(option.value);
let { parent } = option;
while (parent) {
// eslint-disable-next-line no-loop-func
const option = options.find(({ value }) => value === parent);
values.push(option.value);
parent = option.parent;
}
return values;
}
export default getOpenValues;

View File

@ -0,0 +1,45 @@
import flattenTree from '../flattenTree';
import getOpenValues from '../getOpenValues';
const FIXTURE = flattenTree([
{
value: 'f-1',
label: 'Folder 1',
},
{
value: 'f-2',
label: 'Folder 2',
children: [
{
value: 'f-2-1',
label: 'Folder 2-1',
},
{
value: 'f-2-2',
label: 'Folder 2-2',
children: [
{
value: 'f-2-2-1',
label: 'Folder 2-2-1',
},
],
},
],
},
]);
describe('getOpenValues', () => {
test('returns 1 value for depth = 1', () => {
expect(getOpenValues(FIXTURE, 'f-1')).toStrictEqual(['f-1']);
});
test('returns 2 values for depth = 2', () => {
expect(getOpenValues(FIXTURE, 'f-2-1')).toStrictEqual(['f-2-1', 'f-2']);
});
test('returns 3 values for depth = 3', () => {
expect(getOpenValues(FIXTURE, 'f-2-2-1')).toStrictEqual(['f-2-2-1', 'f-2-2', 'f-2']);
});
});