@mtes-mct/monitor-ui 6.3.2 → 6.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/fields/MultiSelect.d.ts +3 -1
- package/fields/Select.d.ts +3 -1
- package/index.js +43 -68
- package/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [6.3.2](https://github.com/MTES-MCT/monitor-ui/compare/v6.3.1...v6.3.2) (2023-05-25)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **libs:** make CustomSearch fully functional ([931dda0](https://github.com/MTES-MCT/monitor-ui/commit/931dda03e79ba3710d9ae0d14a45305e0c57b819))
|
|
7
|
+
|
|
1
8
|
## [6.3.1](https://github.com/MTES-MCT/monitor-ui/compare/v6.3.0...v6.3.1) (2023-05-24)
|
|
2
9
|
|
|
3
10
|
|
package/fields/MultiSelect.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type MultiSelectProps<OptionValue extends OptionValueType = string> = Omi
|
|
|
6
6
|
/** Used to pass something else than `window.document` as a base container to attach global events listeners. */
|
|
7
7
|
baseContainer?: Document | HTMLDivElement | null | undefined;
|
|
8
8
|
customSearch?: CustomSearch<Option<OptionValue>> | undefined;
|
|
9
|
+
/** Minimum search query length required to trigger custom search filtering. */
|
|
10
|
+
customSearchMinQueryLength?: number | undefined;
|
|
9
11
|
error?: string | undefined;
|
|
10
12
|
isErrorMessageHidden?: boolean | undefined;
|
|
11
13
|
isLabelHidden?: boolean | undefined;
|
|
@@ -18,4 +20,4 @@ export type MultiSelectProps<OptionValue extends OptionValueType = string> = Omi
|
|
|
18
20
|
options: Option<OptionValue>[];
|
|
19
21
|
value?: OptionValue[] | undefined;
|
|
20
22
|
};
|
|
21
|
-
export declare function MultiSelect<OptionValue extends OptionValueType = string>({ baseContainer, customSearch, disabled, error, isErrorMessageHidden, isLabelHidden, isLight, isUndefinedWhenDisabled, label, onChange, options, optionValueKey, searchable, value, ...originalProps }: MultiSelectProps<OptionValue>): JSX.Element;
|
|
23
|
+
export declare function MultiSelect<OptionValue extends OptionValueType = string>({ baseContainer, customSearch, customSearchMinQueryLength, disabled, error, isErrorMessageHidden, isLabelHidden, isLight, isUndefinedWhenDisabled, label, onChange, options, optionValueKey, searchable, value, ...originalProps }: MultiSelectProps<OptionValue>): JSX.Element;
|
package/fields/Select.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type SelectProps<OptionValue extends OptionValueType = string> = Omit<Sel
|
|
|
6
6
|
/** Used to pass something else than `window.document` as a base container to attach global events listeners. */
|
|
7
7
|
baseContainer?: Document | HTMLDivElement | null | undefined;
|
|
8
8
|
customSearch?: CustomSearch<Option<OptionValue>> | undefined;
|
|
9
|
+
/** Minimum search query length required to trigger custom search filtering. */
|
|
10
|
+
customSearchMinQueryLength?: number | undefined;
|
|
9
11
|
error?: string | undefined;
|
|
10
12
|
isCleanable?: boolean | undefined;
|
|
11
13
|
isErrorMessageHidden?: boolean | undefined;
|
|
@@ -19,4 +21,4 @@ export type SelectProps<OptionValue extends OptionValueType = string> = Omit<Sel
|
|
|
19
21
|
options: Option<OptionValue>[];
|
|
20
22
|
value?: OptionValue | undefined;
|
|
21
23
|
};
|
|
22
|
-
export declare function Select<OptionValue extends OptionValueType = string>({ baseContainer, customSearch, disabled, error, isCleanable, isErrorMessageHidden, isLabelHidden, isLight, isUndefinedWhenDisabled, label, onChange, options, optionValueKey, searchable, value, ...originalProps }: SelectProps<OptionValue>): JSX.Element;
|
|
24
|
+
export declare function Select<OptionValue extends OptionValueType = string>({ baseContainer, customSearch, customSearchMinQueryLength, disabled, error, isCleanable, isErrorMessageHidden, isLabelHidden, isLight, isUndefinedWhenDisabled, label, onChange, options, optionValueKey, searchable, value, ...originalProps }: SelectProps<OptionValue>): JSX.Element;
|
package/index.js
CHANGED
|
@@ -25681,47 +25681,19 @@ class CustomSearch {
|
|
|
25681
25681
|
}
|
|
25682
25682
|
}
|
|
25683
25683
|
|
|
25684
|
-
function MultiSelect({ baseContainer, customSearch, disabled = false, error, isErrorMessageHidden = false, isLabelHidden = false, isLight = false, isUndefinedWhenDisabled = false, label, onChange, options, optionValueKey, searchable = false, value, ...originalProps }) {
|
|
25684
|
+
function MultiSelect({ baseContainer, customSearch, customSearchMinQueryLength = 1, disabled = false, error, isErrorMessageHidden = false, isLabelHidden = false, isLight = false, isUndefinedWhenDisabled = false, label, onChange, options, optionValueKey, searchable = false, value, ...originalProps }) {
|
|
25685
25685
|
// eslint-disable-next-line no-null/no-null
|
|
25686
25686
|
const boxRef = useRef(null);
|
|
25687
|
-
/**
|
|
25688
|
-
* Current list of option labels found by `CustomSearch.find()` for the current select search query
|
|
25689
|
-
*
|
|
25690
|
-
* @description
|
|
25691
|
-
* `undefined` means that search query is empty, thus all labels should be a match.
|
|
25692
|
-
*/
|
|
25693
|
-
const customSearchLabelMatchesRef = useRef(undefined);
|
|
25694
25687
|
/** Instance of `CustomSearch` */
|
|
25695
25688
|
const customSearchRef = useRef(customSearch);
|
|
25696
|
-
/** Last search query (only used when `customSearch` prop is set) */
|
|
25697
|
-
const previousSearchQueryRef = useRef('');
|
|
25698
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
25699
25689
|
const controlledError = useMemo(() => normalizeString(error), [error]);
|
|
25700
25690
|
const rsuiteData = useMemo(() => getRsuiteDataFromOptions(options, optionValueKey), [options, optionValueKey]);
|
|
25701
25691
|
const hasError = useMemo(() => Boolean(controlledError), [controlledError]);
|
|
25702
25692
|
const key = useKey([disabled, originalProps.name, value]);
|
|
25703
25693
|
const selectedRsuiteValue = useMemo(() => (value || []).map(valueItem => getRsuiteValueFromOptionValue(valueItem, optionValueKey)), [optionValueKey, value]);
|
|
25704
|
-
|
|
25705
|
-
|
|
25706
|
-
|
|
25707
|
-
// and we use the `customSearchLabelMatches` ref-stored results, in the form of option labels,
|
|
25708
|
-
// to check if the current option label is part of these results.
|
|
25709
|
-
// Note that options label are expected to be unique in order for this pattern to work.
|
|
25710
|
-
customSearchRef.current
|
|
25711
|
-
? (query, _label, item) => {
|
|
25712
|
-
if (!customSearchRef.current) {
|
|
25713
|
-
throw new Error('`customSearchRef.current` is undefined.');
|
|
25714
|
-
}
|
|
25715
|
-
// Since this function will be called xN times, N being the number of options,
|
|
25716
|
-
// we only want to update found option labels once each time the search query changes.
|
|
25717
|
-
if (query !== previousSearchQueryRef.current) {
|
|
25718
|
-
const nextCustomSearchLabelMatches = query.trim().length > 0 ? customSearchRef.current.find(query).map(option => option.label) : undefined;
|
|
25719
|
-
customSearchLabelMatchesRef.current = nextCustomSearchLabelMatches;
|
|
25720
|
-
previousSearchQueryRef.current = query;
|
|
25721
|
-
}
|
|
25722
|
-
return customSearchLabelMatchesRef.current ? customSearchLabelMatchesRef.current.includes(item.label) : true;
|
|
25723
|
-
}
|
|
25724
|
-
: undefined, []);
|
|
25694
|
+
// Only used when `customSearch` prop is set
|
|
25695
|
+
const [controlledRsuiteData, setControlledRsuiteData] = useState(customSearch ? rsuiteData : undefined);
|
|
25696
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
25725
25697
|
const { forceUpdate } = useForceUpdate();
|
|
25726
25698
|
const close = useCallback(() => {
|
|
25727
25699
|
setIsOpen(false);
|
|
@@ -25738,8 +25710,18 @@ function MultiSelect({ baseContainer, customSearch, disabled = false, error, isE
|
|
|
25738
25710
|
}
|
|
25739
25711
|
const nextValue = nextOptionRsuiteValues ? getOptionValuesFromRsuiteDataValues(nextOptionRsuiteValues) : [];
|
|
25740
25712
|
const normalizedNextValue = nextValue.length > 0 ? nextValue : undefined;
|
|
25713
|
+
setControlledRsuiteData(rsuiteData);
|
|
25741
25714
|
onChange(normalizedNextValue);
|
|
25742
|
-
}, [getOptionValuesFromRsuiteDataValues, onChange]);
|
|
25715
|
+
}, [getOptionValuesFromRsuiteDataValues, onChange, rsuiteData]);
|
|
25716
|
+
const handleSearch = useCallback((nextQuery) => {
|
|
25717
|
+
if (!customSearchRef.current || nextQuery.trim().length < customSearchMinQueryLength) {
|
|
25718
|
+
return;
|
|
25719
|
+
}
|
|
25720
|
+
const nextControlledRsuiteData = nextQuery.trim().length >= customSearchMinQueryLength
|
|
25721
|
+
? getRsuiteDataFromOptions(customSearchRef.current.find(nextQuery), optionValueKey)
|
|
25722
|
+
: rsuiteData;
|
|
25723
|
+
setControlledRsuiteData(nextControlledRsuiteData);
|
|
25724
|
+
}, [customSearchMinQueryLength, optionValueKey, rsuiteData]);
|
|
25743
25725
|
const renderMenuItem = useCallback((node) => jsx("span", { title: String(node), children: String(node) }), []);
|
|
25744
25726
|
const toggle = useCallback((event) => {
|
|
25745
25727
|
let targetElement = event.target;
|
|
@@ -25759,7 +25741,13 @@ function MultiSelect({ baseContainer, customSearch, disabled = false, error, isE
|
|
|
25759
25741
|
useEffect(() => {
|
|
25760
25742
|
forceUpdate();
|
|
25761
25743
|
}, [forceUpdate]);
|
|
25762
|
-
return (jsxs(Field$2, { className: "Field-MultiSelect", children: [jsx(Label, { disabled: disabled, hasError: hasError, htmlFor: originalProps.name, isHidden: isLabelHidden, children: label }), jsx(Box$4, { ref: boxRef, "$hasError": hasError, "$isActive": isOpen, "$isLight": isLight, onClick: toggle, children: boxRef.current && (jsx(TagPicker, { container: boxRef.current,
|
|
25744
|
+
return (jsxs(Field$2, { className: "Field-MultiSelect", children: [jsx(Label, { disabled: disabled, hasError: hasError, htmlFor: originalProps.name, isHidden: isLabelHidden, children: label }), jsx(Box$4, { ref: boxRef, "$hasError": hasError, "$isActive": isOpen, "$isLight": isLight, onClick: toggle, children: boxRef.current && (jsx(TagPicker, { container: boxRef.current,
|
|
25745
|
+
// When we use a custom search, we use `controlledRsuiteData` to provide the matching options (data),
|
|
25746
|
+
// when we don't, we don't need to control that and just pass the non-internally-controlled `rsuiteData`
|
|
25747
|
+
data: controlledRsuiteData || rsuiteData, disabled: disabled, id: originalProps.name, onChange: handleChange, onClick: toggle, onSearch: handleSearch, open: isOpen, renderMenuItem: renderMenuItem, searchable: !!customSearch || searchable,
|
|
25748
|
+
// When we use a custom search, we use `controlledRsuiteData` to provide the matching options (data),
|
|
25749
|
+
// that's why we send this "always true" filter to disable Rsuite TagPicker internal search filtering
|
|
25750
|
+
searchBy: (customSearch ? () => true : undefined), value: selectedRsuiteValue, ...originalProps }, key)) }), !isErrorMessageHidden && hasError && jsx(FieldError, { children: controlledError })] }));
|
|
25763
25751
|
}
|
|
25764
25752
|
const Box$4 = styled.div `
|
|
25765
25753
|
position: relative;
|
|
@@ -34943,48 +34931,20 @@ const StyledFieldset = styled(Fieldset) `
|
|
|
34943
34931
|
}
|
|
34944
34932
|
`;
|
|
34945
34933
|
|
|
34946
|
-
function Select({ baseContainer, customSearch, disabled = false, error, isCleanable = true, isErrorMessageHidden = false, isLabelHidden = false, isLight = false, isUndefinedWhenDisabled = false, label, onChange, options, optionValueKey, searchable = false, value, ...originalProps }) {
|
|
34934
|
+
function Select({ baseContainer, customSearch, customSearchMinQueryLength = 1, disabled = false, error, isCleanable = true, isErrorMessageHidden = false, isLabelHidden = false, isLight = false, isUndefinedWhenDisabled = false, label, onChange, options, optionValueKey, searchable = false, value, ...originalProps }) {
|
|
34947
34935
|
// eslint-disable-next-line no-null/no-null
|
|
34948
34936
|
const boxRef = useRef(null);
|
|
34949
|
-
/**
|
|
34950
|
-
* Current list of option labels found by `CustomSearch.find()` for the current select search query
|
|
34951
|
-
*
|
|
34952
|
-
* @description
|
|
34953
|
-
* `undefined` means that search query is empty, thus all labels should be a match.
|
|
34954
|
-
*/
|
|
34955
|
-
const customSearchLabelMatchesRef = useRef(undefined);
|
|
34956
34937
|
/** Instance of `CustomSearch` */
|
|
34957
34938
|
const customSearchRef = useRef(customSearch);
|
|
34958
|
-
/** Last search query (only used when `customSearch` prop is set) */
|
|
34959
|
-
const previousSearchQueryRef = useRef('');
|
|
34960
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
34961
34939
|
const { forceUpdate } = useForceUpdate();
|
|
34962
34940
|
const controlledError = useMemo(() => normalizeString(error), [error]);
|
|
34963
34941
|
const rsuiteData = useMemo(() => getRsuiteDataFromOptions(options, optionValueKey), [options, optionValueKey]);
|
|
34964
34942
|
const hasError = useMemo(() => Boolean(controlledError), [controlledError]);
|
|
34965
34943
|
const key = useKey([disabled, originalProps.name, value]);
|
|
34966
34944
|
const selectedRsuiteValue = useMemo(() => getRsuiteValueFromOptionValue(value, optionValueKey), [value, optionValueKey]);
|
|
34967
|
-
|
|
34968
|
-
|
|
34969
|
-
|
|
34970
|
-
// and we use the `customSearchLabelMatches` ref-stored results, in the form of option labels,
|
|
34971
|
-
// to check if the current option label is part of these results.
|
|
34972
|
-
// Note that options label are expected to be unique in order for this pattern to work.
|
|
34973
|
-
customSearchRef.current
|
|
34974
|
-
? (query, _label, item) => {
|
|
34975
|
-
if (!customSearchRef.current) {
|
|
34976
|
-
throw new Error('`customSearchRef.current` is undefined.');
|
|
34977
|
-
}
|
|
34978
|
-
// Since this function will be called xN times, N being the number of options,
|
|
34979
|
-
// we only want to update found option labels once each time the search query changes.
|
|
34980
|
-
if (query !== previousSearchQueryRef.current) {
|
|
34981
|
-
const nextCustomSearchLabelMatches = query.trim().length > 0 ? customSearchRef.current.find(query).map(option => option.label) : undefined;
|
|
34982
|
-
customSearchLabelMatchesRef.current = nextCustomSearchLabelMatches;
|
|
34983
|
-
previousSearchQueryRef.current = query;
|
|
34984
|
-
}
|
|
34985
|
-
return customSearchLabelMatchesRef.current ? customSearchLabelMatchesRef.current.includes(item.label) : true;
|
|
34986
|
-
}
|
|
34987
|
-
: undefined, []);
|
|
34945
|
+
// Only used when `customSearch` prop is set
|
|
34946
|
+
const [controlledRsuiteData, setControlledRsuiteData] = useState(customSearch ? rsuiteData : undefined);
|
|
34947
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
34988
34948
|
const close = useCallback(() => {
|
|
34989
34949
|
setIsOpen(false);
|
|
34990
34950
|
}, []);
|
|
@@ -34994,6 +34954,15 @@ function Select({ baseContainer, customSearch, disabled = false, error, isCleana
|
|
|
34994
34954
|
}
|
|
34995
34955
|
onChange(undefined);
|
|
34996
34956
|
}, [onChange]);
|
|
34957
|
+
const handleSearch = useCallback((nextQuery) => {
|
|
34958
|
+
if (!customSearchRef.current || nextQuery.trim().length < customSearchMinQueryLength) {
|
|
34959
|
+
return;
|
|
34960
|
+
}
|
|
34961
|
+
const nextControlledRsuiteData = nextQuery.trim().length >= customSearchMinQueryLength
|
|
34962
|
+
? getRsuiteDataFromOptions(customSearchRef.current.find(nextQuery), optionValueKey)
|
|
34963
|
+
: rsuiteData;
|
|
34964
|
+
setControlledRsuiteData(nextControlledRsuiteData);
|
|
34965
|
+
}, [customSearchMinQueryLength, optionValueKey, rsuiteData]);
|
|
34997
34966
|
const handleSelect = useCallback((_, selectedItem) => {
|
|
34998
34967
|
close();
|
|
34999
34968
|
if (onChange) {
|
|
@@ -35021,10 +34990,16 @@ function Select({ baseContainer, customSearch, disabled = false, error, isCleana
|
|
|
35021
34990
|
useEffect(() => {
|
|
35022
34991
|
forceUpdate();
|
|
35023
34992
|
}, [forceUpdate]);
|
|
35024
|
-
return (jsxs(Field$2, { className: "Field-Select", children: [jsx(Label, { disabled: disabled, hasError: hasError, htmlFor: originalProps.name, isHidden: isLabelHidden, children: label }), jsx(Box, { ref: boxRef, onClick: toggle, children: boxRef.current && (jsx(StyledSelectPicker, { "$isLight": isLight, cleanable: isCleanable, container: boxRef.current,
|
|
34993
|
+
return (jsxs(Field$2, { className: "Field-Select", children: [jsx(Label, { disabled: disabled, hasError: hasError, htmlFor: originalProps.name, isHidden: isLabelHidden, children: label }), jsx(Box, { ref: boxRef, onClick: toggle, children: boxRef.current && (jsx(StyledSelectPicker, { "$isLight": isLight, cleanable: isCleanable, container: boxRef.current,
|
|
34994
|
+
// When we use a custom search, we use `controlledRsuiteData` to provide the matching options (data),
|
|
34995
|
+
// when we don't, we don't need to control that and just pass the non-internally-controlled `rsuiteData`
|
|
34996
|
+
data: controlledRsuiteData || rsuiteData, disabled: disabled, id: originalProps.name, onClean: handleClean, onSearch: handleSearch,
|
|
35025
34997
|
// `as any` because we customized `ItemDataType` type by adding `optionValue`,
|
|
35026
34998
|
// which generates an optional vs required type conflict
|
|
35027
|
-
onSelect: handleSelect, open: isOpen, renderMenuItem: renderMenuItem, searchable: !!customSearch || searchable,
|
|
34999
|
+
onSelect: handleSelect, open: isOpen, renderMenuItem: renderMenuItem, searchable: !!customSearch || searchable,
|
|
35000
|
+
// When we use a custom search, we use `controlledRsuiteData` to provide the matching options (data),
|
|
35001
|
+
// that's why we send this "always true" filter to disable Rsuite SelectPicker internal search filtering
|
|
35002
|
+
searchBy: (customSearch ? () => true : undefined), value: selectedRsuiteValue, ...originalProps }, key)) }), !isErrorMessageHidden && hasError && jsx(FieldError, { children: controlledError })] }));
|
|
35028
35003
|
}
|
|
35029
35004
|
const StyledSelectPicker = styled(SelectPicker) `
|
|
35030
35005
|
> .rs-picker-toggle {
|