@hh.ru/magritte-ui-new-select 1.0.1 → 1.1.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.
Files changed (60) hide show
  1. package/Select.d.ts +5 -2
  2. package/Select.js +21 -9
  3. package/Select.js.map +1 -1
  4. package/SelectSearchTrigger.d.ts +3 -0
  5. package/SelectSearchTrigger.js +61 -0
  6. package/SelectSearchTrigger.js.map +1 -0
  7. package/SelectTrigger.d.ts +3 -0
  8. package/SelectTrigger.js +42 -0
  9. package/SelectTrigger.js.map +1 -0
  10. package/dataProviderTypes.js +1 -0
  11. package/index.css +25 -0
  12. package/index.d.ts +1 -0
  13. package/index.js +18 -6
  14. package/index.js.map +1 -1
  15. package/internal/ConfigContext.d.ts +1 -3
  16. package/internal/ConfigContext.js +3 -4
  17. package/internal/ConfigContext.js.map +1 -1
  18. package/internal/NavigationManagement.d.ts +8 -0
  19. package/internal/NavigationManagement.js +29 -0
  20. package/internal/NavigationManagement.js.map +1 -0
  21. package/internal/SearchStateContext.d.ts +10 -0
  22. package/internal/SearchStateContext.js +21 -0
  23. package/internal/SearchStateContext.js.map +1 -0
  24. package/internal/SelectDataProvider.d.ts +2 -2
  25. package/internal/SelectDataProvider.js +6 -4
  26. package/internal/SelectDataProvider.js.map +1 -1
  27. package/internal/SelectStateContext.d.ts +5 -5
  28. package/internal/SelectStateContext.js +43 -12
  29. package/internal/SelectStateContext.js.map +1 -1
  30. package/internal/SelectStore.d.ts +16 -0
  31. package/internal/SelectStore.js +60 -0
  32. package/internal/SelectStore.js.map +1 -0
  33. package/internal/VisibilityContext.js +1 -0
  34. package/internal/focusOrchestrator.d.ts +35 -0
  35. package/internal/focusOrchestrator.js +93 -0
  36. package/internal/focusOrchestrator.js.map +1 -0
  37. package/internal/slots.js +1 -0
  38. package/internal/useDataProvider.d.ts +8 -0
  39. package/internal/{useSearch.js → useDataProvider.js} +11 -31
  40. package/internal/useDataProvider.js.map +1 -0
  41. package/internal/useFocusWithin.d.ts +11 -0
  42. package/internal/useFocusWithin.js +87 -0
  43. package/internal/useFocusWithin.js.map +1 -0
  44. package/internal/utils.d.ts +5 -1
  45. package/internal/utils.js +16 -4
  46. package/internal/utils.js.map +1 -1
  47. package/package.json +4 -2
  48. package/types.d.ts +9 -6
  49. package/types.js +1 -0
  50. package/useSelectTrigger.d.ts +6 -0
  51. package/useSelectTrigger.js +112 -0
  52. package/useSelectTrigger.js.map +1 -0
  53. package/internal/NavigationContext.d.ts +0 -17
  54. package/internal/NavigationContext.js +0 -30
  55. package/internal/NavigationContext.js.map +0 -1
  56. package/internal/useSearch.d.ts +0 -8
  57. package/internal/useSearch.js.map +0 -1
  58. package/internal/useSelectState.d.ts +0 -16
  59. package/internal/useSelectState.js +0 -145
  60. package/internal/useSelectState.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["src/internal/utils.ts"],"sourcesContent":["import { useRef, useCallback, useLayoutEffect, useMemo, SyntheticEvent } from 'react';\n\nimport { StaticDataFetcherItem } from '@hh.ru/magritte-common-data-provider';\nimport { findNextFocusableElement } from '@hh.ru/magritte-common-keyboard';\n\n// но не проверяет порядок и дубликаты\nexport const isArraysEquals = <T>(arrayA: T[], arrayB: T[]): boolean =>\n arrayA.length === arrayB.length && arrayA.every((item) => arrayB.includes(item));\n\n// убирает `null` с контекста и падает с внятной ошибкой\nexport const assertSelectContext = <T>(value: T | null, hookName: string): T => {\n if (value === null) {\n throw new Error(`${hookName} must be used within <Select>`);\n }\n return value;\n};\n\n// возвращает стабильную ссылку на колбэк (не вызывать в рендере)\nexport const useEventCallback = <Callback extends (...args: never[]) => unknown>(\n callback: Callback | undefined\n): Callback => {\n const callbackRef = useRef(callback);\n\n useLayoutEffect(() => {\n callbackRef.current = callback;\n });\n\n const stableCallback = useCallback((...args: Parameters<Callback>) => {\n return callbackRef.current?.(...args);\n }, []) as Callback;\n\n return stableCallback;\n};\n\n// placeholder в тригерах собирается одинаково\nexport const useSelectedLabels = <DataType extends StaticDataFetcherItem>(values: DataType | DataType[]): string[] => {\n return useMemo(() => {\n const selectedItems = Array.isArray(values) ? values : [values].filter(Boolean);\n return selectedItems.map((item) => item.text ?? item.value);\n }, [values]);\n};\n\nexport const focusOptionsList = (\n event: SyntheticEvent,\n drop: HTMLElement | null | undefined,\n direction: 'up' | 'down'\n): void => {\n if (drop) {\n const nextFocusableElement = findNextFocusableElement(drop, null, direction, 'list');\n if (nextFocusableElement !== null) {\n event.preventDefault();\n nextFocusableElement.focus();\n }\n }\n};\n"],"names":[],"mappings":";;;AAKA;AACO,MAAM,cAAc,GAAG,CAAI,MAAW,EAAE,MAAW,KACtD,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAErF;MACa,mBAAmB,GAAG,CAAI,KAAe,EAAE,QAAgB,KAAO;AAC3E,IAAA,IAAI,KAAK,KAAK,IAAI,EAAE;AAChB,QAAA,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAA,6BAAA,CAA+B,CAAC,CAAC;KAC/D;AACD,IAAA,OAAO,KAAK,CAAC;AACjB,EAAE;AAEF;AACa,MAAA,gBAAgB,GAAG,CAC5B,QAA8B,KACpB;AACV,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAErC,eAAe,CAAC,MAAK;AACjB,QAAA,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;AACnC,KAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,GAAG,IAA0B,KAAI;QACjE,OAAO,WAAW,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC,CAAC;KACzC,EAAE,EAAE,CAAa,CAAC;AAEnB,IAAA,OAAO,cAAc,CAAC;AAC1B,EAAE;AAEF;AACa,MAAA,iBAAiB,GAAG,CAAyC,MAA6B,KAAc;IACjH,OAAO,OAAO,CAAC,MAAK;QAChB,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAChF,QAAA,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;AAChE,KAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACjB,EAAE;AAEW,MAAA,gBAAgB,GAAG,CAC5B,KAAqB,EACrB,IAAoC,EACpC,SAAwB,KAClB;IACN,IAAI,IAAI,EAAE;AACN,QAAA,MAAM,oBAAoB,GAAG,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AACrF,QAAA,IAAI,oBAAoB,KAAK,IAAI,EAAE;YAC/B,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,oBAAoB,CAAC,KAAK,EAAE,CAAC;SAChC;KACJ;AACL;;;;"}
1
+ {"version":3,"file":"utils.js","sources":["src/internal/utils.ts"],"sourcesContent":["import { useRef, useCallback, useLayoutEffect, useMemo, SyntheticEvent } from 'react';\n\nimport { StaticDataFetcherItem } from '@hh.ru/magritte-common-data-provider';\nimport { findNextFocusableElement } from '@hh.ru/magritte-common-keyboard';\nimport { ValueTypeHelper } from '@hh.ru/magritte-ui-new-select/types';\n\n// не проверяет порядок и дубликаты\nexport const isArraysEquals = <T>(arrayA: T[], arrayB: T[]): boolean =>\n arrayA.length === arrayB.length && arrayA.every((item) => arrayB.includes(item));\n\n// убирает `null` с контекста и падает с внятной ошибкой\nexport const assertSelectContext = <T>(value: T | null, hookName: string): T => {\n if (value === null) {\n throw new Error(`${hookName} must be used within <Select>`);\n }\n return value;\n};\n\n// возвращает стабильную ссылку на колбэк (не вызывать в рендере)\nexport const useEventCallback = <Callback extends (...args: never[]) => unknown>(\n callback: Callback | undefined\n): Callback => {\n const callbackRef = useRef(callback);\n\n useLayoutEffect(() => {\n callbackRef.current = callback;\n });\n\n const stableCallback = useCallback((...args: Parameters<Callback>) => {\n return callbackRef.current?.(...args);\n }, []) as Callback;\n\n return stableCallback;\n};\n\n// placeholder в тригерах собирается одинаково\nexport const useSelectedLabels = <DataType extends StaticDataFetcherItem>(values: readonly DataType[]): string[] => {\n return useMemo(() => {\n return values.map((item) => item.text ?? item.value);\n }, [values]);\n};\n\n// single select работает с обьектом DataType, multiple с массивом\nexport const value2Array = <MultipleType extends boolean, DataType extends StaticDataFetcherItem>(\n value: ValueTypeHelper<MultipleType, DataType> | undefined\n): DataType[] => {\n if (!value) {\n return [];\n }\n return (Array.isArray(value) ? value : [value]) as DataType[];\n};\n\n// достает value из DataType на базе StaticDataFetcherItem\nexport const extractValues = <DataType extends StaticDataFetcherItem>(items: readonly DataType[]): string[] => {\n return items.map((item) => item.value);\n};\n\n// навигация по дропу\nexport const focusOptionsList = (\n event: SyntheticEvent,\n drop: HTMLElement | null | undefined,\n direction: 'up' | 'down'\n): void => {\n if (drop) {\n const nextFocusableElement = findNextFocusableElement(drop, null, direction, 'list');\n if (nextFocusableElement !== null) {\n event.preventDefault();\n nextFocusableElement.focus();\n }\n }\n};\n\n// применяет Omit к каждому варианту union-типа отдельно\nexport type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n"],"names":[],"mappings":";;;AAMA;AACO,MAAM,cAAc,GAAG,CAAI,MAAW,EAAE,MAAW,KACtD,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAErF;MACa,mBAAmB,GAAG,CAAI,KAAe,EAAE,QAAgB,KAAO;AAC3E,IAAA,IAAI,KAAK,KAAK,IAAI,EAAE;AAChB,QAAA,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAA,6BAAA,CAA+B,CAAC,CAAC;KAC/D;AACD,IAAA,OAAO,KAAK,CAAC;AACjB,EAAE;AAEF;AACa,MAAA,gBAAgB,GAAG,CAC5B,QAA8B,KACpB;AACV,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAErC,eAAe,CAAC,MAAK;AACjB,QAAA,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;AACnC,KAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,GAAG,IAA0B,KAAI;QACjE,OAAO,WAAW,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC,CAAC;KACzC,EAAE,EAAE,CAAa,CAAC;AAEnB,IAAA,OAAO,cAAc,CAAC;AAC1B,EAAE;AAEF;AACa,MAAA,iBAAiB,GAAG,CAAyC,MAA2B,KAAc;IAC/G,OAAO,OAAO,CAAC,MAAK;AAChB,QAAA,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;AACzD,KAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACjB,EAAE;AAEF;AACa,MAAA,WAAW,GAAG,CACvB,KAA0D,KAC9C;IACZ,IAAI,CAAC,KAAK,EAAE;AACR,QAAA,OAAO,EAAE,CAAC;KACb;AACD,IAAA,QAAQ,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,KAAK,CAAC,EAAgB;AAClE,EAAE;AAEF;AACa,MAAA,aAAa,GAAG,CAAyC,KAA0B,KAAc;AAC1G,IAAA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3C,EAAE;AAEF;AACa,MAAA,gBAAgB,GAAG,CAC5B,KAAqB,EACrB,IAAoC,EACpC,SAAwB,KAClB;IACN,IAAI,IAAI,EAAE;AACN,QAAA,MAAM,oBAAoB,GAAG,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AACrF,QAAA,IAAI,oBAAoB,KAAK,IAAI,EAAE;YAC/B,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,oBAAoB,CAAC,KAAK,EAAE,CAAC;SAChC;KACJ;AACL;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hh.ru/magritte-ui-new-select",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "sideEffects": [
@@ -28,6 +28,8 @@
28
28
  "dependencies": {
29
29
  "@hh.ru/magritte-common-data-provider": "1.3.7",
30
30
  "@hh.ru/magritte-common-keyboard": "4.3.4",
31
+ "@hh.ru/magritte-common-use-disabled": "1.0.15",
32
+ "@hh.ru/magritte-common-use-multiple-refs": "1.1.11",
31
33
  "@hh.ru/magritte-common-use-translation": "3.1.0",
32
34
  "@hh.ru/magritte-internal-slot-registry": "1.1.0",
33
35
  "@hh.ru/magritte-ui-bottom-sheet": "9.4.11",
@@ -40,5 +42,5 @@
40
42
  "@hh.ru/magritte-ui-title": "8.3.4",
41
43
  "@hh.ru/magritte-ui-trigger": "4.3.26"
42
44
  },
43
- "gitHead": "73e0fbef72d8f731bbda034d85b96c50f7fe3bd3"
45
+ "gitHead": "dcac3032190e4bd234a2c49a73b17adc5b595fcb"
44
46
  }
package/types.d.ts CHANGED
@@ -1,24 +1,27 @@
1
- import { Dispatch, SetStateAction, ReactNode } from 'react';
1
+ import { ReactNode, Dispatch, SetStateAction } from 'react';
2
2
  import { StaticDataFetcherItem } from '@hh.ru/magritte-common-data-provider';
3
3
  import { DataProviderProps } from '@hh.ru/magritte-ui-new-select/dataProviderTypes';
4
+ import { DistributiveOmit } from '@hh.ru/magritte-ui-new-select/internal/utils';
5
+ import { TriggerProps } from '@hh.ru/magritte-ui-trigger';
4
6
  export type DelimiterOptionType = 'delimiter';
5
7
  export type SelectOptionType = 'checkbox' | 'label' | 'radio';
6
8
  export type CommitModel = 'instant' | 'confirm';
9
+ type ControlledTriggerKeys = 'expanded' | 'onBlur' | 'onChange' | 'onClear' | 'onFocus' | 'onKeyDown' | 'values';
10
+ export type SelectUncontrolledTriggerProps = DistributiveOmit<TriggerProps, ControlledTriggerKeys>;
11
+ export type SelectControlledTriggerProps = Pick<TriggerProps, ControlledTriggerKeys>;
7
12
  export interface OnChangeAction<DataType extends StaticDataFetcherItem> {
8
13
  (value: DataType, needToPut: boolean): void;
9
14
  }
10
15
  export interface OnOptionsChangeCallback<DataType extends StaticDataFetcherItem> {
11
16
  (options: SelectOption<DataType>[]): void;
12
17
  }
13
- export interface SearchValue {
18
+ export interface SearchValueState {
14
19
  searchValue: string;
20
+ setSearchValue: Dispatch<SetStateAction<string>>;
15
21
  }
16
22
  export interface OptionsCount {
17
23
  optionsCount: number;
18
24
  }
19
- export interface SetSearchValue {
20
- setSearchValue: Dispatch<SetStateAction<string>>;
21
- }
22
25
  export interface SelectOption<DataType extends StaticDataFetcherItem> {
23
26
  data: DataType;
24
27
  disabled?: boolean;
@@ -46,10 +49,10 @@ export interface SelectBaseProps<MultipleType extends boolean, DataType extends
46
49
  /** Обработчик получения опций */
47
50
  onOptionsChange?: OnOptionsChangeCallback<DataType>;
48
51
  /** Обработчик события выбора option */
49
- onSelectOption?: (values: DataType[]) => void;
50
52
  /** Значение Select, для multiple — это массив */
51
53
  value?: ValueTypeHelper<MultipleType, DataType>;
52
54
  /** Флаг включения загрузки */
53
55
  loading?: boolean;
54
56
  }
55
57
  export type SelectProps<MultipleType extends boolean, DataType extends StaticDataFetcherItem> = SelectBaseProps<MultipleType, DataType> & DataProviderProps<DataType>;
58
+ export {};
package/types.js CHANGED
@@ -1,2 +1,3 @@
1
+ import './index.css';
1
2
 
2
3
  //# sourceMappingURL=types.js.map
@@ -0,0 +1,6 @@
1
+ import { RefObject } from 'react';
2
+ import { StaticDataFetcherItem } from '@hh.ru/magritte-common-data-provider';
3
+ import { SelectControlledTriggerProps } from '@hh.ru/magritte-ui-new-select/types';
4
+ export declare const useGetTriggerRef: () => RefObject<HTMLElement> | undefined;
5
+ export declare const useTriggerRef: () => RefObject<HTMLElement>;
6
+ export declare const useSelectTrigger: <DataType extends StaticDataFetcherItem>(disabled?: boolean) => SelectControlledTriggerProps;
@@ -0,0 +1,112 @@
1
+ import './index.css';
2
+ import { useRef, useEffect, useCallback } from 'react';
3
+ import { keyboardMatches, keyboardKeys, keyboardMatch } from '@hh.ru/magritte-common-keyboard';
4
+ import { useDataProvider } from './internal/SelectDataProvider.js';
5
+ import { useSelectStore, useSelected } from './internal/SelectStateContext.js';
6
+ import { useVisibility } from './internal/VisibilityContext.js';
7
+ import { useFocusOrchestrator } from './internal/focusOrchestrator.js';
8
+ import { useSelectElementsValue, useRegisterSelectElementsSlot } from './internal/slots.js';
9
+ import { useSelectedLabels } from './internal/utils.js';
10
+ import 'react/jsx-runtime';
11
+ import '@hh.ru/magritte-common-data-provider';
12
+ import './internal/useDataProvider.js';
13
+ import './internal/SearchStateContext.js';
14
+ import './internal/ConfigContext.js';
15
+ import './internal/SelectStore.js';
16
+ import '@hh.ru/magritte-internal-slot-registry';
17
+
18
+ // TODO заводил под тест, хук только получает триггер, но нерегает его в сторе
19
+ const useGetTriggerRef = () => {
20
+ const activatorRef = useSelectElementsValue('activatorRef');
21
+ return activatorRef;
22
+ };
23
+ const useTriggerRef = () => {
24
+ const activatorRef = useRef(null);
25
+ useRegisterSelectElementsSlot('activatorRef', activatorRef);
26
+ return activatorRef;
27
+ };
28
+ const useSelectTrigger = (disabled) => {
29
+ const showedByFocus = useRef(false);
30
+ const focusedByPointer = useRef(false);
31
+ const { showOptions, toggleListVisibility } = useVisibility();
32
+ const { optionList } = useDataProvider();
33
+ const orchestrator = useFocusOrchestrator();
34
+ const selectStore = useSelectStore();
35
+ const committedValues = useSelected(selectStore);
36
+ const selectedLabels = useSelectedLabels(committedValues);
37
+ // определяем источник фокуса - pointer или keyboard
38
+ useEffect(() => {
39
+ const onPointerDownDocument = () => {
40
+ focusedByPointer.current = true;
41
+ };
42
+ const onKeyDownDocument = () => {
43
+ focusedByPointer.current = false;
44
+ };
45
+ document.addEventListener('pointerdown', onPointerDownDocument, true);
46
+ document.addEventListener('keydown', onKeyDownDocument, true);
47
+ return () => {
48
+ document.removeEventListener('pointerdown', onPointerDownDocument, true);
49
+ document.removeEventListener('keydown', onKeyDownDocument, true);
50
+ };
51
+ }, []);
52
+ // клавиатурная навигация вокруг тригера и списка
53
+ const onKeyDown = useCallback((event) => {
54
+ // не хотим скролить дроп при использовании пробела
55
+ if (!showOptions && keyboardMatches(event.nativeEvent, [keyboardKeys.Space])) {
56
+ event.preventDefault();
57
+ return;
58
+ }
59
+ // закрытие и переброс фокуса на тригер
60
+ if (showOptions && keyboardMatch(event.nativeEvent, keyboardKeys.Escape)) {
61
+ showedByFocus.current = false;
62
+ orchestrator.yieldFocus();
63
+ toggleListVisibility();
64
+ return;
65
+ }
66
+ // TODO использовать orchestrator и отправлять фокус по стрелкам в дроп
67
+ // после закрытия пользователь решил что-то поделать опять
68
+ if (!showOptions &&
69
+ !keyboardMatches(event.nativeEvent, [keyboardKeys.Tab, keyboardKeys.Escape, keyboardKeys.Space])) {
70
+ toggleListVisibility();
71
+ }
72
+ }, [showOptions, orchestrator, toggleListVisibility]);
73
+ // открытие/закрытие тригера
74
+ const onChange = useCallback(() => {
75
+ if (disabled) {
76
+ return;
77
+ }
78
+ if (showedByFocus.current) {
79
+ showedByFocus.current = false;
80
+ return;
81
+ }
82
+ toggleListVisibility();
83
+ }, [disabled, toggleListVisibility]);
84
+ const onBlur = useCallback(() => {
85
+ // TODO тут что-то про подсказки было
86
+ if (showOptions && optionList.length === 0) {
87
+ toggleListVisibility();
88
+ }
89
+ }, [showOptions, optionList.length, toggleListVisibility]);
90
+ const onClear = useCallback(() => selectStore.clear(), [selectStore]);
91
+ const onFocus = useCallback(() => {
92
+ if (disabled || showOptions) {
93
+ return;
94
+ }
95
+ if (focusedByPointer.current) {
96
+ showedByFocus.current = true;
97
+ toggleListVisibility();
98
+ }
99
+ }, [disabled, showOptions, toggleListVisibility]);
100
+ return {
101
+ expanded: showOptions,
102
+ onBlur,
103
+ onChange,
104
+ onClear,
105
+ onKeyDown,
106
+ onFocus,
107
+ values: selectedLabels,
108
+ };
109
+ };
110
+
111
+ export { useGetTriggerRef, useSelectTrigger, useTriggerRef };
112
+ //# sourceMappingURL=useSelectTrigger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSelectTrigger.js","sources":["src/useSelectTrigger.ts"],"sourcesContent":["import { KeyboardEventHandler, RefObject, useCallback, useRef, useEffect } from 'react';\n\nimport { StaticDataFetcherItem } from '@hh.ru/magritte-common-data-provider';\nimport { keyboardKeys, keyboardMatch, keyboardMatches } from '@hh.ru/magritte-common-keyboard';\nimport { useDataProvider } from '@hh.ru/magritte-ui-new-select/internal/SelectDataProvider';\nimport { useSelectStore, useSelected } from '@hh.ru/magritte-ui-new-select/internal/SelectStateContext';\nimport { useVisibility } from '@hh.ru/magritte-ui-new-select/internal/VisibilityContext';\nimport { useFocusOrchestrator } from '@hh.ru/magritte-ui-new-select/internal/focusOrchestrator';\nimport { useRegisterSelectElementsSlot, useSelectElementsValue } from '@hh.ru/magritte-ui-new-select/internal/slots';\nimport { useSelectedLabels } from '@hh.ru/magritte-ui-new-select/internal/utils';\nimport { SelectControlledTriggerProps } from '@hh.ru/magritte-ui-new-select/types';\n\n// TODO заводил под тест, хук только получает триггер, но нерегает его в сторе\nexport const useGetTriggerRef = (): RefObject<HTMLElement> | undefined => {\n const activatorRef = useSelectElementsValue('activatorRef');\n return activatorRef;\n};\n\nexport const useTriggerRef = (): RefObject<HTMLElement> => {\n const activatorRef = useRef<HTMLElement>(null);\n useRegisterSelectElementsSlot('activatorRef', activatorRef);\n\n return activatorRef;\n};\n\nexport const useSelectTrigger = <DataType extends StaticDataFetcherItem>(\n disabled?: boolean\n): SelectControlledTriggerProps => {\n const showedByFocus = useRef(false);\n const focusedByPointer = useRef<boolean>(false);\n const { showOptions, toggleListVisibility } = useVisibility();\n const { optionList } = useDataProvider<DataType>();\n const orchestrator = useFocusOrchestrator();\n const selectStore = useSelectStore<DataType>();\n const committedValues = useSelected<DataType>(selectStore);\n const selectedLabels = useSelectedLabels(committedValues);\n\n // определяем источник фокуса - pointer или keyboard\n useEffect(() => {\n const onPointerDownDocument = () => {\n focusedByPointer.current = true;\n };\n const onKeyDownDocument = () => {\n focusedByPointer.current = false;\n };\n document.addEventListener('pointerdown', onPointerDownDocument, true);\n document.addEventListener('keydown', onKeyDownDocument, true);\n return () => {\n document.removeEventListener('pointerdown', onPointerDownDocument, true);\n document.removeEventListener('keydown', onKeyDownDocument, true);\n };\n }, []);\n\n // клавиатурная навигация вокруг тригера и списка\n const onKeyDown = useCallback<KeyboardEventHandler>(\n (event) => {\n // не хотим скролить дроп при использовании пробела\n if (!showOptions && keyboardMatches(event.nativeEvent, [keyboardKeys.Space])) {\n event.preventDefault();\n return;\n }\n\n // закрытие и переброс фокуса на тригер\n if (showOptions && keyboardMatch(event.nativeEvent, keyboardKeys.Escape)) {\n showedByFocus.current = false;\n orchestrator.yieldFocus();\n toggleListVisibility();\n return;\n }\n\n // TODO использовать orchestrator и отправлять фокус по стрелкам в дроп\n\n // после закрытия пользователь решил что-то поделать опять\n if (\n !showOptions &&\n !keyboardMatches(event.nativeEvent, [keyboardKeys.Tab, keyboardKeys.Escape, keyboardKeys.Space])\n ) {\n toggleListVisibility();\n }\n },\n [showOptions, orchestrator, toggleListVisibility]\n );\n\n // открытие/закрытие тригера\n const onChange = useCallback(() => {\n if (disabled) {\n return;\n }\n if (showedByFocus.current) {\n showedByFocus.current = false;\n return;\n }\n toggleListVisibility();\n }, [disabled, toggleListVisibility]);\n\n const onBlur = useCallback(() => {\n // TODO тут что-то про подсказки было\n if (showOptions && optionList.length === 0) {\n toggleListVisibility();\n }\n }, [showOptions, optionList.length, toggleListVisibility]);\n\n const onClear = useCallback(() => selectStore.clear(), [selectStore]);\n\n const onFocus = useCallback(() => {\n if (disabled || showOptions) {\n return;\n }\n if (focusedByPointer.current) {\n showedByFocus.current = true;\n toggleListVisibility();\n }\n }, [disabled, showOptions, toggleListVisibility]);\n\n return {\n expanded: showOptions,\n onBlur,\n onChange,\n onClear,\n onKeyDown,\n onFocus,\n values: selectedLabels,\n };\n};\n"],"names":[],"mappings":"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"}
@@ -1,17 +0,0 @@
1
- import { type ReactNode, type ReactElement, Dispatch, MutableRefObject, SetStateAction } from 'react';
2
- export type FocusStateType = 'focus' | 'focusAndSelect' | null;
3
- export interface UseNavigation {
4
- forcedState: FocusStateType;
5
- requestFocus: VoidFunction;
6
- requestFocusAndSelect: VoidFunction;
7
- clearFocusIntent: VoidFunction;
8
- committedByKeyboardRef: MutableRefObject<boolean>;
9
- }
10
- export declare const useNavigation: () => UseNavigation;
11
- interface NavigationProviderProps {
12
- children: ReactNode;
13
- forcedState: FocusStateType;
14
- setForcedState: Dispatch<SetStateAction<FocusStateType>>;
15
- }
16
- export declare const NavigationProvider: ({ children, forcedState, setForcedState, }: NavigationProviderProps) => ReactElement;
17
- export {};
@@ -1,30 +0,0 @@
1
- import { jsx } from 'react/jsx-runtime';
2
- import { createContext, useContext, useCallback, useRef, useMemo } from 'react';
3
- import { assertSelectContext } from './utils.js';
4
- import '@hh.ru/magritte-common-keyboard';
5
-
6
- const SelectNavigationContext = createContext(null);
7
- const useNavigation = () => {
8
- return assertSelectContext(useContext(SelectNavigationContext), 'useNavigation');
9
- };
10
- // фокус/клавиатура (самый нижний в цепочке — читает все что выше)
11
- const NavigationProvider = ({ children, forcedState, setForcedState, }) => {
12
- const requestFocus = useCallback(() => setForcedState('focus'), [setForcedState]);
13
- const requestFocusAndSelect = useCallback(() => setForcedState('focusAndSelect'), [setForcedState]);
14
- const clearFocusIntent = useCallback(() => setForcedState(null), [setForcedState]);
15
- // надо перебросить фокус на тригер
16
- // при выборе опции/использовании кнопок с клавиатуры
17
- // реф обрабатывается в опции/кнопках/дропе
18
- const committedByKeyboardRef = useRef(false);
19
- const contextValue = useMemo(() => ({
20
- forcedState,
21
- requestFocus,
22
- requestFocusAndSelect,
23
- clearFocusIntent,
24
- committedByKeyboardRef,
25
- }), [forcedState, requestFocus, requestFocusAndSelect, clearFocusIntent]);
26
- return jsx(SelectNavigationContext.Provider, { value: contextValue, children: children });
27
- };
28
-
29
- export { NavigationProvider, useNavigation };
30
- //# sourceMappingURL=NavigationContext.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"NavigationContext.js","sources":["src/internal/NavigationContext.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n type ReactNode,\n type ReactElement,\n Dispatch,\n useMemo,\n MutableRefObject,\n useCallback,\n useRef,\n SetStateAction,\n} from 'react';\n\nimport { assertSelectContext } from '@hh.ru/magritte-ui-new-select/internal/utils';\n\nexport type FocusStateType = 'focus' | 'focusAndSelect' | null;\n\nexport interface UseNavigation {\n forcedState: FocusStateType;\n requestFocus: VoidFunction;\n requestFocusAndSelect: VoidFunction;\n clearFocusIntent: VoidFunction;\n committedByKeyboardRef: MutableRefObject<boolean>;\n}\n\nconst SelectNavigationContext = createContext<UseNavigation | null>(null);\n\nexport const useNavigation = (): UseNavigation => {\n return assertSelectContext(useContext(SelectNavigationContext), 'useNavigation');\n};\n\ninterface NavigationProviderProps {\n children: ReactNode;\n forcedState: FocusStateType;\n setForcedState: Dispatch<SetStateAction<FocusStateType>>;\n}\n\n// фокус/клавиатура (самый нижний в цепочке — читает все что выше)\nexport const NavigationProvider = ({\n children,\n forcedState,\n setForcedState,\n}: NavigationProviderProps): ReactElement => {\n const requestFocus = useCallback(() => setForcedState('focus'), [setForcedState]);\n const requestFocusAndSelect = useCallback(() => setForcedState('focusAndSelect'), [setForcedState]);\n const clearFocusIntent = useCallback(() => setForcedState(null), [setForcedState]);\n\n // надо перебросить фокус на тригер\n // при выборе опции/использовании кнопок с клавиатуры\n // реф обрабатывается в опции/кнопках/дропе\n const committedByKeyboardRef = useRef(false);\n\n const contextValue = useMemo(\n () => ({\n forcedState,\n requestFocus,\n requestFocusAndSelect,\n clearFocusIntent,\n committedByKeyboardRef,\n }),\n [forcedState, requestFocus, requestFocusAndSelect, clearFocusIntent]\n );\n return <SelectNavigationContext.Provider value={contextValue}>{children}</SelectNavigationContext.Provider>;\n};\n"],"names":["_jsx"],"mappings":";;;;;AAyBA,MAAM,uBAAuB,GAAG,aAAa,CAAuB,IAAI,CAAC,CAAC;AAEnE,MAAM,aAAa,GAAG,MAAoB;IAC7C,OAAO,mBAAmB,CAAC,UAAU,CAAC,uBAAuB,CAAC,EAAE,eAAe,CAAC,CAAC;AACrF,EAAE;AAQF;AACO,MAAM,kBAAkB,GAAG,CAAC,EAC/B,QAAQ,EACR,WAAW,EACX,cAAc,GACQ,KAAkB;AACxC,IAAA,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;AAClF,IAAA,MAAM,qBAAqB,GAAG,WAAW,CAAC,MAAM,cAAc,CAAC,gBAAgB,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;AACpG,IAAA,MAAM,gBAAgB,GAAG,WAAW,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC;;;;AAKnF,IAAA,MAAM,sBAAsB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;AAE7C,IAAA,MAAM,YAAY,GAAG,OAAO,CACxB,OAAO;QACH,WAAW;QACX,YAAY;QACZ,qBAAqB;QACrB,gBAAgB;QAChB,sBAAsB;KACzB,CAAC,EACF,CAAC,WAAW,EAAE,YAAY,EAAE,qBAAqB,EAAE,gBAAgB,CAAC,CACvE,CAAC;IACF,OAAOA,GAAA,CAAC,uBAAuB,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,YAAY,EAAA,QAAA,EAAG,QAAQ,EAAA,CAAoC,CAAC;AAChH;;;;"}
@@ -1,8 +0,0 @@
1
- import { StaticDataFetcherItem, DataProvider as DataProviderType } from '@hh.ru/magritte-common-data-provider';
2
- import { OnOptionsChangeCallback, SelectOption, SearchValue, SetSearchValue } from '@hh.ru/magritte-ui-new-select/types';
3
- export interface UseSelectSearch<DataType extends StaticDataFetcherItem> extends SearchValue, SetSearchValue {
4
- internalError?: boolean;
5
- internalLoading?: boolean;
6
- optionList: SelectOption<DataType>[];
7
- }
8
- export declare const useSearch: <DataType extends StaticDataFetcherItem>(dataProvider: DataProviderType<DataType>, onOptionsChangeExternal?: OnOptionsChangeCallback<DataType>) => UseSelectSearch<DataType>;
@@ -1 +0,0 @@
1
- {"version":3,"file":"useSearch.js","sources":["src/internal/useSearch.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n StaticDataFetcherItem,\n DataProvider as DataProviderType,\n DataProviderError,\n} from '@hh.ru/magritte-common-data-provider';\nimport { DataProviderRequest } from '@hh.ru/magritte-common-data-provider/types';\nimport { useVisibility } from '@hh.ru/magritte-ui-new-select/internal/VisibilityContext';\nimport {\n OnOptionsChangeCallback,\n SelectOption,\n SearchValue,\n SetSearchValue,\n} from '@hh.ru/magritte-ui-new-select/types';\n\nconst EMPTY_OPTION_LIST: never[] = [];\n\nexport interface UseSelectSearch<DataType extends StaticDataFetcherItem> extends SearchValue, SetSearchValue {\n internalError?: boolean;\n internalLoading?: boolean;\n optionList: SelectOption<DataType>[];\n}\n\nexport const useSearch = <DataType extends StaticDataFetcherItem>(\n dataProvider: DataProviderType<DataType>,\n onOptionsChangeExternal?: OnOptionsChangeCallback<DataType>\n): UseSelectSearch<DataType> => {\n const { showOptions } = useVisibility();\n const [searchValue, setSearchValue] = useState('');\n const [optionList, setOptionList] = useState<SelectOption<DataType>[]>(EMPTY_OPTION_LIST);\n const [internalError, setInternalError] = useState(false);\n const [optionsLoading, setOptionsLoading] = useState(false);\n const currentRequestRef = useRef<DataProviderRequest>();\n\n // TODO loading/inProgress реализовать в отдельном компоненте\n // const loadingTimeoutRef = useRef<number>(0);\n // const inProgressTimeoutRef = useRef<number>(0);\n // const [searchInProgress, setSearchInProgress] = useState(false);\n\n const updateOptionsFromProvider = useCallback(\n (text: string) => {\n if (!dataProvider) {\n return;\n }\n setInternalError(false);\n currentRequestRef.current?.cancel();\n const request = dataProvider(text);\n currentRequestRef.current = request;\n request\n .then((result) => {\n currentRequestRef.current = undefined;\n const newOptions: SelectOption<DataType>[] = [];\n result.forEach((section) => {\n if (section.type === 'delimiter') {\n newOptions.push({\n data: { text: section.text, value: section.text } as DataType,\n type: 'delimiter',\n });\n }\n if (section.type === 'cells') {\n section.items.forEach((item) => {\n newOptions.push({\n data: item.data ? item.data : ({ text: item.value, value: item.value } as DataType),\n disabled: item.disabled,\n });\n });\n }\n });\n\n const hasRealOptions = newOptions.some((item) => item.type !== 'delimiter');\n setOptionList(hasRealOptions ? newOptions : EMPTY_OPTION_LIST);\n })\n .catch((error) => {\n // включаем error state если это НЕ ошибка\n // вызванная `minCharsCount` или отменненым запросом\n if (!(error instanceof DataProviderError)) {\n setInternalError(true);\n setOptionList(EMPTY_OPTION_LIST);\n }\n })\n .finally(() => {\n setOptionsLoading(false);\n });\n },\n [dataProvider]\n );\n\n // уведомляем клиента об изменении списка опций вне фазы рендера (только при реальной смене ссылки)\n const notifiedListRef = useRef(optionList);\n useEffect(() => {\n if (notifiedListRef.current === optionList) {\n return;\n }\n notifiedListRef.current = optionList;\n onOptionsChangeExternal?.(optionList);\n }, [optionList, onOptionsChangeExternal]);\n\n // обрабатываем обновление провайдера из клиента\n useEffect(() => {\n updateOptionsFromProvider(searchValue);\n // eslint-disable-next-line disable-autofix/react-hooks/exhaustive-deps\n }, [dataProvider]);\n\n // TODO убрать в тригер/пикер\n // сбрасываем select при закрытии компонента\n /* useEffect(() => {\n if (!showOptions) {\n setSearchValue('');\n updateOptionsFromProvider('');\n }\n // eslint-disable-next-line disable-autofix/react-hooks/exhaustive-deps\n }, [showOptions]);\n\n // обрабатываем поиск\n\n useEffect(() => {\n updateOptionsFromProvider(searchValue);\n // eslint-disable-next-line disable-autofix/react-hooks/exhaustive-deps\n }, [searchValue]);*/\n\n // после анмаунта надо отменить все запросы\n useEffect(\n () => () => {\n currentRequestRef.current?.cancel();\n },\n []\n );\n\n return useMemo(\n () => ({\n internalError,\n internalLoading: optionsLoading && showOptions,\n optionList,\n searchValue,\n setSearchValue,\n }),\n [internalError, optionList, optionsLoading, searchValue, setSearchValue, showOptions]\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,16 +0,0 @@
1
- import { StaticDataFetcherItem } from '@hh.ru/magritte-common-data-provider';
2
- import { ValueTypeHelper, OnChangeAction } from '@hh.ru/magritte-ui-new-select/types';
3
- export declare const getToggledValues: <DataType extends StaticDataFetcherItem>(state: DataType[], value: DataType, needToPut: boolean, multiple?: boolean) => DataType[];
4
- export interface UseSelectState<MultipleType extends boolean, DataType extends StaticDataFetcherItem> {
5
- clearSelectedValues: VoidFunction;
6
- clearSelectedValuesByTrigger: VoidFunction;
7
- committedValues: ValueTypeHelper<MultipleType, DataType>;
8
- setInitialValues: VoidFunction;
9
- setInitialValuesOnClosePicker: VoidFunction;
10
- values: ValueTypeHelper<MultipleType, DataType>;
11
- valuesLength: number;
12
- hasUnsavedChanges: boolean;
13
- onChange: OnChangeAction<DataType>;
14
- setSelectedValues: VoidFunction;
15
- }
16
- export declare const useSelectState: <DataType extends StaticDataFetcherItem, MultipleType extends boolean>(value: DataType[] | DataType, onChangeExternal?: (value: ValueTypeHelper<MultipleType, DataType>) => void, onSelectOption?: (values: DataType[]) => void) => UseSelectState<MultipleType, DataType>;
@@ -1,145 +0,0 @@
1
- import { useReducer, useRef, useState, useCallback, useEffect, useMemo } from 'react';
2
- import { useSelectConfig } from './ConfigContext.js';
3
- import { useVisibility } from './VisibilityContext.js';
4
- import { isArraysEquals } from './utils.js';
5
- import 'react/jsx-runtime';
6
- import '@hh.ru/magritte-common-keyboard';
7
-
8
- const TOGGLE = 'TOGGLE';
9
- const SET = 'SET';
10
- const SYNC = 'SYNC';
11
- const CLEAR = 'CLEAR';
12
- const getToggledValues = (state, value, needToPut, multiple) => {
13
- if (!multiple) {
14
- return [value];
15
- }
16
- return needToPut ? [...state, value] : state.filter((item) => item.value !== value.value);
17
- };
18
- const reducer = (state, action) => {
19
- switch (action.type) {
20
- case TOGGLE:
21
- return getToggledValues(state, action.value, action.needToPut, action.multiple);
22
- case SET:
23
- return [...action.payload];
24
- case SYNC:
25
- // синхронизация из внешнего value
26
- return isArraysEquals(action.payload, state) ? state : [...action.payload];
27
- case CLEAR:
28
- return [];
29
- default:
30
- return state;
31
- }
32
- };
33
- const useSelectState = (value, onChangeExternal, onSelectOption) => {
34
- const { showOptions } = useVisibility();
35
- const { multiple, commitModel } = useSelectConfig();
36
- const valuesAsArray = Array.isArray(value) ? value : [value];
37
- const [state, dispatch] = useReducer((reducer), valuesAsArray);
38
- /**
39
- * внешние снапшоты значений
40
- * committed - отдано наружу (есть гард onChange)
41
- * openBaseline - черновик на момент открытия пикера
42
- */
43
- const snapshotsRef = useRef({ committed: valuesAsArray, openBaseline: [] });
44
- // реактивная копия committed для отрисовки (триггер показывает применённое, а не черновик)
45
- const [committed, setCommitted] = useState(valuesAsArray);
46
- const mountBaselineRef = useRef(valuesAsArray);
47
- // эмит и гард
48
- const commit = useCallback((values, emit = true) => {
49
- if (emit) {
50
- const hasUnsavedChanges = !isArraysEquals(snapshotsRef.current.committed.map((item) => item.value), values.map((item) => item.value));
51
- if (hasUnsavedChanges) {
52
- onChangeExternal?.((multiple ? values : values[0]));
53
- }
54
- }
55
- snapshotsRef.current.committed = values;
56
- setCommitted((prev) => isArraysEquals(prev.map((item) => item.value), values.map((item) => item.value))
57
- ? prev
58
- : values);
59
- }, [multiple, onChangeExternal]);
60
- // снимок черновика на открытии пикера
61
- useEffect(() => {
62
- if (showOptions) {
63
- snapshotsRef.current.openBaseline = state;
64
- }
65
- // eslint-disable-next-line disable-autofix/react-hooks/exhaustive-deps
66
- }, [showOptions]);
67
- // синхронизация с внешним value
68
- useEffect(() => {
69
- const newValues = Array.isArray(value) ? value : [value];
70
- dispatch({ type: SYNC, payload: newValues });
71
- // без эмита, так как внешний стейт уже все знает
72
- commit(newValues, false);
73
- }, [commit, value]);
74
- // используется для креста на тригере
75
- const clearSelectedValuesByTrigger = useCallback(() => {
76
- dispatch({ type: CLEAR });
77
- commit([]);
78
- }, [commit]);
79
- // для кнопки очистки в пикере
80
- const clearSelectedValues = useCallback((applyOnClear = true) => {
81
- dispatch({ type: CLEAR });
82
- if (applyOnClear) {
83
- commit([]);
84
- }
85
- }, [commit]);
86
- // сброс стейта в пикере на кнопке сброса
87
- const setInitialValues = useCallback((applyOnClear = true) => {
88
- dispatch({ type: SET, payload: mountBaselineRef.current });
89
- if (applyOnClear) {
90
- commit(mountBaselineRef.current);
91
- }
92
- }, [commit]);
93
- // откат черновика при закрытии пикера
94
- const setInitialValuesOnClosePicker = useCallback(() => {
95
- const { openBaseline, committed } = snapshotsRef.current;
96
- // если за сессию открытия ничего не закоммитили => возвращаем черновик к бейзлайну открытия
97
- const nothingCommittedSinceOpen = isArraysEquals(openBaseline.map((item) => item.value), committed.map((item) => item.value));
98
- if (nothingCommittedSinceOpen) {
99
- dispatch({ type: SET, payload: openBaseline });
100
- }
101
- }, []);
102
- const onChange = useCallback((value, needToPut) => {
103
- // эффектам нужно новое значение до применения стейта
104
- const newValue = getToggledValues(state, value, needToPut, multiple);
105
- dispatch({ type: TOGGLE, value, needToPut, multiple });
106
- onSelectOption?.(newValue);
107
- if (commitModel === 'instant') {
108
- commit(newValue);
109
- }
110
- }, [commitModel, multiple, state, commit, onSelectOption]);
111
- // применение черновик
112
- const setSelectedValues = useCallback(() => {
113
- commit(state);
114
- }, [commit, state]);
115
- // флаг для алерта при несохраненных изменениях
116
- const hasUnsavedChanges = !isArraysEquals(snapshotsRef.current.committed.map((item) => item.value), state.map((item) => item.value));
117
- const values = (multiple ? state : state[0]);
118
- const committedValues = (multiple ? committed : committed[0]);
119
- return useMemo(() => ({
120
- clearSelectedValues,
121
- clearSelectedValuesByTrigger,
122
- committedValues,
123
- onChange,
124
- setInitialValues,
125
- setInitialValuesOnClosePicker,
126
- setSelectedValues,
127
- valuesLength: state.length,
128
- values,
129
- hasUnsavedChanges,
130
- }), [
131
- clearSelectedValues,
132
- clearSelectedValuesByTrigger,
133
- committedValues,
134
- onChange,
135
- setInitialValues,
136
- setInitialValuesOnClosePicker,
137
- setSelectedValues,
138
- state.length,
139
- values,
140
- hasUnsavedChanges,
141
- ]);
142
- };
143
-
144
- export { getToggledValues, useSelectState };
145
- //# sourceMappingURL=useSelectState.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useSelectState.js","sources":["src/internal/useSelectState.ts"],"sourcesContent":["import { useCallback, useReducer, useEffect, useRef, useMemo, useState } from 'react';\n\nimport { StaticDataFetcherItem } from '@hh.ru/magritte-common-data-provider';\nimport { useSelectConfig } from '@hh.ru/magritte-ui-new-select/internal/ConfigContext';\nimport { useVisibility } from '@hh.ru/magritte-ui-new-select/internal/VisibilityContext';\nimport { isArraysEquals } from '@hh.ru/magritte-ui-new-select/internal/utils';\nimport { ValueTypeHelper, OnChangeAction } from '@hh.ru/magritte-ui-new-select/types';\n\nconst TOGGLE = 'TOGGLE';\nconst SET = 'SET';\nconst SYNC = 'SYNC';\nconst CLEAR = 'CLEAR';\n\ntype SelectStateAction<DataType extends StaticDataFetcherItem> =\n | { type: typeof TOGGLE; value: DataType; needToPut: boolean; multiple?: boolean }\n | { type: typeof SET; payload: DataType[] }\n | { type: typeof SYNC; payload: DataType[] }\n | { type: typeof CLEAR };\n\nexport const getToggledValues = <DataType extends StaticDataFetcherItem>(\n state: DataType[],\n value: DataType,\n needToPut: boolean,\n multiple?: boolean\n): DataType[] => {\n if (!multiple) {\n return [value];\n }\n return needToPut ? [...state, value] : state.filter((item) => item.value !== value.value);\n};\n\nconst reducer = <DataType extends StaticDataFetcherItem>(\n state: DataType[],\n action: SelectStateAction<DataType>\n): DataType[] => {\n switch (action.type) {\n case TOGGLE:\n return getToggledValues(state, action.value, action.needToPut, action.multiple);\n case SET:\n return [...action.payload];\n case SYNC:\n // синхронизация из внешнего value\n return isArraysEquals(action.payload, state) ? state : [...action.payload];\n case CLEAR:\n return [];\n default:\n return state;\n }\n};\n\nexport interface UseSelectState<MultipleType extends boolean, DataType extends StaticDataFetcherItem> {\n clearSelectedValues: VoidFunction;\n clearSelectedValuesByTrigger: VoidFunction;\n committedValues: ValueTypeHelper<MultipleType, DataType>;\n setInitialValues: VoidFunction;\n setInitialValuesOnClosePicker: VoidFunction;\n values: ValueTypeHelper<MultipleType, DataType>;\n valuesLength: number;\n hasUnsavedChanges: boolean;\n onChange: OnChangeAction<DataType>;\n setSelectedValues: VoidFunction;\n}\n\nexport const useSelectState = <DataType extends StaticDataFetcherItem, MultipleType extends boolean>(\n value: DataType[] | DataType,\n onChangeExternal?: (value: ValueTypeHelper<MultipleType, DataType>) => void,\n onSelectOption?: (values: DataType[]) => void\n): UseSelectState<MultipleType, DataType> => {\n const { showOptions } = useVisibility();\n const { multiple, commitModel } = useSelectConfig();\n const valuesAsArray = Array.isArray(value) ? value : [value];\n const [state, dispatch] = useReducer(reducer<DataType>, valuesAsArray);\n\n /**\n * внешние снапшоты значений\n * committed - отдано наружу (есть гард onChange)\n * openBaseline - черновик на момент открытия пикера\n */\n const snapshotsRef = useRef({ committed: valuesAsArray, openBaseline: [] as DataType[] });\n // реактивная копия committed для отрисовки (триггер показывает применённое, а не черновик)\n const [committed, setCommitted] = useState(valuesAsArray);\n const mountBaselineRef = useRef(valuesAsArray);\n\n // эмит и гард\n const commit = useCallback(\n (values: DataType[], emit = true) => {\n if (emit) {\n const hasUnsavedChanges = !isArraysEquals<string>(\n snapshotsRef.current.committed.map((item) => item.value),\n values.map((item) => item.value)\n );\n if (hasUnsavedChanges) {\n onChangeExternal?.((multiple ? values : values[0]) as ValueTypeHelper<MultipleType, DataType>);\n }\n }\n snapshotsRef.current.committed = values;\n setCommitted((prev) =>\n isArraysEquals<string>(\n prev.map((item) => item.value),\n values.map((item) => item.value)\n )\n ? prev\n : values\n );\n },\n [multiple, onChangeExternal]\n );\n\n // снимок черновика на открытии пикера\n useEffect(() => {\n if (showOptions) {\n snapshotsRef.current.openBaseline = state;\n }\n // eslint-disable-next-line disable-autofix/react-hooks/exhaustive-deps\n }, [showOptions]);\n\n // синхронизация с внешним value\n useEffect(() => {\n const newValues = Array.isArray(value) ? value : [value];\n dispatch({ type: SYNC, payload: newValues });\n // без эмита, так как внешний стейт уже все знает\n commit(newValues, false);\n }, [commit, value]);\n\n // используется для креста на тригере\n const clearSelectedValuesByTrigger = useCallback(() => {\n dispatch({ type: CLEAR });\n commit([]);\n }, [commit]);\n\n // для кнопки очистки в пикере\n const clearSelectedValues = useCallback(\n (applyOnClear = true) => {\n dispatch({ type: CLEAR });\n if (applyOnClear) {\n commit([]);\n }\n },\n [commit]\n );\n\n // сброс стейта в пикере на кнопке сброса\n const setInitialValues = useCallback(\n (applyOnClear = true) => {\n dispatch({ type: SET, payload: mountBaselineRef.current });\n if (applyOnClear) {\n commit(mountBaselineRef.current);\n }\n },\n [commit]\n );\n\n // откат черновика при закрытии пикера\n const setInitialValuesOnClosePicker = useCallback(() => {\n const { openBaseline, committed } = snapshotsRef.current;\n // если за сессию открытия ничего не закоммитили => возвращаем черновик к бейзлайну открытия\n const nothingCommittedSinceOpen = isArraysEquals<string>(\n openBaseline.map((item) => item.value),\n committed.map((item) => item.value)\n );\n if (nothingCommittedSinceOpen) {\n dispatch({ type: SET, payload: openBaseline });\n }\n }, []);\n\n const onChange = useCallback<UseSelectState<MultipleType, DataType>['onChange']>(\n (value, needToPut) => {\n // эффектам нужно новое значение до применения стейта\n const newValue = getToggledValues(state, value, needToPut, multiple);\n dispatch({ type: TOGGLE, value, needToPut, multiple });\n onSelectOption?.(newValue);\n if (commitModel === 'instant') {\n commit(newValue);\n }\n },\n [commitModel, multiple, state, commit, onSelectOption]\n );\n\n // применение черновик\n const setSelectedValues = useCallback(() => {\n commit(state);\n }, [commit, state]);\n\n // флаг для алерта при несохраненных изменениях\n const hasUnsavedChanges = !isArraysEquals<string>(\n snapshotsRef.current.committed.map((item) => item.value),\n state.map((item) => item.value)\n );\n\n const values = (multiple ? state : state[0]) as ValueTypeHelper<MultipleType, DataType>;\n const committedValues = (multiple ? committed : committed[0]) as ValueTypeHelper<MultipleType, DataType>;\n return useMemo<UseSelectState<MultipleType, DataType>>(\n () => ({\n clearSelectedValues,\n clearSelectedValuesByTrigger,\n committedValues,\n onChange,\n setInitialValues,\n setInitialValuesOnClosePicker,\n setSelectedValues,\n valuesLength: state.length,\n values,\n hasUnsavedChanges,\n }),\n [\n clearSelectedValues,\n clearSelectedValuesByTrigger,\n committedValues,\n onChange,\n setInitialValues,\n setInitialValuesOnClosePicker,\n setSelectedValues,\n state.length,\n values,\n hasUnsavedChanges,\n ]\n );\n};\n"],"names":[],"mappings":"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"}