@snack-uikit/fields 0.53.2-preview-0a70077b.0 → 0.54.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +28 -130
  3. package/dist/cjs/components/FieldSecure/FieldSecure.d.ts +1 -1
  4. package/dist/cjs/components/FieldSelect/FieldSelectMultiple.d.ts +3 -1
  5. package/dist/cjs/components/FieldSelect/FieldSelectMultiple.js +28 -7
  6. package/dist/cjs/components/FieldSelect/FieldSelectSingle.d.ts +3 -1
  7. package/dist/cjs/components/FieldSelect/FieldSelectSingle.js +25 -12
  8. package/dist/cjs/components/FieldSelect/{hooks.d.ts → hooks/common.d.ts} +1 -1
  9. package/dist/cjs/components/FieldSelect/{hooks.js → hooks/common.js} +4 -5
  10. package/dist/cjs/components/FieldSelect/hooks/customOption.d.ts +26 -0
  11. package/dist/cjs/components/FieldSelect/hooks/customOption.js +69 -0
  12. package/dist/cjs/components/FieldSelect/hooks/index.d.ts +2 -0
  13. package/dist/cjs/components/FieldSelect/hooks/index.js +26 -0
  14. package/dist/cjs/components/FieldSelect/index.d.ts +1 -1
  15. package/dist/cjs/components/FieldSelect/types.d.ts +20 -3
  16. package/dist/cjs/components/FieldSelect/utils/customOption.d.ts +4 -0
  17. package/dist/cjs/components/FieldSelect/utils/customOption.js +21 -0
  18. package/dist/cjs/components/FieldSelect/utils/index.d.ts +2 -0
  19. package/dist/cjs/components/FieldSelect/utils/index.js +3 -1
  20. package/dist/cjs/components/FieldText/FieldText.d.ts +1 -1
  21. package/dist/cjs/components/FieldTextArea/FieldTextArea.d.ts +1 -1
  22. package/dist/cjs/components/index.d.ts +0 -1
  23. package/dist/cjs/components/index.js +0 -1
  24. package/dist/cjs/helperComponents/ButtonFieldList/ButtonFieldList.d.ts +1 -1
  25. package/dist/esm/components/FieldSecure/FieldSecure.d.ts +1 -1
  26. package/dist/esm/components/FieldSelect/FieldSelectMultiple.d.ts +3 -1
  27. package/dist/esm/components/FieldSelect/FieldSelectMultiple.js +27 -9
  28. package/dist/esm/components/FieldSelect/FieldSelectSingle.d.ts +3 -1
  29. package/dist/esm/components/FieldSelect/FieldSelectSingle.js +24 -14
  30. package/dist/esm/components/FieldSelect/{hooks.d.ts → hooks/common.d.ts} +1 -1
  31. package/dist/esm/components/FieldSelect/{hooks.js → hooks/common.js} +3 -4
  32. package/dist/esm/components/FieldSelect/hooks/customOption.d.ts +26 -0
  33. package/dist/esm/components/FieldSelect/hooks/customOption.js +38 -0
  34. package/dist/esm/components/FieldSelect/hooks/index.d.ts +2 -0
  35. package/dist/esm/components/FieldSelect/hooks/index.js +2 -0
  36. package/dist/esm/components/FieldSelect/index.d.ts +1 -1
  37. package/dist/esm/components/FieldSelect/types.d.ts +20 -3
  38. package/dist/esm/components/FieldSelect/utils/customOption.d.ts +4 -0
  39. package/dist/esm/components/FieldSelect/utils/customOption.js +13 -0
  40. package/dist/esm/components/FieldSelect/utils/index.d.ts +2 -0
  41. package/dist/esm/components/FieldSelect/utils/index.js +2 -0
  42. package/dist/esm/components/FieldText/FieldText.d.ts +1 -1
  43. package/dist/esm/components/FieldTextArea/FieldTextArea.d.ts +1 -1
  44. package/dist/esm/components/index.d.ts +0 -1
  45. package/dist/esm/components/index.js +0 -1
  46. package/dist/esm/helperComponents/ButtonFieldList/ButtonFieldList.d.ts +1 -1
  47. package/package.json +2 -2
  48. package/src/components/FieldSelect/FieldSelectMultiple.tsx +55 -10
  49. package/src/components/FieldSelect/FieldSelectSingle.tsx +33 -15
  50. package/src/components/FieldSelect/{hooks.ts → hooks/common.ts} +4 -5
  51. package/src/components/FieldSelect/hooks/customOption.ts +90 -0
  52. package/src/components/FieldSelect/hooks/index.ts +2 -0
  53. package/src/components/FieldSelect/index.ts +2 -0
  54. package/src/components/FieldSelect/types.ts +24 -3
  55. package/src/components/FieldSelect/utils/customOption.ts +23 -0
  56. package/src/components/FieldSelect/utils/index.ts +2 -0
  57. package/src/components/index.ts +0 -1
  58. package/dist/cjs/components/FieldAdd/FieldAdd.d.ts +0 -52
  59. package/dist/cjs/components/FieldAdd/FieldAdd.js +0 -216
  60. package/dist/cjs/components/FieldAdd/index.d.ts +0 -2
  61. package/dist/cjs/components/FieldAdd/index.js +0 -13
  62. package/dist/cjs/components/FieldAdd/styles.module.css +0 -51
  63. package/dist/esm/components/FieldAdd/FieldAdd.d.ts +0 -52
  64. package/dist/esm/components/FieldAdd/FieldAdd.js +0 -31
  65. package/dist/esm/components/FieldAdd/index.d.ts +0 -2
  66. package/dist/esm/components/FieldAdd/index.js +0 -1
  67. package/dist/esm/components/FieldAdd/styles.module.css +0 -51
  68. package/src/components/FieldAdd/FieldAdd.tsx +0 -215
  69. package/src/components/FieldAdd/index.ts +0 -3
  70. package/src/components/FieldAdd/styles.module.scss +0 -60
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
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.54.0 (2026-04-21)
7
+
8
+
9
+ ### Features
10
+
11
+ * **IAM-6423:** support triggers for custom field option ([1865a13](https://github.com/cloud-ru-tech/snack-uikit/commit/1865a13f6e270de961295a96ad7c8d80c7cb147d))
12
+
13
+
14
+
15
+
16
+
6
17
  ## 0.53.1 (2026-04-02)
7
18
 
8
19
 
package/README.md CHANGED
@@ -128,50 +128,6 @@ export function FieldSelectExample() {
128
128
  }
129
129
  ```
130
130
 
131
- ## FieldAdd
132
-
133
- ### Description
134
-
135
- - `FieldAdd` — составной контрол для сценариев, где нужно выбрать существующее значение и рядом дать быстрое действие на создание нового.
136
- - Внутри использует одиночный `FieldSelect` и кнопку добавления, поэтому наследует состояния поля (`disabled`, `readonly`, `loading`, `validationState`) и возможности селекта вроде поиска, очистки и кастомных empty-state экранов.
137
- - Подходит для форм и мастеров создания сущностей, где пользователь может либо выбрать уже существующий объект, либо сразу перейти к созданию нового.
138
- - Figma: [`FieldAdd`](https://www.figma.com/design/sLD7Z9OcMX5GPsp9LXb6mw/-PD-2059--%D0%9F%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD-FieldAdd?node-id=16177-2&m=dev).
139
-
140
- ### Example
141
-
142
- ```tsx
143
- import { useState } from 'react';
144
- import { FieldAdd } from '@snack-uikit/fields';
145
-
146
- const OPTIONS = [
147
- { value: 'op1', option: 'Option 1' },
148
- { value: 'op2', option: 'Option 2' },
149
- ];
150
-
151
- export function FieldAddExample() {
152
- const [value, setValue] = useState<string | undefined>();
153
-
154
- return (
155
- <FieldAdd
156
- id='field-add'
157
- label='Select option'
158
- placeholder='Placeholder'
159
- options={OPTIONS}
160
- value={value}
161
- onChange={setValue}
162
- searchable
163
- addButton={{
164
- label: 'Create',
165
- onClick: () => {
166
- // open create flow
167
- },
168
- }}
169
- size='s'
170
- />
171
- );
172
- }
173
- ```
174
-
175
131
  ## FieldSecure
176
132
 
177
133
  ### Description
@@ -599,70 +555,6 @@ FieldStepper в основном предназначен для работы с
599
555
 
600
556
  [//]: DOCUMENTATION_SECTION_START
601
557
  [//]: THIS_SECTION_IS_AUTOGENERATED_PLEASE_DONT_EDIT_IT
602
- ## FieldAdd
603
- ### Props
604
- | name | type | default value | description |
605
- |------|------|---------------|-------------|
606
- | options* | `OptionProps[]` | - | |
607
- | id | `string` | - | Значение html-атрибута id |
608
- | name | `string` | - | Значение html-атрибута name |
609
- | placeholder | `string` | - | Значение плейсхолдера |
610
- | disabled | `boolean` | - | Является ли поле деактивированным |
611
- | readonly | `boolean` | - | Является ли поле доступным только для чтения |
612
- | onFocus | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки получения фокуса |
613
- | onBlur | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки потери фокуса |
614
- | onKeyDown | `KeyboardEventHandler<HTMLInputElement>` | - | Колбек обработки начала нажатия клавиши клавиатуры |
615
- | autoFocus | `boolean` | false | Включен ли авто-фокус для поля |
616
- | className | `string` | - | CSS-класс |
617
- | label | `string` | - | Лейбл |
618
- | labelTooltip | `ReactNode` | - | Всплывающая подсказка лейбла |
619
- | required | `boolean` | - | Является ли поле обязательным |
620
- | caption | `string` | - | Подпись справа от лейбла |
621
- | hint | `string` | - | Подсказка внизу |
622
- | showHintIcon | `boolean` | - | Отображать иконку подсказки |
623
- | size | enum Size: `"s"`, `"m"`, `"l"` | s | Размер |
624
- | validationState | enum ValidationState: `"error"`, `"default"`, `"warning"`, `"success"` | default | Состояние валидации |
625
- | labelTooltipPlacement | enum Placement: `"left"`, `"left-start"`, `"left-end"`, `"right"`, `"right-start"`, `"right-end"`, `"top"`, `"top-start"`, `"top-end"`, `"bottom"`, `"bottom-start"`, `"bottom-end"` | top | Расположение подсказки лейбла |
626
- | error | `string` | - | |
627
- | loading | `boolean` | - | Отображать ли состояние загрузки данных в поле и списке |
628
- | prefix | `ReactNode` | - | Произвольный префикс для поля |
629
- | postfix | `ReactNode` | - | Произвольный постфикс для поля |
630
- | defaultValue | `ItemId` | - | Начальное состояние |
631
- | value | `ItemId` | - | Controlled состояние |
632
- | onChange | `OnChangeHandler<any>` | - | Controlled обработчик измения состояния |
633
- | pinTop | `OptionProps[]` | - | |
634
- | pinBottom | `OptionProps[]` | - | |
635
- | searchable | `boolean` | true | |
636
- | showCopyButton | `boolean` | true | Отображение кнопки Копировать для поля (актуально только для `readonly = true`) |
637
- | onCopyButtonClick | `() => void` | - | Колбек клика по кнопке Копировать для поля |
638
- | showClearButton | `boolean` | true | Отображение кнопки очистки поля |
639
- | prefixIcon | `ReactElement<any, string \| JSXElementConstructor<any>>` | - | Иконка-префикс для поля |
640
- | footer | `ReactNode` | - | |
641
- | widthStrategy | enum PopoverWidthStrategy: `"auto"`, `"gte"`, `"eq"` | - | |
642
- | search | `SearchState` | - | |
643
- | autocomplete | `boolean` | - | |
644
- | addOptionByEnter | `boolean` | - | |
645
- | open | `boolean` | - | |
646
- | enableFuzzySearch | `boolean` | true | Включить нечеткий поиск |
647
- | resetSearchOnOptionSelection | `boolean` | true | Поведение строки поиска при выборе опции из списка, false необходимо при асинхронной подгрузке значений с бэка, в случае если надо поиск оставить как значение при отсутствии данных |
648
- | onOpenChange | `(open: boolean) => void` | - | |
649
- | selectedOptionFormatter | `SelectedOptionFormatter` | - | |
650
- | scrollToSelectedItem | `boolean` | - | Флаг, отвещающий за прокручивание до выбранного элемента |
651
- | virtualized | `boolean` | - | Включить виртуализацию на компоненты списка. Рекомендуется если у вас от 1к элементов списка |
652
- | scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
653
- | scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
654
- | untouchableScrollbars | `boolean` | - | Отключает возможность взаимодействовать со скролбарами мышью. |
655
- | onScroll | `(event?: Event) => void` | - | Колбек на скролл прокручиваемого списка |
656
- | dataFiltered | `boolean` | - | |
657
- | dataError | `boolean` | - | |
658
- | noDataState | `EmptyStateProps` | - | Экран при отстутствии данных |
659
- | noResultsState | `EmptyStateProps` | - | Экран при отстутствии результатов поиска или фильтров |
660
- | errorDataState | `EmptyStateProps` | - | Экран при ошибке запроса |
661
- | addButton | `FieldAddButtonProps` | - | Настройки кнопки добавления справа от поля |
662
- | controlTooltip | `Omit<TooltipProps, "children">` | - | Тултип над контролом выбора значения |
663
- | showAddButton | `boolean` | - | Показывать ли кнопку добавления; в `readonly` режиме кнопка скрывается независимо от значения пропса |
664
- | ref | `LegacyRef<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 {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs} |
665
- | key | `Key` | - | |
666
558
  ## FieldColor
667
559
  ### Props
668
560
  | name | type | default value | description |
@@ -674,17 +566,17 @@ FieldStepper в основном предназначен для работы с
674
566
  | showClearButton | `boolean` | true | Отображение кнопки Очистки поля |
675
567
  | value | `string` | - | Значение input |
676
568
  | onChange | `(value: string) => void` | - | |
677
- | className | `string` | - | Класснейм |
678
569
  | withAlpha | `boolean` | - | Значение с альфаканалом |
679
570
  | autoApply | `boolean` | - | Применять изменения автоматически, если значение false - то изменения происходят по кнопке |
571
+ | className | `string` | - | Класснейм |
680
572
  | colorMode | `{ hex?: boolean; rgb?: boolean; hsv?: boolean; }` | - | |
681
573
  | id | `string` | - | Значение html-атрибута id |
682
574
  | name | `string` | - | Значение html-атрибута name |
683
- | placeholder | `string` | - | Значение плейсхолдера |
684
575
  | disabled | `boolean` | - | Является ли поле деактивированным |
685
576
  | readonly | `boolean` | - | Является ли поле доступным только для чтения |
686
577
  | onFocus | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки получения фокуса |
687
578
  | onBlur | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки потери фокуса |
579
+ | placeholder | `string` | - | Значение плейсхолдера |
688
580
  | autoFocus | `boolean` | false | Включен ли авто-фокус для поля |
689
581
  | label | `string` | - | Лейбл |
690
582
  | labelTooltip | `ReactNode` | - | Всплывающая подсказка лейбла |
@@ -765,15 +657,15 @@ FieldStepper в основном предназначен для работы с
765
657
  | allowMoreThanMaxLength | `boolean` | - | Можно ли вводить больше разрешённого кол-ва символов |
766
658
  | prefixIcon | `ReactElement<any, string \| JSXElementConstructor<any>>` | - | Иконка-префикс для поля |
767
659
  | asyncValueGetter | `() => Promise<string>` | - | Свойство позволяет грузить данные в поле по требованию |
768
- | value | `string` | - | Значение input |
769
660
  | onChange | `(value: string, e?: ChangeEvent<HTMLInputElement>) => void` | - | Колбек смены значения |
661
+ | value | `string` | - | Значение input |
770
662
  | id | `string` | - | Значение html-атрибута id |
771
663
  | name | `string` | - | Значение html-атрибута name |
772
- | placeholder | `string` | - | Значение плейсхолдера |
773
664
  | disabled | `boolean` | - | Является ли поле деактивированным |
774
665
  | readonly | `boolean` | - | Является ли поле доступным только для чтения |
775
666
  | onFocus | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки получения фокуса |
776
667
  | onBlur | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки потери фокуса |
668
+ | placeholder | `string` | - | Значение плейсхолдера |
777
669
  | autoFocus | `boolean` | false | Включен ли авто-фокус для поля |
778
670
  | maxLength | `number` | - | Максимальная длина вводимого значения |
779
671
  | autoComplete | `string \| boolean` | false | Включен ли автокомплит для поля |
@@ -797,13 +689,13 @@ FieldStepper в основном предназначен для работы с
797
689
  | options* | `OptionProps[]` | - | |
798
690
  | id | `string` | - | Значение html-атрибута id |
799
691
  | name | `string` | - | Значение html-атрибута name |
800
- | placeholder | `string` | - | Значение плейсхолдера |
801
692
  | disabled | `boolean` | false | Является ли поле деактивированным |
802
693
  | readonly | `boolean` | false false | Является ли поле доступным только для чтения |
803
694
  | onFocus | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки получения фокуса |
804
695
  | onBlur | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки потери фокуса |
805
- | onKeyDown | `KeyboardEventHandler<HTMLInputElement>` | - | Колбек обработки начала нажатия клавиши клавиатуры |
696
+ | placeholder | `string` | - | Значение плейсхолдера |
806
697
  | autoFocus | `boolean` | false | Включен ли авто-фокус для поля |
698
+ | onKeyDown | `KeyboardEventHandler<HTMLInputElement>` | - | Колбек обработки начала нажатия клавиши клавиатуры |
807
699
  | className | `string` | - | CSS-класс |
808
700
  | label | `string` | - | Лейбл |
809
701
  | labelTooltip | `ReactNode` | - | Всплывающая подсказка лейбла |
@@ -815,12 +707,12 @@ FieldStepper в основном предназначен для работы с
815
707
  | validationState | enum ValidationState: `"error"`, `"default"`, `"warning"`, `"success"` | - | Состояние валидации |
816
708
  | labelTooltipPlacement | enum Placement: `"left"`, `"left-start"`, `"left-end"`, `"right"`, `"right-start"`, `"right-end"`, `"top"`, `"top-start"`, `"top-end"`, `"bottom"`, `"bottom-start"`, `"bottom-end"` | top | Расположение подсказки лейбла |
817
709
  | error | `string` | - | |
818
- | loading | `boolean` | - | Отображать ли состояние загрузки данных в поле и списке |
710
+ | loading | `boolean` | - | |
819
711
  | prefix | `ReactNode` | - | Произвольный префикс для поля |
820
712
  | postfix | `ReactNode` | - | Произвольный постфикс для поля |
821
- | defaultValue | `ItemId \| ItemId[]` | - | Начальное состояние |
822
- | value | `ItemId \| ItemId[]` | - | Controlled состояние |
823
713
  | onChange | `OnChangeHandler<any>` | - | Controlled обработчик измения состояния |
714
+ | value | `ItemId \| ItemId[]` | - | Controlled состояние |
715
+ | defaultValue | `ItemId \| ItemId[]` | - | Начальное состояние |
824
716
  | pinTop | `OptionProps[]` | - | |
825
717
  | pinBottom | `OptionProps[]` | - | |
826
718
  | searchable | `boolean` | - | |
@@ -832,7 +724,7 @@ FieldStepper в основном предназначен для работы с
832
724
  | widthStrategy | enum PopoverWidthStrategy: `"auto"`, `"gte"`, `"eq"` | - | |
833
725
  | search | `SearchState` | - | |
834
726
  | autocomplete | `boolean` | - | |
835
- | addOptionByEnter | `boolean` | - | |
727
+ | addOptionByEnter | `boolean` | - | @deprecated Используйте `addCustomOptionTriggers` |
836
728
  | open | `boolean` | - | |
837
729
  | enableFuzzySearch | `boolean` | - | Включить нечеткий поиск |
838
730
  | resetSearchOnOptionSelection | `boolean` | true | Поведение строки поиска при выборе опции из списка, false необходимо при асинхронной подгрузке значений с бэка, в случае если надо поиск оставить как значение при отсутствии данных |
@@ -840,8 +732,8 @@ FieldStepper в основном предназначен для работы с
840
732
  | selectedOptionFormatter | `SelectedOptionFormatter` | - | |
841
733
  | scrollToSelectedItem | `boolean` | - | Флаг, отвещающий за прокручивание до выбранного элемента |
842
734
  | virtualized | `boolean` | - | Включить виртуализацию на компоненты списка. Рекомендуется если у вас от 1к элементов списка |
843
- | scrollRef | `RefObject<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
844
- | scrollContainerRef | `RefObject<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
735
+ | scrollRef | `Ref<HTMLElement>` | - | Ссылка на элемент, обозначающий самый конец прокручиваемого списка |
736
+ | scrollContainerRef | `Ref<HTMLElement>` | - | Ссылка на контейнер, который скроллится |
845
737
  | untouchableScrollbars | `boolean` | - | Отключает возможность взаимодействовать со скролбарами мышью. |
846
738
  | onScroll | `(event?: Event) => void` | - | Колбек на скролл прокручиваемого списка |
847
739
  | dataFiltered | `boolean` | - | |
@@ -849,10 +741,16 @@ FieldStepper в основном предназначен для работы с
849
741
  | noDataState | `EmptyStateProps` | - | Экран при отстутствии данных |
850
742
  | noResultsState | `EmptyStateProps` | - | Экран при отстутствии результатов поиска или фильтров |
851
743
  | errorDataState | `EmptyStateProps` | - | Экран при ошибке запроса |
744
+ | addCustomOptionTriggers | `FieldSelectSingleAddCustomOptionTrigger[] \| FieldSelectMultipleAddCustomOptionTrigger[]` | - | Триггеры фиксации произвольного значения из строки поиска в режиме `single`. Если передан, имеет приоритет над устаревшим `addOptionByEnter`. Триггеры фиксации произвольного значения из строки поиска в режиме `multiple`. Если передан, имеет приоритет над устаревшим `addOptionByEnter`. |
852
745
  | selection | "single" \| "multiple" | - | |
853
746
  | ref | `LegacyRef<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 {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs} |
854
747
  | key | `Key` | - | |
855
748
  | removeByBackspace | `boolean` | - | |
749
+ ## FieldSelectMultipleAddCustomOptionTrigger
750
+ События, по которым произвольное значение из строки поиска фиксируется в значении поля
751
+ ### Props
752
+ | name | type | default value | description |
753
+ |------|------|---------------|-------------|
856
754
  ## FieldSlider
857
755
  ### Props
858
756
  | name | type | default value | description |
@@ -870,8 +768,8 @@ FieldStepper в основном предназначен для работы с
870
768
  | onFocus | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки получения фокуса |
871
769
  | onBlur | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки потери фокуса |
872
770
  | autoFocus | `boolean` | false | Включен ли авто-фокус для поля |
873
- | value | `number \| number[]` | - | |
874
771
  | onChange | `(value: number \| number[]) => void` | - | |
772
+ | value | `number \| number[]` | - | |
875
773
  | range | `boolean` | - | |
876
774
  | tipFormatter | `(value: string \| number) => ReactNode` | - | |
877
775
  | step | `number` | - | |
@@ -937,22 +835,22 @@ FieldStepper в основном предназначен для работы с
937
835
  | postfix | `ReactNode` | - | Произвольный постфикс для поля |
938
836
  | button | `Button` | - | Кнопка действия внутри поля |
939
837
  | type | "text" \| "tel" \| "email" | text | |
940
- | value | `string` | - | Значение input |
941
838
  | onChange | `(value: string, e?: ChangeEvent<HTMLInputElement>) => void` | - | Колбек смены значения |
942
- | inputMode | enum InputMode: `"search"`, `"none"`, `"text"`, `"tel"`, `"email"`, `"decimal"`, `"numeric"`, `"url"` | - | Режим работы экранной клавиатуры |
839
+ | value | `string` | - | Значение input |
840
+ | inputMode | enum InputMode: `"none"`, `"text"`, `"search"`, `"tel"`, `"email"`, `"decimal"`, `"numeric"`, `"url"` | - | Режим работы экранной клавиатуры |
943
841
  | id | `string` | - | Значение html-атрибута id |
944
842
  | name | `string` | - | Значение html-атрибута name |
945
- | placeholder | `string` | - | Значение плейсхолдера |
946
843
  | disabled | `boolean` | - | Является ли поле деактивированным |
947
844
  | readonly | `boolean` | - | Является ли поле доступным только для чтения |
948
845
  | onFocus | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки получения фокуса |
949
846
  | onBlur | `FocusEventHandler<HTMLInputElement>` | - | Колбек обработки потери фокуса |
950
- | onKeyDown | `KeyboardEventHandler<HTMLInputElement>` | - | Колбек обработки начала нажатия клавиши клавиатуры |
847
+ | placeholder | `string` | - | Значение плейсхолдера |
951
848
  | autoFocus | `boolean` | false | Включен ли авто-фокус для поля |
952
849
  | maxLength | `number` | - | Максимальная длина вводимого значения |
953
850
  | autoComplete | `string \| boolean` | false | Включен ли автокомплит для поля |
954
851
  | spellCheck | `boolean` | true | Значение атрибута spellcheck (проверка орфографии) |
955
852
  | pattern | `string` | - | Регулярное выражение валидного инпута |
853
+ | onKeyDown | `KeyboardEventHandler<HTMLInputElement>` | - | Колбек обработки начала нажатия клавиши клавиатуры |
956
854
  | onPaste | `ClipboardEventHandler<HTMLInputElement>` | - | Колбек обработки вставки значения |
957
855
  | className | `string` | - | CSS-класс |
958
856
  | label | `string` | - | Лейбл |
@@ -983,16 +881,16 @@ FieldStepper в основном предназначен для работы с
983
881
  | value | `string` | - | HTML-аттрибут value |
984
882
  | id | `string` | - | HTML-аттрибут id |
985
883
  | name | `string` | - | HTML-аттрибут name |
986
- | placeholder | `string` | - | Плейсхолдер |
987
884
  | disabled | `boolean` | - | Является ли поле деактивированным |
988
885
  | readonly | `boolean` | - | Является ли поле доступным только на чтение |
989
886
  | onFocus | `FocusEventHandler<HTMLTextAreaElement>` | - | Колбек получения фокуса |
990
887
  | onBlur | `FocusEventHandler<HTMLTextAreaElement>` | - | Колбек потери фокуса |
991
- | onKeyDown | `KeyboardEventHandler<HTMLTextAreaElement>` | - | Колбек нажатия клавиши клавиатуры |
888
+ | placeholder | `string` | - | Плейсхолдер |
992
889
  | autoFocus | `boolean` | - | Включен ли авто-фокус |
993
890
  | maxLength | `number` | - | Максимальное кол-во символов |
994
- | inputMode | enum InputMode: `"search"`, `"none"`, `"text"`, `"tel"`, `"email"`, `"decimal"`, `"numeric"`, `"url"` | - | Режим работы экранной клавиатуры |
891
+ | inputMode | enum InputMode: `"none"`, `"text"`, `"search"`, `"tel"`, `"email"`, `"decimal"`, `"numeric"`, `"url"` | - | Режим работы экранной клавиатуры |
995
892
  | spellCheck | `boolean` | true | Включение проверки орфографии |
893
+ | onKeyDown | `KeyboardEventHandler<HTMLTextAreaElement>` | - | Колбек нажатия клавиши клавиатуры |
996
894
  | className | `string` | - | CSS-класс |
997
895
  | label | `string` | - | Лейбл |
998
896
  | labelTooltip | `ReactNode` | - | Всплывающая подсказка лейбла |
@@ -1042,8 +940,8 @@ FieldStepper в основном предназначен для работы с
1042
940
  ### Props
1043
941
  | name | type | default value | description |
1044
942
  |------|------|---------------|-------------|
1045
- | __@metadata@1080* | `DecoratorMetadataObject` | - | |
1046
- | __@hasInstance@1078* | `(value: any) => boolean` | - | Determines whether the given value inherits from this function if this function was used as a constructor function. A constructor function can control which objects are recognized as its instances by 'instanceof' by overriding this method. |
943
+ | __@metadata@1004* | `DecoratorMetadataObject` | - | |
944
+ | __@hasInstance@1002* | `(value: any) => boolean` | - | Determines whether the given value inherits from this function if this function was used as a constructor function. A constructor function can control which objects are recognized as its instances by 'instanceof' by overriding this method. |
1047
945
  | name* | `string` | - | Returns the name of the function. Function names are read-only and can not be changed. |
1048
946
  | caller* | `Function` | - | |
1049
947
  | arguments* | `any` | - | |
@@ -23,5 +23,5 @@ type FieldSecureOwnProps = {
23
23
  export type FieldSecureProps = WithSupportProps<FieldSecureOwnProps & InputProps & WrapperProps>;
24
24
  export declare const FieldSecure: import("react").ForwardRefExoticComponent<{
25
25
  'data-test-id'?: string;
26
- } & import("react").AriaAttributes & FieldSecureOwnProps & Pick<Partial<InputPrivateProps>, "onChange" | "value"> & Pick<InputPrivateProps, "id" | "name" | "onFocus" | "onBlur" | "disabled" | "placeholder" | "readonly" | "autoFocus" | "autoComplete" | "maxLength"> & WrapperProps & import("react").RefAttributes<HTMLInputElement>>;
26
+ } & import("react").AriaAttributes & FieldSecureOwnProps & Pick<Partial<InputPrivateProps>, "onChange" | "value"> & Pick<InputPrivateProps, "id" | "name" | "onFocus" | "onBlur" | "disabled" | "readonly" | "placeholder" | "autoFocus" | "autoComplete" | "maxLength"> & WrapperProps & import("react").RefAttributes<HTMLInputElement>>;
27
27
  export {};
@@ -28,4 +28,6 @@ export declare const FieldSelectMultiple: import("react").ForwardRefExoticCompon
28
28
  resetSearchOnOptionSelection?: boolean;
29
29
  onOpenChange?(open: boolean): void;
30
30
  selectedOptionFormatter?: SelectedOptionFormatter;
31
- } & Pick<import("@snack-uikit/list").DroplistProps, "onScroll" | "scrollRef" | "scrollContainerRef" | "untouchableScrollbars" | "dataError" | "dataFiltered" | "scrollToSelectedItem" | "virtualized" | "noDataState" | "noResultsState" | "errorDataState">, "showCopyButton" | "onCopyButtonClick"> & import("react").RefAttributes<HTMLInputElement>>;
31
+ } & Pick<import("@snack-uikit/list").DroplistProps, "onScroll" | "scrollRef" | "scrollContainerRef" | "untouchableScrollbars" | "dataError" | "dataFiltered" | "scrollToSelectedItem" | "virtualized" | "noDataState" | "noResultsState" | "errorDataState">, "showCopyButton" | "onCopyButtonClick"> & {
32
+ addCustomOptionTriggers?: import("./types").FieldSelectMultipleAddCustomOptionTrigger[];
33
+ } & import("react").RefAttributes<HTMLInputElement>>;
@@ -62,6 +62,7 @@ exports.FieldSelectMultiple = (0, react_1.forwardRef)((props, ref) => {
62
62
  postfix,
63
63
  removeByBackspace = false,
64
64
  addOptionByEnter = false,
65
+ addCustomOptionTriggers,
65
66
  untouchableScrollbars = false,
66
67
  open: openProp,
67
68
  enableFuzzySearch = true,
@@ -70,7 +71,7 @@ exports.FieldSelectMultiple = (0, react_1.forwardRef)((props, ref) => {
70
71
  selectedOptionFormatter = defaultSelectedOptionFormatter,
71
72
  autoFocus
72
73
  } = props,
73
- rest = __rest(props, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showClearButton", "onKeyDown", "validationState", "search", "autocomplete", "prefixIcon", "prefix", "postfix", "removeByBackspace", "addOptionByEnter", "untouchableScrollbars", "open", "enableFuzzySearch", "resetSearchOnOptionSelection", "onOpenChange", "selectedOptionFormatter", "autoFocus"]);
74
+ rest = __rest(props, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showClearButton", "onKeyDown", "validationState", "search", "autocomplete", "prefixIcon", "prefix", "postfix", "removeByBackspace", "addOptionByEnter", "addCustomOptionTriggers", "untouchableScrollbars", "open", "enableFuzzySearch", "resetSearchOnOptionSelection", "onOpenChange", "selectedOptionFormatter", "autoFocus"]);
74
75
  const localRef = (0, react_1.useRef)(null);
75
76
  const inputPlugRef = (0, react_1.useRef)(null);
76
77
  const contentRef = (0, react_1.useRef)(null);
@@ -102,6 +103,17 @@ exports.FieldSelectMultiple = (0, react_1.forwardRef)((props, ref) => {
102
103
  selectedOptionFormatter,
103
104
  resetSearchOnOptionSelection
104
105
  }));
106
+ const {
107
+ resolvedAddCustomOptionTriggers,
108
+ tryCommitCustomOptionFromInput
109
+ } = (0, hooks_2.useFieldSelectMultipleCustomOption)({
110
+ addCustomOptionTriggers,
111
+ addOptionByEnter,
112
+ inputValue,
113
+ value,
114
+ setValue,
115
+ updateInputValue
116
+ });
105
117
  const prefixSettings = (0, hooks_1.usePrefix)({
106
118
  prefix,
107
119
  disabled
@@ -155,6 +167,12 @@ exports.FieldSelectMultiple = (0, react_1.forwardRef)((props, ref) => {
155
167
  setOpen
156
168
  });
157
169
  const handleItemDelete = (0, hooks_2.useHandleDeleteItem)(setValue);
170
+ const handleTagDelete = (0, react_1.useCallback)(option => () => {
171
+ var _a;
172
+ const deleteItemHandler = handleItemDelete(option);
173
+ deleteItemHandler();
174
+ (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.focus();
175
+ }, [handleItemDelete]);
158
176
  const handleOnKeyDown = onKeyDown => e => {
159
177
  if (removeByBackspace && e.code === 'Backspace' && inputValue === '') {
160
178
  if ((selectedItems === null || selectedItems === void 0 ? void 0 : selectedItems.length) && !selectedItems.slice(-1)[0].disabled) {
@@ -164,11 +182,13 @@ exports.FieldSelectMultiple = (0, react_1.forwardRef)((props, ref) => {
164
182
  if (e.code === 'Enter') {
165
183
  e.stopPropagation();
166
184
  e.preventDefault();
167
- }
168
- if (addOptionByEnter && e.code === 'Enter' && inputValue !== '') {
169
- if (!(value !== null && value !== void 0 ? value : []).includes(inputValue)) {
170
- setValue(value => (value !== null && value !== void 0 ? value : []).concat(inputValue));
171
- updateInputValue();
185
+ tryCommitCustomOptionFromInput('enter');
186
+ } else {
187
+ const customOptionTrigger = (0, utils_3.getCustomOptionTriggerByCode)(e.code);
188
+ if ((0, utils_3.shouldHandleCustomOptionTrigger)(customOptionTrigger, resolvedAddCustomOptionTriggers)) {
189
+ e.stopPropagation();
190
+ e.preventDefault();
191
+ tryCommitCustomOptionFromInput(customOptionTrigger);
172
192
  }
173
193
  }
174
194
  if (!open && prevInputValue.current !== inputValue) {
@@ -194,6 +214,7 @@ exports.FieldSelectMultiple = (0, react_1.forwardRef)((props, ref) => {
194
214
  const handleBlur = e => {
195
215
  var _a;
196
216
  if (!open && !buttonsRefs.filter(Boolean).includes(e.relatedTarget)) {
217
+ tryCommitCustomOptionFromInput('blur');
197
218
  updateInputValue();
198
219
  (_a = rest === null || rest === void 0 ? void 0 : rest.onBlur) === null || _a === void 0 ? void 0 : _a.call(rest, e);
199
220
  }
@@ -278,7 +299,7 @@ exports.FieldSelectMultiple = (0, react_1.forwardRef)((props, ref) => {
278
299
  tabIndex: -1,
279
300
  label: selectedOptionFormatter(option),
280
301
  appearance: (_a = option.appearance) !== null && _a !== void 0 ? _a : 'neutral',
281
- onDelete: !option.disabled && !disabled && !readonly ? handleItemDelete(option) : undefined,
302
+ onDelete: !option.disabled && !disabled && !readonly ? handleTagDelete(option) : undefined,
282
303
  className: styles_module_scss_1.default.tag,
283
304
  "data-disabled": disabled || undefined
284
305
  }, option.id);
@@ -26,4 +26,6 @@ export declare const FieldSelectSingle: import("react").ForwardRefExoticComponen
26
26
  resetSearchOnOptionSelection?: boolean;
27
27
  onOpenChange?(open: boolean): void;
28
28
  selectedOptionFormatter?: SelectedOptionFormatter;
29
- } & Pick<import("@snack-uikit/list").DroplistProps, "onScroll" | "scrollRef" | "scrollContainerRef" | "untouchableScrollbars" | "dataError" | "dataFiltered" | "scrollToSelectedItem" | "virtualized" | "noDataState" | "noResultsState" | "errorDataState"> & import("react").RefAttributes<HTMLInputElement>>;
29
+ } & Pick<import("@snack-uikit/list").DroplistProps, "onScroll" | "scrollRef" | "scrollContainerRef" | "untouchableScrollbars" | "dataError" | "dataFiltered" | "scrollToSelectedItem" | "virtualized" | "noDataState" | "noResultsState" | "errorDataState"> & {
30
+ addCustomOptionTriggers?: import("./types").FieldSelectSingleAddCustomOptionTrigger[];
31
+ } & import("react").RefAttributes<HTMLInputElement>>;
@@ -60,6 +60,7 @@ exports.FieldSelectSingle = (0, react_1.forwardRef)((props, ref) => {
60
60
  prefix,
61
61
  postfix,
62
62
  addOptionByEnter = false,
63
+ addCustomOptionTriggers: addCustomOptionTriggersProp,
63
64
  untouchableScrollbars = false,
64
65
  open: openProp,
65
66
  onOpenChange,
@@ -69,7 +70,7 @@ exports.FieldSelectSingle = (0, react_1.forwardRef)((props, ref) => {
69
70
  onCopyButtonClick,
70
71
  autoFocus
71
72
  } = props,
72
- rest = __rest(props, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showCopyButton", "showClearButton", "onKeyDown", "required", "validationState", "search", "autocomplete", "prefixIcon", "prefix", "postfix", "addOptionByEnter", "untouchableScrollbars", "open", "onOpenChange", "selectedOptionFormatter", "enableFuzzySearch", "resetSearchOnOptionSelection", "onCopyButtonClick", "autoFocus"]);
73
+ rest = __rest(props, ["id", "name", "placeholder", "size", "options", "value", "defaultValue", "onChange", "disabled", "readonly", "searchable", "showCopyButton", "showClearButton", "onKeyDown", "required", "validationState", "search", "autocomplete", "prefixIcon", "prefix", "postfix", "addOptionByEnter", "addCustomOptionTriggers", "untouchableScrollbars", "open", "onOpenChange", "selectedOptionFormatter", "enableFuzzySearch", "resetSearchOnOptionSelection", "onCopyButtonClick", "autoFocus"]);
73
74
  const localRef = (0, react_1.useRef)(null);
74
75
  const [open = false, setOpen] = (0, hooks_1.useValueControl)({
75
76
  value: openProp,
@@ -160,13 +161,6 @@ exports.FieldSelectSingle = (0, react_1.forwardRef)((props, ref) => {
160
161
  onCopyButtonClick,
161
162
  valueToCopy: selectedOptionFormatter(selectedItem)
162
163
  });
163
- const handleBlur = e => {
164
- var _a;
165
- if (!open && !buttonsRefs.filter(Boolean).includes(e.relatedTarget)) {
166
- updateInputValue(selectedItem);
167
- (_a = rest === null || rest === void 0 ? void 0 : rest.onBlur) === null || _a === void 0 ? void 0 : _a.call(rest, e);
168
- }
169
- };
170
164
  const commonHandleOnKeyDown = (0, hooks_2.useHandleOnKeyDown)({
171
165
  inputKeyDownNavigationHandler,
172
166
  onInputKeyDownProp,
@@ -180,6 +174,27 @@ exports.FieldSelectSingle = (0, react_1.forwardRef)((props, ref) => {
180
174
  setValue(newValue);
181
175
  }
182
176
  }, [setOpen, setValue]);
177
+ const {
178
+ resolvedAddCustomOptionTriggers,
179
+ tryCommitCustomOptionFromInput
180
+ } = (0, hooks_2.useFieldSelectSingleCustomOption)({
181
+ addCustomOptionTriggers: addCustomOptionTriggersProp,
182
+ addOptionByEnter,
183
+ inputValue,
184
+ handleSelectionChange
185
+ });
186
+ const handleBlur = e => {
187
+ var _a;
188
+ if (!open && !buttonsRefs.filter(Boolean).includes(e.relatedTarget)) {
189
+ const commitOnBlur = (0, utils_3.shouldHandleCustomOptionTrigger)('blur', resolvedAddCustomOptionTriggers) && inputValue !== '';
190
+ if (commitOnBlur) {
191
+ tryCommitCustomOptionFromInput('blur');
192
+ } else {
193
+ updateInputValue(selectedItem);
194
+ }
195
+ (_a = rest === null || rest === void 0 ? void 0 : rest.onBlur) === null || _a === void 0 ? void 0 : _a.call(rest, e);
196
+ }
197
+ };
183
198
  const handleOnKeyDown = onKeyDown => e => {
184
199
  if (!open && prevInputValue.current !== inputValue) {
185
200
  setOpen(true);
@@ -187,16 +202,14 @@ exports.FieldSelectSingle = (0, react_1.forwardRef)((props, ref) => {
187
202
  if (e.code === 'Enter') {
188
203
  e.stopPropagation();
189
204
  e.preventDefault();
190
- }
191
- if (addOptionByEnter && e.code === 'Enter' && inputValue !== '') {
192
- handleSelectionChange(inputValue);
205
+ tryCommitCustomOptionFromInput('enter');
193
206
  }
194
207
  commonHandleOnKeyDown(onKeyDown)(e);
195
208
  };
196
209
  const handleOpenChange = open => {
197
210
  if ((0, utils_1.isBrowser)() && !readonly && !disabled && !buttonsRefs.includes(document.activeElement)) {
198
211
  setOpen(open);
199
- if (!open) {
212
+ if (!open && !(0, utils_3.shouldHandleCustomOptionTrigger)('blur', resolvedAddCustomOptionTriggers)) {
200
213
  updateInputValue(selectedItem);
201
214
  }
202
215
  }
@@ -1,7 +1,7 @@
1
1
  import { KeyboardEvent, KeyboardEventHandler, MouseEvent, RefObject } from 'react';
2
2
  import { Handler } from 'uncontrollable';
3
3
  import { ItemProps } from '@snack-uikit/list';
4
- import { ItemWithId, SearchState, SelectedOptionFormatter } from './types';
4
+ import { ItemWithId, SearchState, SelectedOptionFormatter } from '../types';
5
5
  type UseHandleOnKeyDownProps = {
6
6
  inputKeyDownNavigationHandler: KeyboardEventHandler<HTMLInputElement>;
7
7
  onInputKeyDownProp: KeyboardEventHandler<HTMLInputElement> | undefined;
@@ -17,10 +17,9 @@ const fuzzy_search_1 = __importDefault(require("fuzzy-search"));
17
17
  const react_1 = require("react");
18
18
  const input_private_1 = require("@snack-uikit/input-private");
19
19
  const list_1 = require("@snack-uikit/list");
20
- const hooks_1 = require("../../hooks");
21
- const legacy_1 = require("./legacy");
22
- const utils_1 = require("./utils");
23
- const filterItemsByFlattenIds_1 = require("./utils/filterItemsByFlattenIds");
20
+ const hooks_1 = require("../../../hooks");
21
+ const legacy_1 = require("../legacy");
22
+ const utils_1 = require("../utils");
24
23
  function useHandleOnKeyDown(_ref) {
25
24
  let {
26
25
  setOpen,
@@ -173,7 +172,7 @@ function useSearch(items) {
173
172
  }, [enableFuzzySearch, flattenItems]);
174
173
  const filterFunction = (0, react_1.useCallback)(search => {
175
174
  const filteredIds = filterFlattenFunction(search).map(item => item.id);
176
- return (0, filterItemsByFlattenIds_1.filterItemsByFlattenIds)(items, filteredIds);
175
+ return (0, utils_1.filterItemsByFlattenIds)(items, filteredIds);
177
176
  }, [filterFlattenFunction, items]);
178
177
  return (0, react_1.useCallback)(search => search.length >= DEFAULT_MIN_SEARCH_INPUT_LENGTH ? filterFunction(search) : items, [filterFunction, items]);
179
178
  }
@@ -0,0 +1,26 @@
1
+ import { Handler } from 'uncontrollable';
2
+ import { SelectionSingleValueType } from '@snack-uikit/list';
3
+ import { FieldSelectMultipleAddCustomOptionTrigger } from '../types';
4
+ type UseResolvedAddCustomOptionTriggersParams = {
5
+ addCustomOptionTriggers?: FieldSelectMultipleAddCustomOptionTrigger[];
6
+ addOptionByEnter: boolean;
7
+ };
8
+ type UseFieldSelectMultipleCustomOptionParams = UseResolvedAddCustomOptionTriggersParams & {
9
+ inputValue: string;
10
+ value: SelectionSingleValueType[] | undefined;
11
+ setValue: Handler;
12
+ updateInputValue: () => void;
13
+ };
14
+ export declare function useFieldSelectMultipleCustomOption({ addCustomOptionTriggers, addOptionByEnter, inputValue, value, setValue, updateInputValue, }: UseFieldSelectMultipleCustomOptionParams): {
15
+ resolvedAddCustomOptionTriggers: FieldSelectMultipleAddCustomOptionTrigger[];
16
+ tryCommitCustomOptionFromInput: (trigger: FieldSelectMultipleAddCustomOptionTrigger) => void;
17
+ };
18
+ type UseFieldSelectSingleCustomOptionParams = UseResolvedAddCustomOptionTriggersParams & {
19
+ inputValue: string;
20
+ handleSelectionChange: (value: SelectionSingleValueType) => void;
21
+ };
22
+ export declare function useFieldSelectSingleCustomOption({ addCustomOptionTriggers, addOptionByEnter, inputValue, handleSelectionChange, }: UseFieldSelectSingleCustomOptionParams): {
23
+ resolvedAddCustomOptionTriggers: FieldSelectMultipleAddCustomOptionTrigger[];
24
+ tryCommitCustomOptionFromInput: (trigger: FieldSelectMultipleAddCustomOptionTrigger) => void;
25
+ };
26
+ export {};