@snack-uikit/fields 0.26.0 → 0.27.0

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
@@ -3,6 +3,24 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 0.27.0 (2024-09-23)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **DPS-12873:** selectedOptionFormatter with predefined value ([7a8d335](https://github.com/cloud-ru-tech/snack-uikit/commit/7a8d33574a6205a56aa742aaa052d07d30f99eb0))
12
+ * **PDS-480:** remove direct usage of browser api elements ([1231ff7](https://github.com/cloud-ru-tech/snack-uikit/commit/1231ff7ab7a1b210b579a7b694633ef23bffcf44))
13
+ * **PDS-480:** replace useLayoutEffect -> useIsomorphicLayoutEffect for ssr ([21aa9ad](https://github.com/cloud-ru-tech/snack-uikit/commit/21aa9ad9f113e465766339d396924357ccb1d432))
14
+
15
+
16
+ ### Features
17
+
18
+ * **PDS-000:** add resetSearchOnOptionSelection property ([1fe3640](https://github.com/cloud-ru-tech/snack-uikit/commit/1fe3640b23a3da35c6b949c2bdc0796073b51425))
19
+
20
+
21
+
22
+
23
+
6
24
  # 0.26.0 (2024-09-17)
7
25
 
8
26
 
package/README.md CHANGED
@@ -368,31 +368,32 @@ FieldStepper в основном предназначен для работы с
368
368
  | value | `ItemId \| ItemId[]` | - | Controlled состояние |
369
369
  | onChange | `OnChangeHandler<any>` | - | Controlled обработчик измения состояния |
370
370
  | defaultValue | `ItemId \| ItemId[]` | - | Начальное состояние |
371
- | pinTop | `OptionProps[]` | - | |
372
- | pinBottom | `OptionProps[]` | - | |
373
- | searchable | `boolean` | - | |
371
+ | open | `boolean` | - | |
372
+ | onOpenChange | `(open: boolean) => void` | - | |
374
373
  | showCopyButton | `boolean` | - | Отображение кнопки Копировать для поля (актуально только для `readonly = true`) |
375
374
  | showClearButton | `boolean` | true | Отображение кнопки очистки поля |
376
375
  | prefixIcon | `ReactElement<any, string \| JSXElementConstructor<any>>` | - | Иконка-префикс для поля |
377
- | footer | `ReactNode` | - | |
378
376
  | widthStrategy | enum PopoverWidthStrategy: `"auto"`, `"gte"`, `"eq"` | - | |
377
+ | pinTop | `OptionProps[]` | - | |
378
+ | pinBottom | `OptionProps[]` | - | |
379
+ | footer | `ReactNode` | - | |
379
380
  | search | `SearchState` | - | |
380
- | autocomplete | `boolean` | - | |
381
- | addOptionByEnter | `boolean` | - | |
382
- | open | `boolean` | - | |
383
- | enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
384
- | onOpenChange | `(open: boolean) => void` | - | |
385
- | selectedOptionFormatter | `SelectedOptionFormatter` | - | |
386
381
  | untouchableScrollbars | `boolean` | - | Отключает возможность взаимодействовать со скролбарами мышью. |
387
382
  | dataFiltered | `boolean` | - | |
388
383
  | dataError | `boolean` | - | |
389
384
  | noDataState | `EmptyStateProps` | - | Экран при отстутствии данных |
390
385
  | noResultsState | `EmptyStateProps` | - | Экран при отстутствии результатов поиска или фильтров |
391
386
  | errorDataState | `EmptyStateProps` | - | Экран при ошибке запроса |
387
+ | searchable | `boolean` | - | |
388
+ | autocomplete | `boolean` | - | |
389
+ | addOptionByEnter | `boolean` | - | |
390
+ | enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
391
+ | selectedOptionFormatter | `SelectedOptionFormatter` | - | |
392
392
  | selection | "single" \| "multiple" | - | |
393
393
  | ref | `Ref<HTMLInputElement>` | - | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom |
394
394
  | key | `Key` | - | |
395
395
  | removeByBackspace | `boolean` | - | |
396
+ | resetSearchOnOptionSelection | `boolean` | - | Поведение строки поиска при выборе опции из списка |
396
397
  ## FieldStepper
397
398
  ### Props
398
399
  | name | type | default value | description |
@@ -1,4 +1,5 @@
1
1
  import { useCallback, useMemo, useRef } from 'react';
2
+ import { isBrowser } from '@snack-uikit/utils';
2
3
  import { DEFAULT_LOCALE, MASK, SlotKey, SLOTS, SLOTS_PLACEHOLDER } from '../constants';
3
4
  import { getNextSlotKey, getPrevSlotKey, getSlotKey } from '../utils';
4
5
  import { useDateFieldHelpers } from './useDateFieldHelpers';
@@ -12,7 +13,7 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
12
13
  if (!inputRef.current || readonly) {
13
14
  return;
14
15
  }
15
- if (document.activeElement !== inputRef.current) {
16
+ if (isBrowser() && document.activeElement !== inputRef.current) {
16
17
  focusSlotRef.current = focusSlot || SlotKey.Day;
17
18
  inputRef.current.focus();
18
19
  return;
@@ -22,6 +22,7 @@ export declare const FieldSelectMultiple: import("react").ForwardRefExoticCompon
22
22
  addOptionByEnter?: boolean;
23
23
  open?: boolean;
24
24
  enableFuzzySearch?: boolean;
25
+ resetSearchOnOptionSelection?: boolean;
25
26
  onOpenChange?(open: boolean): void;
26
27
  selectedOptionFormatter?: SelectedOptionFormatter;
27
28
  } & Pick<import("@snack-uikit/list").DroplistProps, "untouchableScrollbars" | "dataError" | "dataFiltered" | "noDataState" | "noResultsState" | "errorDataState">, "showCopyButton"> & import("react").RefAttributes<HTMLInputElement>>;
@@ -12,11 +12,11 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
13
13
  import cn from 'classnames';
14
14
  import mergeRefs from 'merge-refs';
15
- import { forwardRef, useLayoutEffect, useRef, useState } from 'react';
15
+ import { forwardRef, useRef, useState } from 'react';
16
16
  import { InputPrivate } from '@snack-uikit/input-private';
17
17
  import { Droplist } from '@snack-uikit/list';
18
18
  import { Tag } from '@snack-uikit/tag';
19
- import { extractSupportProps } from '@snack-uikit/utils';
19
+ import { extractSupportProps, isBrowser, useLayoutEffect } from '@snack-uikit/utils';
20
20
  import { FieldContainerPrivate } from '../../helperComponents';
21
21
  import { useValueControl } from '../../hooks';
22
22
  import { getValidationState } from '../../utils/getValidationState';
@@ -32,7 +32,7 @@ const defaultSelectedOptionFormatter = item =>
32
32
  (item === null || item === void 0 ? void 0 : item.content.option) || '';
33
33
  export const FieldSelectMultiple = forwardRef((props, ref) => {
34
34
  var _a;
35
- const { id, name, placeholder, size = 's', options, value: valueProp, defaultValue, onChange: onChangeProp, disabled = false, readonly = false, searchable = true, showClearButton = true, onKeyDown: onInputKeyDownProp, validationState = 'default', search, autocomplete = false, prefixIcon, removeByBackspace = false, addOptionByEnter = false, untouchableScrollbars = false, open: openProp, enableFuzzySearch = true, onOpenChange, selectedOptionFormatter = defaultSelectedOptionFormatter } = props, rest = __rest(props, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showClearButton", "onKeyDown", "validationState", "search", "autocomplete", "prefixIcon", "removeByBackspace", "addOptionByEnter", "untouchableScrollbars", "open", "enableFuzzySearch", "onOpenChange", "selectedOptionFormatter"]);
35
+ const { id, name, placeholder, size = 's', options, value: valueProp, defaultValue, onChange: onChangeProp, disabled = false, readonly = false, searchable = true, showClearButton = true, onKeyDown: onInputKeyDownProp, validationState = 'default', search, autocomplete = false, prefixIcon, removeByBackspace = false, addOptionByEnter = false, untouchableScrollbars = false, open: openProp, enableFuzzySearch = true, resetSearchOnOptionSelection = true, onOpenChange, selectedOptionFormatter = defaultSelectedOptionFormatter } = props, rest = __rest(props, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showClearButton", "onKeyDown", "validationState", "search", "autocomplete", "prefixIcon", "removeByBackspace", "addOptionByEnter", "untouchableScrollbars", "open", "enableFuzzySearch", "resetSearchOnOptionSelection", "onOpenChange", "selectedOptionFormatter"]);
36
36
  const localRef = useRef(null);
37
37
  const inputPlugRef = useRef(null);
38
38
  const contentRef = useRef(null);
@@ -43,7 +43,8 @@ export const FieldSelectMultiple = forwardRef((props, ref) => {
43
43
  onChange: onChangeProp,
44
44
  });
45
45
  const [{ selectedItems, items = [] }, setItems] = useState(() => updateMultipleItems({ options, value, currentItems: [], selectedItems: undefined }));
46
- const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: '', selectedOptionFormatter }));
46
+ const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: '', selectedOptionFormatter,
47
+ resetSearchOnOptionSelection }));
47
48
  useLayoutEffect(() => {
48
49
  setItems(({ selectedItems }) => updateMultipleItems({ options, value, selectedItems }));
49
50
  }, [options, value]);
@@ -92,7 +93,7 @@ export const FieldSelectMultiple = forwardRef((props, ref) => {
92
93
  commonHandleOnKeyDown(onKeyDown)(e);
93
94
  };
94
95
  const handleOpenChange = (open) => {
95
- if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
96
+ if (isBrowser() && !readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
96
97
  setOpen(open);
97
98
  if (!open) {
98
99
  if (inputPlugRef.current) {
@@ -2,7 +2,7 @@ import { SelectedOptionFormatter } from './types';
2
2
  export declare const FieldSelectSingle: import("react").ForwardRefExoticComponent<import("./types").InputProps & import("./types").WrapperProps & {
3
3
  options: import("./types").OptionProps[];
4
4
  loading?: boolean;
5
- } & Omit<import("@snack-uikit/list").SelectionSingleState, "mode"> & {
5
+ } & Omit<import("@snack-uikit/list").SelectionSingleState, "mode"> & Omit<{
6
6
  'data-test-id'?: string;
7
7
  } & import("react").AriaAttributes & {
8
8
  options: import("./types").OptionProps[];
@@ -20,6 +20,7 @@ export declare const FieldSelectSingle: import("react").ForwardRefExoticComponen
20
20
  addOptionByEnter?: boolean;
21
21
  open?: boolean;
22
22
  enableFuzzySearch?: boolean;
23
+ resetSearchOnOptionSelection?: boolean;
23
24
  onOpenChange?(open: boolean): void;
24
25
  selectedOptionFormatter?: SelectedOptionFormatter;
25
- } & Pick<import("@snack-uikit/list").DroplistProps, "untouchableScrollbars" | "dataError" | "dataFiltered" | "noDataState" | "noResultsState" | "errorDataState"> & import("react").RefAttributes<HTMLInputElement>>;
26
+ } & Pick<import("@snack-uikit/list").DroplistProps, "untouchableScrollbars" | "dataError" | "dataFiltered" | "noDataState" | "noResultsState" | "errorDataState">, "resetSearchOnOptionSelection"> & import("react").RefAttributes<HTMLInputElement>>;
@@ -12,10 +12,10 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import cn from 'classnames';
14
14
  import mergeRefs from 'merge-refs';
15
- import { forwardRef, useCallback, useEffect, useLayoutEffect, useRef, useState, } from 'react';
15
+ import { forwardRef, useCallback, useEffect, useRef, useState, } from 'react';
16
16
  import { InputPrivate } from '@snack-uikit/input-private';
17
17
  import { Droplist } from '@snack-uikit/list';
18
- import { extractSupportProps } from '@snack-uikit/utils';
18
+ import { extractSupportProps, isBrowser, useLayoutEffect } from '@snack-uikit/utils';
19
19
  import { FieldContainerPrivate } from '../../helperComponents';
20
20
  import { useValueControl } from '../../hooks';
21
21
  import { getValidationState } from '../../utils/getValidationState';
@@ -29,7 +29,6 @@ const defaultSelectedOptionFormatter = item =>
29
29
  // @ts-expect-error
30
30
  (item === null || item === void 0 ? void 0 : item.content.option) || '';
31
31
  export const FieldSelectSingle = forwardRef((props, ref) => {
32
- var _a;
33
32
  const { id, name, placeholder, size = 's', options, value: valueProp, defaultValue, onChange: onChangeProp, disabled = false, readonly = false, searchable = true, showCopyButton = true, showClearButton = true, onKeyDown: onInputKeyDownProp, required = false, validationState = 'default', search, autocomplete = false, prefixIcon, addOptionByEnter = false, untouchableScrollbars = false, open: openProp, onOpenChange, selectedOptionFormatter = defaultSelectedOptionFormatter, enableFuzzySearch = true } = props, rest = __rest(props, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showCopyButton", "showClearButton", "onKeyDown", "required", "validationState", "search", "autocomplete", "prefixIcon", "addOptionByEnter", "untouchableScrollbars", "open", "onOpenChange", "selectedOptionFormatter", "enableFuzzySearch"]);
34
33
  const localRef = useRef(null);
35
34
  const [open = false, setOpen] = useValueControl({ value: openProp, onChange: onOpenChange });
@@ -39,10 +38,7 @@ export const FieldSelectSingle = forwardRef((props, ref) => {
39
38
  onChange: onChangeProp,
40
39
  });
41
40
  const [{ selectedItem, items = [] }, setItems] = useState(() => updateItems({ options, value, currentItems: [], selectedItem: undefined }));
42
- const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput(Object.assign(Object.assign({}, search), {
43
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
44
- // @ts-expect-error
45
- defaultValue: (_a = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.content.option) !== null && _a !== void 0 ? _a : '', selectedOptionFormatter }));
41
+ const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput(Object.assign(Object.assign({}, search), { defaultValue: selectedOptionFormatter(selectedItem), selectedOptionFormatter }));
46
42
  const prevSelectedItem = useRef(selectedItem);
47
43
  useLayoutEffect(() => {
48
44
  setItems(({ selectedItem }) => updateItems({ options, value, selectedItem }));
@@ -111,7 +107,7 @@ export const FieldSelectSingle = forwardRef((props, ref) => {
111
107
  commonHandleOnKeyDown(onKeyDown)(e);
112
108
  };
113
109
  const handleOpenChange = (open) => {
114
- if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
110
+ if (isBrowser() && !readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
115
111
  setOpen(open);
116
112
  if (!open) {
117
113
  updateInputValue(selectedItem);
@@ -22,8 +22,9 @@ export declare function useButtons({ readonly, showClearButton, showCopyButton,
22
22
  inputKeyDownNavigationHandler: KeyboardEventHandler<HTMLInputElement>;
23
23
  buttonsRefs: (Element | null)[];
24
24
  };
25
- export declare function useSearchInput({ value, onChange, defaultValue, selectedOptionFormatter, }: SearchState & {
25
+ export declare function useSearchInput({ value, onChange, defaultValue, selectedOptionFormatter, resetSearchOnOptionSelection, }: SearchState & {
26
26
  selectedOptionFormatter: SelectedOptionFormatter;
27
+ resetSearchOnOptionSelection?: boolean;
27
28
  }): {
28
29
  inputValue: string;
29
30
  setInputValue: (value: any, ...args: any[]) => ReturnType<Handler> | void;
@@ -51,16 +51,16 @@ export function useButtons({ readonly, showClearButton, showCopyButton, size, on
51
51
  });
52
52
  return { buttons, inputKeyDownNavigationHandler, buttonsRefs };
53
53
  }
54
- export function useSearchInput({ value, onChange, defaultValue, selectedOptionFormatter, }) {
54
+ export function useSearchInput({ value, onChange, defaultValue, selectedOptionFormatter, resetSearchOnOptionSelection = true, }) {
55
55
  const [inputValue = '', setInputValue] = useValueControl({ value, onChange, defaultValue });
56
56
  const prevInputValue = useRef(inputValue);
57
57
  const updateInputValue = useCallback((selectedItem) => {
58
58
  const newInputValue = selectedOptionFormatter(selectedItem);
59
- if (inputValue !== newInputValue || prevInputValue.current !== newInputValue) {
59
+ if (resetSearchOnOptionSelection && (inputValue !== newInputValue || prevInputValue.current !== newInputValue)) {
60
60
  setInputValue(newInputValue);
61
61
  prevInputValue.current = newInputValue;
62
62
  }
63
- }, [inputValue, selectedOptionFormatter, setInputValue]);
63
+ }, [inputValue, resetSearchOnOptionSelection, selectedOptionFormatter, setInputValue]);
64
64
  return { inputValue, setInputValue, prevInputValue, onInputValueChange: setInputValue, updateInputValue };
65
65
  }
66
66
  export function useHandleDeleteItem(setValue) {
@@ -62,10 +62,12 @@ type FiledSelectCommonProps = WithSupportProps<{
62
62
  open?: boolean;
63
63
  /** Включить нечеткий поиск */
64
64
  enableFuzzySearch?: boolean;
65
+ /** Поведение строки поиска при выборе опции из списка */
66
+ resetSearchOnOptionSelection?: boolean;
65
67
  onOpenChange?(open: boolean): void;
66
68
  selectedOptionFormatter?: SelectedOptionFormatter;
67
69
  }> & Pick<DroplistProps, 'dataError' | 'noDataState' | 'noResultsState' | 'errorDataState' | 'dataFiltered' | 'untouchableScrollbars'>;
68
- export type FieldSelectSingleProps = FieldSelectPrivateProps & Omit<SelectionSingleState, 'mode'> & WrapperProps & FiledSelectCommonProps;
70
+ export type FieldSelectSingleProps = FieldSelectPrivateProps & Omit<SelectionSingleState, 'mode'> & WrapperProps & Omit<FiledSelectCommonProps, 'resetSearchOnOptionSelection'>;
69
71
  export type FieldSelectMultipleProps = FieldSelectPrivateProps & {
70
72
  removeByBackspace?: boolean;
71
73
  } & Omit<SelectionMultipleState, 'mode'> & Omit<FiledSelectCommonProps, 'showCopyButton'>;
@@ -11,9 +11,9 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import cn from 'classnames';
14
- import { forwardRef, useLayoutEffect, useState, } from 'react';
14
+ import { forwardRef, useState, } from 'react';
15
15
  import TextareaAutosize from 'react-textarea-autosize';
16
- import { extractSupportProps } from '@snack-uikit/utils';
16
+ import { extractSupportProps, useLayoutEffect } from '@snack-uikit/utils';
17
17
  import styles from './styles.module.css';
18
18
  export const TextArea = forwardRef((_a, ref) => {
19
19
  var { name, value = '', onChange, placeholder, id, className, disabled = false, readonly = false, autoComplete = false, maxLength, onFocus, onBlur, onKeyDown, tabIndex, minRows = 3 } = _a, rest = __rest(_a, ["name", "value", "onChange", "placeholder", "id", "className", "disabled", "readonly", "autoComplete", "maxLength", "onFocus", "onBlur", "onKeyDown", "tabIndex", "minRows"]);
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Fields",
7
- "version": "0.26.0",
7
+ "version": "0.27.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -32,19 +32,19 @@
32
32
  "license": "Apache-2.0",
33
33
  "scripts": {},
34
34
  "dependencies": {
35
- "@snack-uikit/button": "0.17.4",
36
- "@snack-uikit/calendar": "0.7.10",
37
- "@snack-uikit/dropdown": "0.2.5",
38
- "@snack-uikit/icons": "0.22.0",
39
- "@snack-uikit/input-private": "3.2.0",
40
- "@snack-uikit/list": "0.16.1",
41
- "@snack-uikit/scroll": "0.6.0",
42
- "@snack-uikit/skeleton": "0.3.4",
43
- "@snack-uikit/slider": "0.1.16",
44
- "@snack-uikit/tag": "0.9.8",
45
- "@snack-uikit/tooltip": "0.13.8",
46
- "@snack-uikit/truncate-string": "0.4.21",
47
- "@snack-uikit/utils": "3.3.0",
35
+ "@snack-uikit/button": "0.17.5",
36
+ "@snack-uikit/calendar": "0.7.11",
37
+ "@snack-uikit/dropdown": "0.2.6",
38
+ "@snack-uikit/icons": "0.22.1",
39
+ "@snack-uikit/input-private": "3.2.1",
40
+ "@snack-uikit/list": "0.16.2",
41
+ "@snack-uikit/scroll": "0.6.1",
42
+ "@snack-uikit/skeleton": "0.3.5",
43
+ "@snack-uikit/slider": "0.1.17",
44
+ "@snack-uikit/tag": "0.9.9",
45
+ "@snack-uikit/tooltip": "0.13.9",
46
+ "@snack-uikit/truncate-string": "0.4.22",
47
+ "@snack-uikit/utils": "3.4.0",
48
48
  "classnames": "2.3.2",
49
49
  "copy-to-clipboard": "3.3.3",
50
50
  "fuzzy-search": "3.2.1",
@@ -59,5 +59,5 @@
59
59
  "peerDependencies": {
60
60
  "@snack-uikit/locale": "*"
61
61
  },
62
- "gitHead": "b5dbc02c777773140b597e9c3268a9424f8608d8"
62
+ "gitHead": "f9212fe04b0dbba9bedea1bb3a034ab612287841"
63
63
  }
@@ -1,5 +1,7 @@
1
1
  import { ChangeEvent, FocusEventHandler, KeyboardEvent, RefObject, useCallback, useMemo, useRef } from 'react';
2
2
 
3
+ import { isBrowser } from '@snack-uikit/utils';
4
+
3
5
  import { DEFAULT_LOCALE, MASK, SlotKey, SLOTS, SLOTS_PLACEHOLDER } from '../constants';
4
6
  import { getNextSlotKey, getPrevSlotKey, getSlotKey } from '../utils';
5
7
  import { useDateFieldHelpers } from './useDateFieldHelpers';
@@ -32,7 +34,7 @@ export function useDateField({ inputRef, onChange, readonly, locale = DEFAULT_LO
32
34
  return;
33
35
  }
34
36
 
35
- if (document.activeElement !== inputRef.current) {
37
+ if (isBrowser() && document.activeElement !== inputRef.current) {
36
38
  focusSlotRef.current = focusSlot || SlotKey.Day;
37
39
  inputRef.current.focus();
38
40
  return;
@@ -1,11 +1,11 @@
1
1
  import cn from 'classnames';
2
2
  import mergeRefs from 'merge-refs';
3
- import { FocusEvent, forwardRef, KeyboardEvent, KeyboardEventHandler, useLayoutEffect, useRef, useState } from 'react';
3
+ import { FocusEvent, forwardRef, KeyboardEvent, KeyboardEventHandler, useRef, useState } from 'react';
4
4
 
5
5
  import { InputPrivate } from '@snack-uikit/input-private';
6
6
  import { BaseItemProps, Droplist, ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
7
7
  import { Tag } from '@snack-uikit/tag';
8
- import { extractSupportProps } from '@snack-uikit/utils';
8
+ import { extractSupportProps, isBrowser, useLayoutEffect } from '@snack-uikit/utils';
9
9
 
10
10
  import { FieldContainerPrivate } from '../../helperComponents';
11
11
  import { useValueControl } from '../../hooks';
@@ -48,6 +48,7 @@ export const FieldSelectMultiple = forwardRef<HTMLInputElement, FieldSelectMulti
48
48
  untouchableScrollbars = false,
49
49
  open: openProp,
50
50
  enableFuzzySearch = true,
51
+ resetSearchOnOptionSelection = true,
51
52
  onOpenChange,
52
53
  selectedOptionFormatter = defaultSelectedOptionFormatter,
53
54
  ...rest
@@ -73,6 +74,7 @@ export const FieldSelectMultiple = forwardRef<HTMLInputElement, FieldSelectMulti
73
74
  ...search,
74
75
  defaultValue: '',
75
76
  selectedOptionFormatter,
77
+ resetSearchOnOptionSelection,
76
78
  });
77
79
 
78
80
  useLayoutEffect(() => {
@@ -133,7 +135,7 @@ export const FieldSelectMultiple = forwardRef<HTMLInputElement, FieldSelectMulti
133
135
  };
134
136
 
135
137
  const handleOpenChange = (open: boolean) => {
136
- if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
138
+ if (isBrowser() && !readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
137
139
  setOpen(open);
138
140
 
139
141
  if (!open) {
@@ -7,14 +7,13 @@ import {
7
7
  KeyboardEventHandler,
8
8
  useCallback,
9
9
  useEffect,
10
- useLayoutEffect,
11
10
  useRef,
12
11
  useState,
13
12
  } from 'react';
14
13
 
15
14
  import { InputPrivate } from '@snack-uikit/input-private';
16
15
  import { Droplist, ItemProps, SelectionSingleValueType } from '@snack-uikit/list';
17
- import { extractSupportProps } from '@snack-uikit/utils';
16
+ import { extractSupportProps, isBrowser, useLayoutEffect } from '@snack-uikit/utils';
18
17
 
19
18
  import { FieldContainerPrivate } from '../../helperComponents';
20
19
  import { useValueControl } from '../../hooks';
@@ -75,9 +74,7 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
75
74
 
76
75
  const { inputValue, setInputValue, prevInputValue, updateInputValue } = useSearchInput({
77
76
  ...search,
78
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
79
- // @ts-expect-error
80
- defaultValue: selectedItem?.content.option ?? '',
77
+ defaultValue: selectedOptionFormatter(selectedItem),
81
78
  selectedOptionFormatter,
82
79
  });
83
80
 
@@ -168,7 +165,7 @@ export const FieldSelectSingle = forwardRef<HTMLInputElement, FieldSelectSingleP
168
165
  };
169
166
 
170
167
  const handleOpenChange = (open: boolean) => {
171
- if (!readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
168
+ if (isBrowser() && !readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
172
169
  setOpen(open);
173
170
 
174
171
  if (!open) {
@@ -106,7 +106,8 @@ export function useSearchInput({
106
106
  onChange,
107
107
  defaultValue,
108
108
  selectedOptionFormatter,
109
- }: SearchState & { selectedOptionFormatter: SelectedOptionFormatter }) {
109
+ resetSearchOnOptionSelection = true,
110
+ }: SearchState & { selectedOptionFormatter: SelectedOptionFormatter; resetSearchOnOptionSelection?: boolean }) {
110
111
  const [inputValue = '', setInputValue] = useValueControl<string>({ value, onChange, defaultValue });
111
112
 
112
113
  const prevInputValue = useRef<string>(inputValue);
@@ -115,13 +116,13 @@ export function useSearchInput({
115
116
  (selectedItem?: ItemWithId) => {
116
117
  const newInputValue = selectedOptionFormatter(selectedItem);
117
118
 
118
- if (inputValue !== newInputValue || prevInputValue.current !== newInputValue) {
119
+ if (resetSearchOnOptionSelection && (inputValue !== newInputValue || prevInputValue.current !== newInputValue)) {
119
120
  setInputValue(newInputValue);
120
121
 
121
122
  prevInputValue.current = newInputValue;
122
123
  }
123
124
  },
124
- [inputValue, selectedOptionFormatter, setInputValue],
125
+ [inputValue, resetSearchOnOptionSelection, selectedOptionFormatter, setInputValue],
125
126
  );
126
127
 
127
128
  return { inputValue, setInputValue, prevInputValue, onInputValueChange: setInputValue, updateInputValue };
@@ -144,14 +145,13 @@ export function useHandleDeleteItem(setValue: Handler) {
144
145
  }
145
146
 
146
147
  if (isBaseOptionProps(item)) {
147
- setValue(
148
- (value: SelectionSingleValueType[]) =>
149
- value?.filter(
150
- v =>
151
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
152
- // @ts-expect-error
153
- v !== item.id,
154
- ),
148
+ setValue((value: SelectionSingleValueType[]) =>
149
+ value?.filter(
150
+ v =>
151
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
152
+ // @ts-expect-error
153
+ v !== item.id,
154
+ ),
155
155
  );
156
156
  }
157
157
  },
@@ -119,6 +119,9 @@ type FiledSelectCommonProps = WithSupportProps<{
119
119
  /** Включить нечеткий поиск */
120
120
  enableFuzzySearch?: boolean;
121
121
 
122
+ /** Поведение строки поиска при выборе опции из списка */
123
+ resetSearchOnOptionSelection?: boolean;
124
+
122
125
  onOpenChange?(open: boolean): void;
123
126
 
124
127
  selectedOptionFormatter?: SelectedOptionFormatter;
@@ -131,7 +134,7 @@ type FiledSelectCommonProps = WithSupportProps<{
131
134
  export type FieldSelectSingleProps = FieldSelectPrivateProps &
132
135
  Omit<SelectionSingleState, 'mode'> &
133
136
  WrapperProps &
134
- FiledSelectCommonProps;
137
+ Omit<FiledSelectCommonProps, 'resetSearchOnOptionSelection'>;
135
138
 
136
139
  export type FieldSelectMultipleProps = FieldSelectPrivateProps & {
137
140
  removeByBackspace?: boolean;
@@ -7,12 +7,11 @@ import {
7
7
  KeyboardEventHandler,
8
8
  MouseEventHandler,
9
9
  RefAttributes,
10
- useLayoutEffect,
11
10
  useState,
12
11
  } from 'react';
13
12
  import TextareaAutosize from 'react-textarea-autosize';
14
13
 
15
- import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
14
+ import { extractSupportProps, useLayoutEffect, WithSupportProps } from '@snack-uikit/utils';
16
15
 
17
16
  import styles from './styles.module.scss';
18
17