@mtes-mct/monitor-ui 6.3.3 → 6.4.1

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 CHANGED
@@ -1,3 +1,23 @@
1
+ # [6.4.0](https://github.com/MTES-MCT/monitor-ui/compare/v6.3.3...v6.4.0) (2023-05-25)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **formiks:** delete setTouched in handleChange and delete touched condition for error ([17a9e24](https://github.com/MTES-MCT/monitor-ui/commit/17a9e249a74352f0696a9cc2146aa4e88422a542))
7
+
8
+
9
+ ### Features
10
+
11
+ * **fields:** add customSearch prop to Search ([53e993a](https://github.com/MTES-MCT/monitor-ui/commit/53e993ac1cd8c218a3bddbd5cef0d36778589166))
12
+
13
+ ## [6.3.3](https://github.com/MTES-MCT/monitor-ui/compare/v6.3.2...v6.3.3) (2023-05-25)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * **fields:** control options internally with customSearch in Select & MultiSelect ([251ad18](https://github.com/MTES-MCT/monitor-ui/commit/251ad188dbc388c6efcaa1e2bf0afdd0ba343a65))
19
+ * **fields:** reset controlled rsuite data on change with customSearch in MultiSelect ([b96b6d5](https://github.com/MTES-MCT/monitor-ui/commit/b96b6d5eb0e3e00170449ec5df0615ee7c6cea96))
20
+
1
21
  ## [6.3.2](https://github.com/MTES-MCT/monitor-ui/compare/v6.3.1...v6.3.2) (2023-05-25)
2
22
 
3
23
 
@@ -1,4 +1,5 @@
1
1
  import { type ElementType } from 'react';
2
+ import type { CustomSearch } from '../libs/CustomSearch';
2
3
  import type { Option, OptionValueType } from '../types';
3
4
  import type { AutoCompleteProps as RsuiteAutoCompleteProps } from 'rsuite';
4
5
  import type { Promisable } from 'type-fest';
@@ -6,6 +7,9 @@ export type SearchProps<OptionValue extends OptionValueType = string> = Omit<Rsu
6
7
  MenuItem?: ElementType | undefined;
7
8
  /** Used to pass something else than `window.document` as a base container to attach global events listeners. */
8
9
  baseContainer?: Document | HTMLDivElement | null | undefined;
10
+ customSearch?: CustomSearch<Option<OptionValue>> | undefined;
11
+ /** Minimum search query length required to trigger custom search filtering. */
12
+ customSearchMinQueryLength?: number | undefined;
9
13
  error?: string | undefined;
10
14
  isErrorMessageHidden?: boolean | undefined;
11
15
  isLabelHidden?: boolean | undefined;
@@ -19,4 +23,4 @@ export type SearchProps<OptionValue extends OptionValueType = string> = Omit<Rsu
19
23
  options?: Option<OptionValue>[];
20
24
  value?: OptionValue | undefined;
21
25
  };
22
- export declare function Search<OptionValue extends OptionValueType = string>({ baseContainer, className, error, isErrorMessageHidden, isLabelHidden, isLight, isSearchIconVisible, label, MenuItem, onChange, onQuery, options, optionValueKey, value, ...originalProps }: SearchProps<OptionValue>): JSX.Element;
26
+ export declare function Search<OptionValue extends OptionValueType = string>({ baseContainer, className, customSearch, customSearchMinQueryLength, error, isErrorMessageHidden, isLabelHidden, isLight, isSearchIconVisible, label, MenuItem, onChange, onQuery, options, optionValueKey, value, ...originalProps }: SearchProps<OptionValue>): JSX.Element;
package/index.js CHANGED
@@ -20739,9 +20739,11 @@ function normalizeString(text) {
20739
20739
  return cleanText.length > 0 ? cleanText : undefined;
20740
20740
  }
20741
20741
 
20742
- function Search({ baseContainer, className, error, isErrorMessageHidden = false, isLabelHidden, isLight = false, isSearchIconVisible = true, label, MenuItem, onChange, onQuery, options = [], optionValueKey, value, ...originalProps }) {
20742
+ function Search({ baseContainer, className, customSearch = undefined, customSearchMinQueryLength = 1, error, isErrorMessageHidden = false, isLabelHidden, isLight = false, isSearchIconVisible = true, label, MenuItem, onChange, onQuery, options = [], optionValueKey, value, ...originalProps }) {
20743
20743
  // eslint-disable-next-line no-null/no-null
20744
20744
  const boxRef = useRef(null);
20745
+ /** Instance of `CustomSearch` */
20746
+ const customSearchRef = useRef(customSearch);
20745
20747
  const queryRef = useRef(undefined);
20746
20748
  const data = useMemo(() => getRsuiteDataFromOptions(options, optionValueKey), [options, optionValueKey]);
20747
20749
  const [isOpen, setIsOpen] = useState(false);
@@ -20752,6 +20754,8 @@ function Search({ baseContainer, className, error, isErrorMessageHidden = false,
20752
20754
  const key = useKey([value, originalProps.disabled, originalProps.name]);
20753
20755
  const rsuiteValue = useMemo(() => getRsuiteValueFromOptionValue(value, optionValueKey), [value, optionValueKey]);
20754
20756
  const [inputValue, setInputValue] = useState(rsuiteValue);
20757
+ // Only used when `customSearch` prop is set
20758
+ const [controlledRsuiteData, setControlledRsuiteData] = useState(customSearch ? [] : undefined);
20755
20759
  const close = useCallback(() => {
20756
20760
  setIsOpen(false);
20757
20761
  }, []);
@@ -20763,6 +20767,12 @@ function Search({ baseContainer, className, error, isErrorMessageHidden = false,
20763
20767
  if (!(typeof nextQuery === 'string')) {
20764
20768
  return;
20765
20769
  }
20770
+ if (customSearch && customSearchRef.current) {
20771
+ const nextControlledRsuiteData = nextQuery.trim().length >= customSearchMinQueryLength
20772
+ ? getRsuiteDataFromOptions(customSearchRef.current.find(nextQuery), optionValueKey)
20773
+ : [];
20774
+ setControlledRsuiteData(nextControlledRsuiteData);
20775
+ }
20766
20776
  queryRef.current = normalizeString(nextQuery);
20767
20777
  if (event.type === 'change') {
20768
20778
  setInputValue(nextQuery);
@@ -20777,7 +20787,7 @@ function Search({ baseContainer, className, error, isErrorMessageHidden = false,
20777
20787
  if (onQuery) {
20778
20788
  onQuery(queryRef.current);
20779
20789
  }
20780
- }, [onChange, onQuery]);
20790
+ }, [customSearch, onChange, onQuery, customSearchMinQueryLength, optionValueKey]);
20781
20791
  const handleSelect = useCallback((_, item) => {
20782
20792
  if (onChange) {
20783
20793
  onChange(item.optionValue);
@@ -20789,7 +20799,13 @@ function Search({ baseContainer, className, error, isErrorMessageHidden = false,
20789
20799
  useEffect(() => {
20790
20800
  forceUpdate();
20791
20801
  }, [forceUpdate]);
20792
- return (jsxs(Field$2, { className: controlledClassName, children: [jsx(Label, { disabled: originalProps.disabled, hasError: hasError, htmlFor: originalProps.name, isHidden: isLabelHidden, children: label }), jsxs(Box$c, { ref: boxRef, isLight: isLight, children: [boxRef.current && (jsx(StyledAutoComplete, { "$isLight": isLight, container: boxRef.current, data: data, id: originalProps.name, onChange: handleChange, onSelect: handleSelect, open: isOpen, renderMenuItem: (itemLabel, item) => MenuItem ? jsx(MenuItem, { item: item.value }) : itemLabel, value: inputValue, ...originalProps }, key)), inputValue && (jsxs(Fragment, { children: [jsx(StyledCloseButton, { accent: Accent.TERTIARY, color: THEME.color.slateGray, Icon: Close, isSearchIconVisible: isSearchIconVisible, onClick: clean, size: Size.SMALL }), isSearchIconVisible && jsx(Separator, { children: "|" })] })), isSearchIconVisible && jsx(StyledIconSearch, { color: THEME.color.slateGray, size: 20 })] }), !isErrorMessageHidden && hasError && jsx(FieldError, { children: controlledError })] }));
20802
+ return (jsxs(Field$2, { className: controlledClassName, children: [jsx(Label, { disabled: originalProps.disabled, hasError: hasError, htmlFor: originalProps.name, isHidden: isLabelHidden, children: label }), jsxs(Box$c, { ref: boxRef, isLight: isLight, children: [boxRef.current && (jsx(StyledAutoComplete, { "$isLight": isLight, container: boxRef.current,
20803
+ // When we use a custom search, we use `controlledRsuiteData` to provide the matching options (data),
20804
+ // when we don't, we don't need to control that and just pass the non-internally-controlled `rsuiteData`
20805
+ data: controlledRsuiteData || data,
20806
+ // When we use a custom search, we use `controlledRsuiteData` to provide the matching options (data),
20807
+ // that's why we send this "always true" filter to disable Rsuite SelectPicker internal search filtering
20808
+ filterBy: (customSearch ? () => true : undefined), id: originalProps.name, onChange: handleChange, onSelect: handleSelect, open: isOpen, renderMenuItem: (itemLabel, item) => MenuItem ? jsx(MenuItem, { item: item.value }) : itemLabel, value: inputValue, ...originalProps }, key)), inputValue && (jsxs(Fragment, { children: [jsx(StyledCloseButton, { accent: Accent.TERTIARY, color: THEME.color.slateGray, Icon: Close, isSearchIconVisible: isSearchIconVisible, onClick: clean, size: Size.SMALL }), isSearchIconVisible && jsx(Separator, { children: "|" })] })), isSearchIconVisible && jsx(StyledIconSearch, { color: THEME.color.slateGray, size: 20 })] }), !isErrorMessageHidden && hasError && jsx(FieldError, { children: controlledError })] }));
20793
20809
  }
20794
20810
  const StyledCloseButton = styled(IconButton) `
20795
20811
  cursor: pointer;
@@ -20812,7 +20828,7 @@ const StyledAutoComplete = styled(AutoComplete) `
20812
20828
  font-size: 13px;
20813
20829
  flex-grow: 1;
20814
20830
 
20815
- > input {
20831
+ .rs-input {
20816
20832
  background-color: ${p => (p.$isLight ? p.theme.color.white : p.theme.color.gainsboro)};
20817
20833
  border-width: 0 0 1px;
20818
20834
  border-color: ${p => (p.$isLight ? p.theme.color.white : p.theme.color.gainsboro)};
@@ -20824,7 +20840,11 @@ const StyledAutoComplete = styled(AutoComplete) `
20824
20840
 
20825
20841
  :focus {
20826
20842
  outline: unset;
20827
- border-color: ${p => p.theme.color.blueGray['100']};
20843
+ border-color: transparent;
20844
+ }
20845
+ :hover {
20846
+ outline: unset;
20847
+ border-color: transparent;
20828
20848
  }
20829
20849
  }
20830
20850
  `;
@@ -35165,20 +35185,17 @@ const InputBox = styled.div `
35165
35185
 
35166
35186
  function FormikSearch({ name, ...originalProps }) {
35167
35187
  const [field, meta, helpers] = useField(name);
35168
- const error = meta.touched ? meta.error : undefined;
35169
35188
  const handleChange = useMemo(() => value => {
35170
- helpers.setTouched(true);
35171
35189
  helpers.setValue(value);
35172
35190
  },
35173
35191
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35174
35192
  // eslint-disable-next-line react-hooks/exhaustive-deps
35175
35193
  []);
35176
- return jsx(Search, { error: error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35194
+ return jsx(Search, { error: meta.error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35177
35195
  }
35178
35196
 
35179
35197
  function FormikCheckbox({ name, ...originalProps }) {
35180
35198
  const [field, meta, helpers] = useField(name);
35181
- const error = meta.touched ? meta.error : undefined;
35182
35199
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35183
35200
  // eslint-disable-next-line react-hooks/exhaustive-deps
35184
35201
  const handleChange = useMemo(() => helpers.setValue, []);
@@ -35186,56 +35203,49 @@ function FormikCheckbox({ name, ...originalProps }) {
35186
35203
  // A checkbox must initialize its Formik value on mount:
35187
35204
  // it wouldn't make sense to keep it as `undefined` since `undefined` means `false` in the case of a checkbox
35188
35205
  useEffect(() => {
35189
- helpers.setTouched(true);
35190
35206
  helpers.setValue(isChecked);
35191
35207
  },
35192
35208
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35193
35209
  // eslint-disable-next-line react-hooks/exhaustive-deps
35194
35210
  []);
35195
- return jsx(Checkbox, { checked: isChecked, error: error, name: name, onChange: handleChange, ...originalProps });
35211
+ return jsx(Checkbox, { checked: isChecked, error: meta.error, name: name, onChange: handleChange, ...originalProps });
35196
35212
  }
35197
35213
 
35198
35214
  function FormikCoordinatesInput({ name, ...originalProps }) {
35199
35215
  const [field, meta, helpers] = useField(name);
35200
35216
  // eslint-disable-next-line react-hooks/exhaustive-deps
35201
35217
  const defaultValue = useMemo(() => field.value, []);
35202
- const error = meta.touched ? meta.error : undefined;
35203
35218
  const handleChange = useMemo(() => value => {
35204
- helpers.setTouched(true);
35205
35219
  helpers.setValue(value);
35206
35220
  },
35207
35221
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35208
35222
  // eslint-disable-next-line react-hooks/exhaustive-deps
35209
35223
  []);
35210
- return jsx(CoordinatesInput, { defaultValue: defaultValue, error: error, onChange: handleChange, ...originalProps });
35224
+ return jsx(CoordinatesInput, { defaultValue: defaultValue, error: meta.error, onChange: handleChange, ...originalProps });
35211
35225
  }
35212
35226
 
35213
35227
  const UntypedDatePicker = DatePicker;
35214
35228
  function FormikDatePicker({ name, ...originalProps }) {
35215
35229
  const [field, meta, helpers] = useField(name);
35216
- const error = meta.touched ? meta.error : undefined;
35217
35230
  const handleChange = useMemo(() => value => {
35218
- helpers.setTouched(true);
35219
35231
  helpers.setValue(value);
35220
35232
  },
35221
35233
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35222
35234
  // eslint-disable-next-line react-hooks/exhaustive-deps
35223
35235
  []);
35224
- return jsx(UntypedDatePicker, { defaultValue: field.value, error: error, onChange: handleChange, ...originalProps });
35236
+ return jsx(UntypedDatePicker, { defaultValue: field.value, error: meta.error, onChange: handleChange, ...originalProps });
35225
35237
  }
35226
35238
 
35227
35239
  const UntypedDateRangePicker = DateRangePicker;
35228
35240
  function FormikDateRangePicker({ name, ...originalProps }) {
35229
35241
  const [field, meta, helpers] = useField(name);
35230
- const error = meta.touched ? meta.error : undefined;
35231
35242
  const handleChange = useMemo(() => value => {
35232
- helpers.setTouched(true);
35233
35243
  helpers.setValue(value);
35234
35244
  },
35235
35245
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35236
35246
  // eslint-disable-next-line react-hooks/exhaustive-deps
35237
35247
  []);
35238
- return jsx(UntypedDateRangePicker, { defaultValue: field.value, error: error, onChange: handleChange, ...originalProps });
35248
+ return (jsx(UntypedDateRangePicker, { defaultValue: field.value, error: meta.error, onChange: handleChange, ...originalProps }));
35239
35249
  }
35240
35250
 
35241
35251
  function FormikEffect({ onChange }) {
@@ -35248,93 +35258,79 @@ function FormikEffect({ onChange }) {
35248
35258
 
35249
35259
  function FormikMultiCheckbox({ name, ...originalProps }) {
35250
35260
  const [field, meta, helpers] = useField(name);
35251
- const error = meta.touched ? meta.error : undefined;
35252
35261
  const handleChange = useMemo(() => value => {
35253
- helpers.setTouched(true);
35254
35262
  helpers.setValue(value);
35255
35263
  },
35256
35264
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35257
35265
  // eslint-disable-next-line react-hooks/exhaustive-deps
35258
35266
  []);
35259
- return jsx(MultiCheckbox, { error: error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35267
+ return jsx(MultiCheckbox, { error: meta.error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35260
35268
  }
35261
35269
 
35262
35270
  function FormikMultiSelect({ name, ...originalProps }) {
35263
35271
  const [field, meta, helpers] = useField(name);
35264
- const error = meta.touched ? meta.error : undefined;
35265
35272
  const handleChange = useMemo(() => value => {
35266
- helpers.setTouched(true);
35267
35273
  helpers.setValue(value);
35268
35274
  },
35269
35275
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35270
35276
  // eslint-disable-next-line react-hooks/exhaustive-deps
35271
35277
  []);
35272
- return jsx(MultiSelect, { error: error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35278
+ return jsx(MultiSelect, { error: meta.error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35273
35279
  }
35274
35280
 
35275
35281
  function FormikMultiRadio({ name, ...originalProps }) {
35276
35282
  const [field, meta, helpers] = useField(name);
35277
- const error = meta.touched ? meta.error : undefined;
35278
35283
  const handleChange = useMemo(() => value => {
35279
- helpers.setTouched(true);
35280
35284
  helpers.setValue(value);
35281
35285
  },
35282
35286
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35283
35287
  // eslint-disable-next-line react-hooks/exhaustive-deps
35284
35288
  []);
35285
- return jsx(MultiRadio, { error: error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35289
+ return jsx(MultiRadio, { error: meta.error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35286
35290
  }
35287
35291
 
35288
35292
  function FormikNumberInput({ name, ...originalProps }) {
35289
35293
  const [field, meta, helpers] = useField(name);
35290
- const error = meta.touched ? meta.error : undefined;
35291
35294
  const handleChange = useMemo(() => value => {
35292
- helpers.setTouched(true);
35293
35295
  helpers.setValue(value);
35294
35296
  },
35295
35297
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35296
35298
  // eslint-disable-next-line react-hooks/exhaustive-deps
35297
35299
  []);
35298
- return jsx(NumberInput, { error: error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35300
+ return jsx(NumberInput, { error: meta.error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35299
35301
  }
35300
35302
 
35301
35303
  function FormikSelect({ name, ...originalProps }) {
35302
35304
  const [field, meta, helpers] = useField(name);
35303
- const error = meta.touched ? meta.error : undefined;
35304
35305
  const handleChange = useMemo(() => value => {
35305
- helpers.setTouched(true);
35306
35306
  helpers.setValue(value);
35307
35307
  },
35308
35308
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35309
35309
  // eslint-disable-next-line react-hooks/exhaustive-deps
35310
35310
  []);
35311
- return jsx(Select, { error: error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35311
+ return jsx(Select, { error: meta.error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35312
35312
  }
35313
35313
 
35314
35314
  function FormikTextarea({ name, ...originalProps }) {
35315
35315
  const [field, meta, helpers] = useField(name);
35316
- const error = meta.touched ? meta.error : undefined;
35317
35316
  const handleChange = useMemo(() => value => {
35318
- helpers.setTouched(true);
35319
35317
  helpers.setValue(value);
35320
35318
  },
35321
35319
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35322
35320
  // eslint-disable-next-line react-hooks/exhaustive-deps
35323
35321
  []);
35324
- return jsx(Textarea, { error: error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35322
+ return jsx(Textarea, { error: meta.error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35325
35323
  }
35326
35324
 
35327
35325
  function FormikTextInput({ name, ...originalProps }) {
35328
35326
  const [field, meta, helpers] = useField(name);
35329
- const error = meta.touched ? meta.error : undefined;
35330
35327
  const handleChange = useMemo(() => value => {
35331
- helpers.setTouched(true);
35332
35328
  helpers.setValue(value);
35333
35329
  },
35334
35330
  // We don't want to trigger infinite re-rendering since `helpers.setValue` changes after each rendering
35335
35331
  // eslint-disable-next-line react-hooks/exhaustive-deps
35336
35332
  []);
35337
- return jsx(TextInput, { error: error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35333
+ return jsx(TextInput, { error: meta.error, name: name, onChange: handleChange, value: field.value, ...originalProps });
35338
35334
  }
35339
35335
 
35340
35336
  function useFieldControl(value, onChange, defaultValueWhenUndefined) {