mirror of
https://github.com/strapi/strapi.git
synced 2025-11-03 03:17:11 +00:00
SelectTree: Handle react-select defaultValue
This commit is contained in:
parent
447713434f
commit
07737dad1a
@ -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,
|
||||
};
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
@ -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']);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user