mirror of
https://github.com/strapi/strapi.git
synced 2025-11-13 00:29:51 +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 Option from './Option';
|
||||||
|
|
||||||
import flattenTree from './utils/flattenTree';
|
import flattenTree from './utils/flattenTree';
|
||||||
|
import getOpenValues from './utils/getOpenValues';
|
||||||
|
|
||||||
const hasParent = option => !option.parent;
|
const hasParent = option => !option.parent;
|
||||||
|
|
||||||
const hasParentOrMatchesValue = (option, value) =>
|
const hasParentOrMatchesValue = (option, value) =>
|
||||||
option.value === value || option.parent === 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 flatDefaultOptions = useMemo(() => flattenTree(defaultOptions), [defaultOptions]);
|
||||||
const toplevelDefaultOptions = useMemo(() => flatDefaultOptions.filter(hasParent), [
|
const optionsFiltered = useMemo(() => flatDefaultOptions.filter(hasParent), [flatDefaultOptions]);
|
||||||
flatDefaultOptions,
|
const [options, setOptions] = useState(optionsFiltered);
|
||||||
]);
|
const [openValues, setOpenValues] = useState(getOpenValues(flatDefaultOptions, defaultValue));
|
||||||
const [options, setOptions] = useState(toplevelDefaultOptions);
|
|
||||||
const [openValues, setOpenValues] = useState([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (openValues.length === 0) {
|
if (openValues.length === 0) {
|
||||||
setOptions(toplevelDefaultOptions);
|
setOptions(optionsFiltered);
|
||||||
}
|
}
|
||||||
|
|
||||||
openValues.forEach(value => {
|
openValues.forEach(value => {
|
||||||
@ -31,7 +30,7 @@ const SelectTree = ({ options: defaultOptions, maxDisplayDepth, ...props }) => {
|
|||||||
|
|
||||||
setOptions(filtered);
|
setOptions(filtered);
|
||||||
});
|
});
|
||||||
}, [openValues, flatDefaultOptions, toplevelDefaultOptions]);
|
}, [openValues, flatDefaultOptions, optionsFiltered]);
|
||||||
|
|
||||||
function handleToggle(e, value) {
|
function handleToggle(e, value) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -58,13 +57,14 @@ const SelectTree = ({ options: defaultOptions, maxDisplayDepth, ...props }) => {
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
options={options}
|
options={options}
|
||||||
|
defaultValue={defaultValue}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const OptionShape = PropTypes.shape({
|
const OptionShape = PropTypes.shape({
|
||||||
value: PropTypes.number.isRequired,
|
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
children: PropTypes.array,
|
children: PropTypes.array,
|
||||||
});
|
});
|
||||||
@ -76,10 +76,14 @@ OptionShape.defaultProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SelectTree.defaultProps = {
|
SelectTree.defaultProps = {
|
||||||
|
defaultValue: undefined,
|
||||||
maxDisplayDepth: 5,
|
maxDisplayDepth: 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
SelectTree.propTypes = {
|
SelectTree.propTypes = {
|
||||||
|
defaultValue: PropTypes.shape({
|
||||||
|
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||||
|
}),
|
||||||
maxDisplayDepth: PropTypes.number,
|
maxDisplayDepth: PropTypes.number,
|
||||||
options: PropTypes.arrayOf(OptionShape).isRequired,
|
options: PropTypes.arrayOf(OptionShape).isRequired,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
import { Meta, ArgsTable, Canvas, Story } from '@storybook/addon-docs';
|
import { Meta, ArgsTable, Canvas, Story } from '@storybook/addon-docs';
|
||||||
import SelectTree from './index';
|
import SelectTree from './index';
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ into `react-select` are forwarded.
|
|||||||
<Canvas>
|
<Canvas>
|
||||||
<Story name="base">
|
<Story name="base">
|
||||||
{() => {
|
{() => {
|
||||||
|
const [value, setValue] = useState(null);
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
value: 1,
|
value: 1,
|
||||||
@ -47,7 +49,12 @@ into `react-select` are forwarded.
|
|||||||
label: 'Folder 3'
|
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>
|
</Story>
|
||||||
</Canvas>
|
</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