@ozen-ui/kit 0.33.0 → 0.34.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 (79) hide show
  1. package/Autocomplete/package.json +5 -0
  2. package/__inner__/cjs/components/Autocomplete/Autocomplete.css +46 -0
  3. package/__inner__/cjs/components/Autocomplete/Autocomplete.d.ts +4 -0
  4. package/__inner__/cjs/components/Autocomplete/Autocomplete.js +202 -0
  5. package/__inner__/cjs/components/Autocomplete/components/AutocompleteLoading/AutocompleteLoading.d.ts +6 -0
  6. package/__inner__/cjs/components/Autocomplete/components/AutocompleteLoading/AutocompleteLoading.js +23 -0
  7. package/__inner__/cjs/components/Autocomplete/components/AutocompleteLoading/index.d.ts +1 -0
  8. package/__inner__/cjs/components/Autocomplete/components/AutocompleteLoading/index.js +4 -0
  9. package/__inner__/cjs/components/Autocomplete/components/AutocompleteNoOptions/AutocompleteNoOptions.d.ts +6 -0
  10. package/__inner__/cjs/components/Autocomplete/components/AutocompleteNoOptions/AutocompleteNoOptions.js +17 -0
  11. package/__inner__/cjs/components/Autocomplete/components/AutocompleteNoOptions/index.d.ts +1 -0
  12. package/__inner__/cjs/components/Autocomplete/components/AutocompleteNoOptions/index.js +4 -0
  13. package/__inner__/cjs/components/Autocomplete/components/AutocompleteRenderRight/AutocompleteRenderRight.d.ts +10 -0
  14. package/__inner__/cjs/components/Autocomplete/components/AutocompleteRenderRight/AutocompleteRenderRight.js +26 -0
  15. package/__inner__/cjs/components/Autocomplete/components/AutocompleteRenderRight/index.d.ts +1 -0
  16. package/__inner__/cjs/components/Autocomplete/components/AutocompleteRenderRight/index.js +4 -0
  17. package/__inner__/cjs/components/Autocomplete/components/index.d.ts +3 -0
  18. package/__inner__/cjs/components/Autocomplete/components/index.js +6 -0
  19. package/__inner__/cjs/components/Autocomplete/constants.d.ts +10 -0
  20. package/__inner__/cjs/components/Autocomplete/constants.js +13 -0
  21. package/__inner__/cjs/components/Autocomplete/helper.d.ts +166 -0
  22. package/__inner__/cjs/components/Autocomplete/helper.js +14 -0
  23. package/__inner__/cjs/components/Autocomplete/index.d.ts +2 -0
  24. package/__inner__/cjs/components/Autocomplete/index.js +5 -0
  25. package/__inner__/cjs/components/Autocomplete/types.d.ts +105 -0
  26. package/__inner__/cjs/components/Autocomplete/types.js +2 -0
  27. package/__inner__/cjs/components/DataList/helpers/useDataListNavigation.js +4 -12
  28. package/__inner__/cjs/components/List/List.css +5 -0
  29. package/__inner__/cjs/components/List/List.js +2 -2
  30. package/__inner__/cjs/components/List/constants.d.ts +1 -0
  31. package/__inner__/cjs/components/List/constants.js +2 -1
  32. package/__inner__/cjs/components/List/types.d.ts +2 -0
  33. package/__inner__/cjs/components/ThemeProvider/types.d.ts +2 -0
  34. package/__inner__/cjs/hooks/useEventListener/useEventListener.js +2 -4
  35. package/__inner__/cjs/hooks/useMutableRef/index.d.ts +1 -0
  36. package/__inner__/cjs/hooks/useMutableRef/index.js +4 -0
  37. package/__inner__/cjs/hooks/useMutableRef/useMutableRef.d.ts +2 -0
  38. package/__inner__/cjs/hooks/useMutableRef/useMutableRef.js +10 -0
  39. package/__inner__/cjs/locale/locale.js +21 -0
  40. package/__inner__/esm/components/Autocomplete/Autocomplete.css +46 -0
  41. package/__inner__/esm/components/Autocomplete/Autocomplete.d.ts +4 -0
  42. package/__inner__/esm/components/Autocomplete/Autocomplete.js +199 -0
  43. package/__inner__/esm/components/Autocomplete/components/AutocompleteLoading/AutocompleteLoading.d.ts +6 -0
  44. package/__inner__/esm/components/Autocomplete/components/AutocompleteLoading/AutocompleteLoading.js +18 -0
  45. package/__inner__/esm/components/Autocomplete/components/AutocompleteLoading/index.d.ts +1 -0
  46. package/__inner__/esm/components/Autocomplete/components/AutocompleteLoading/index.js +1 -0
  47. package/__inner__/esm/components/Autocomplete/components/AutocompleteNoOptions/AutocompleteNoOptions.d.ts +6 -0
  48. package/__inner__/esm/components/Autocomplete/components/AutocompleteNoOptions/AutocompleteNoOptions.js +12 -0
  49. package/__inner__/esm/components/Autocomplete/components/AutocompleteNoOptions/index.d.ts +1 -0
  50. package/__inner__/esm/components/Autocomplete/components/AutocompleteNoOptions/index.js +1 -0
  51. package/__inner__/esm/components/Autocomplete/components/AutocompleteRenderRight/AutocompleteRenderRight.d.ts +10 -0
  52. package/__inner__/esm/components/Autocomplete/components/AutocompleteRenderRight/AutocompleteRenderRight.js +22 -0
  53. package/__inner__/esm/components/Autocomplete/components/AutocompleteRenderRight/index.d.ts +1 -0
  54. package/__inner__/esm/components/Autocomplete/components/AutocompleteRenderRight/index.js +1 -0
  55. package/__inner__/esm/components/Autocomplete/components/index.d.ts +3 -0
  56. package/__inner__/esm/components/Autocomplete/components/index.js +3 -0
  57. package/__inner__/esm/components/Autocomplete/constants.d.ts +10 -0
  58. package/__inner__/esm/components/Autocomplete/constants.js +10 -0
  59. package/__inner__/esm/components/Autocomplete/helper.d.ts +166 -0
  60. package/__inner__/esm/components/Autocomplete/helper.js +7 -0
  61. package/__inner__/esm/components/Autocomplete/index.d.ts +2 -0
  62. package/__inner__/esm/components/Autocomplete/index.js +2 -0
  63. package/__inner__/esm/components/Autocomplete/types.d.ts +105 -0
  64. package/__inner__/esm/components/Autocomplete/types.js +1 -0
  65. package/__inner__/esm/components/DataList/helpers/useDataListNavigation.js +5 -13
  66. package/__inner__/esm/components/List/List.css +5 -0
  67. package/__inner__/esm/components/List/List.js +3 -3
  68. package/__inner__/esm/components/List/constants.d.ts +1 -0
  69. package/__inner__/esm/components/List/constants.js +1 -0
  70. package/__inner__/esm/components/List/types.d.ts +2 -0
  71. package/__inner__/esm/components/ThemeProvider/types.d.ts +2 -0
  72. package/__inner__/esm/hooks/useEventListener/useEventListener.js +3 -5
  73. package/__inner__/esm/hooks/useMutableRef/index.d.ts +1 -0
  74. package/__inner__/esm/hooks/useMutableRef/index.js +1 -0
  75. package/__inner__/esm/hooks/useMutableRef/useMutableRef.d.ts +2 -0
  76. package/__inner__/esm/hooks/useMutableRef/useMutableRef.js +6 -0
  77. package/__inner__/esm/locale/locale.js +21 -0
  78. package/package.json +1 -1
  79. package/useMutableRef/package.json +5 -0
@@ -0,0 +1,105 @@
1
+ import type { SyntheticEvent, ChangeEvent, ReactElement, ReactNode } from 'react';
2
+ import type { FormElementSizeVariant } from '../../types/FormElementSizeVariant';
3
+ import type { DataListBaseProps } from '../DataList';
4
+ import type { InputProps } from '../Input';
5
+ export type AutocompleteRenderOptionProps<OPTION> = {
6
+ option: OPTION;
7
+ selected: boolean;
8
+ };
9
+ export type AutocompletePropValue<OPTION> = OPTION | null | undefined;
10
+ export type AutocompletePropGetOptionLabel<OPTION> = (option: OPTION) => string;
11
+ export type AutocompletePropGetOptionKey<OPTION> = (option: OPTION) => string | number;
12
+ export type AutocompletePropRenderValue<OPTION> = (value: OPTION) => ReactNode | null;
13
+ export type AutocompletePropGetOptionDisabled<OPTION> = (option: OPTION) => boolean | undefined;
14
+ export type AutocompletePropRenderOption<OPTION> = (props: AutocompleteRenderOptionProps<OPTION>) => ReactElement | null;
15
+ export type AutocompleteDefaultOption = {
16
+ id: string | number;
17
+ label: string;
18
+ disabled?: boolean;
19
+ };
20
+ export type AutocompleteSearchFunction<OPTION> = (options: OPTION[], searchValue: string) => OPTION[];
21
+ export type AutocompleteRenderInput = (props: InputProps) => ReactNode;
22
+ type AutocompleteOpenControlledProps = {
23
+ /** Текущее состояние списка. Если `true`, список отображается. */
24
+ open?: boolean;
25
+ /** Состояние открытие по умолчанию (неконтролируемый компонент) */
26
+ defaultOpen?: never;
27
+ };
28
+ type AutocompleteOpenUncontrolledProps = {
29
+ /** Текущее состояние списка. Если `true`, список отображается. */
30
+ open?: never;
31
+ /** Состояние открытие по умолчанию (неконтролируемый компонент) */
32
+ defaultOpen?: boolean;
33
+ };
34
+ type AutocompleteInputProps = Pick<InputProps, 'placeholder' | 'autoFocus' | 'fullWidth' | 'disabled' | 'label' | 'required' | 'style' | 'error' | 'hint' | 'renderLeft' | 'className' | 'inputProps' | 'onKeyDown'>;
35
+ type AutocompleteDataListProps = Partial<Omit<DataListBaseProps, 'onClose' | 'open' | 'anchorRef' | 'multiple' | 'selected' | 'onSelect'>>;
36
+ export type AutocompleteProps<OPTION = AutocompleteDefaultOption> = {
37
+ /** Список вариантов выбора (опции) */
38
+ options: OPTION[];
39
+ /** Размер */
40
+ size?: FormElementSizeVariant;
41
+ /** Выбранное значение опции */
42
+ value?: AutocompletePropValue<OPTION>;
43
+ /** Выбранное значение опции по умолчанию */
44
+ defaultValue?: AutocompletePropValue<OPTION>;
45
+ /** Функция обратного вызова, которая будет вызвана при выборе значения */
46
+ onChange?: (e: SyntheticEvent | KeyboardEvent, value: OPTION | null) => void;
47
+ /** Введённое значение в текстовом поле */
48
+ inputValue?: string;
49
+ /** Функция обратного вызова, которая будет вызвана при вводе значения с клавиатуры */
50
+ onInputChange?: (e: ChangeEvent<HTMLInputElement> | null, value: string) => void;
51
+ /** Функция для кастомизации текстового поля */
52
+ renderInput?: AutocompleteRenderInput;
53
+ /** Функция для кастомизации отображения опции */
54
+ renderOption?: AutocompletePropRenderOption<OPTION>;
55
+ /** Функция для определения названия элемента */
56
+ getOptionLabel?: AutocompletePropGetOptionLabel<OPTION>;
57
+ /** Функция для определения уникального ключа элемента */
58
+ getOptionKey?: AutocompletePropGetOptionKey<OPTION>;
59
+ /** Функция для определения заблокированного элемента */
60
+ getOptionDisabled?: AutocompletePropGetOptionDisabled<OPTION>;
61
+ /** Если {true} не закрывает выпадающий список при выборе опции */
62
+ disableCloseOnSelect?: boolean;
63
+ /** Если {true} позволяет вводить кастомное значение в текстовом поле */
64
+ allowCustomValue?: boolean;
65
+ /** Если {true} отображает статус загрузки (при условии отсутствующих опций) */
66
+ loading?: boolean;
67
+ /** Текст компонента при отсутствующих опций */
68
+ noOptionsText?: ReactNode;
69
+ /** Текст для кнопки очистки поля */
70
+ clearText?: string;
71
+ /** Текст для кнопки открытия выпадающего списка */
72
+ openText?: string;
73
+ /** Текст для кнопки закрытия выпадающего списка */
74
+ closeText?: string;
75
+ /** Текст компонента в состоянии загрузки */
76
+ loadingText?: ReactNode;
77
+ /** Функция обратного вызова, которая будет вызвана когда компонент запрашивает закрытие */
78
+ onClose?: () => void;
79
+ /** Функция обратного вызова, которая будет вызвана когда компонент запрашивает открытие */
80
+ onOpen?: () => void;
81
+ /** Если {true}, то не отображает кнопку закрытия */
82
+ disableClearButton?: boolean;
83
+ /** Функция поиска */
84
+ searchFunction?: AutocompleteSearchFunction<OPTION>;
85
+ /** Если {true} не показывает список с отсутствующими опциями */
86
+ disableShowEmptyOptionsList?: boolean;
87
+ /** Если {true} скрывает кнопку раскрытия/скрытия списка */
88
+ disableShowChevron?: boolean;
89
+ /** Свойства компонента DataList */
90
+ dataListProps?: AutocompleteDataListProps;
91
+ } & AutocompleteInputProps & (AutocompleteOpenControlledProps | AutocompleteOpenUncontrolledProps) & (OPTION extends {
92
+ label: AutocompleteDefaultOption['label'];
93
+ } ? Record<string, unknown> : {
94
+ getOptionLabel?: AutocompletePropGetOptionLabel<OPTION>;
95
+ }) & (OPTION extends {
96
+ id: AutocompleteDefaultOption['id'];
97
+ } ? Record<string, unknown> : {
98
+ getOptionKey?: AutocompletePropGetOptionKey<OPTION>;
99
+ }) & (OPTION extends {
100
+ id: AutocompleteDefaultOption['disabled'];
101
+ } ? Record<string, unknown> : {
102
+ getOptionDisabled?: AutocompletePropGetOptionKey<OPTION>;
103
+ });
104
+ export type AutocompleteComponent = <OPTION = AutocompleteDefaultOption>(props: AutocompleteProps<OPTION>) => ReactElement | null;
105
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useDataListNavigation = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var react_1 = require("react");
6
+ var useMutableRef_1 = require("../../../hooks/useMutableRef");
6
7
  var getNextIndex_1 = require("../../../utils/getNextIndex");
7
8
  var getPrevIndex_1 = require("../../../utils/getPrevIndex");
8
9
  var isKey_1 = require("../../../utils/isKey");
@@ -10,19 +11,10 @@ var isKeys_1 = require("../../../utils/isKeys");
10
11
  /** Навигация по элементам списка без перехвата фокуса с элемента контроля */
11
12
  function useDataListNavigation(_a) {
12
13
  var selected = _a.selected, onSelect = _a.onSelect, _b = _a.active, active = _b === void 0 ? false : _b, itemsProps = _a.items;
13
- var savedItems = (0, react_1.useRef)(itemsProps);
14
- var savedSelected = (0, react_1.useRef)();
15
- var savedOnSelect = (0, react_1.useRef)();
14
+ var savedItems = (0, useMutableRef_1.useMutableRef)(itemsProps);
15
+ var savedSelected = (0, useMutableRef_1.useMutableRef)(selected);
16
+ var savedOnSelect = (0, useMutableRef_1.useMutableRef)(onSelect);
16
17
  var _c = tslib_1.__read((0, react_1.useState)({}), 2), state = _c[0], setState = _c[1];
17
- (0, react_1.useEffect)(function () {
18
- savedItems.current = itemsProps;
19
- }, [itemsProps]);
20
- (0, react_1.useEffect)(function () {
21
- savedOnSelect.current = onSelect;
22
- }, [onSelect]);
23
- (0, react_1.useEffect)(function () {
24
- savedSelected.current = selected;
25
- }, [selected]);
26
18
  var findInItems = function (value) { var _a; return (_a = savedItems.current) === null || _a === void 0 ? void 0 : _a.find(function (item) { return item === value; }); };
27
19
  (0, react_1.useEffect)(function () {
28
20
  if (!active) {
@@ -82,3 +82,8 @@
82
82
  --list-pipka-height: 48px;
83
83
  --list-pipka-width: 4px;
84
84
  }
85
+
86
+ .List_disablePadding,
87
+ .List:empty {
88
+ --list-gutter: 0;
89
+ }
@@ -12,8 +12,8 @@ var ListContext_1 = require("./ListContext");
12
12
  exports.cnList = (0, classname_1.cn)('List');
13
13
  exports.List = (0, polymorphicComponentWithRef_1.polymorphicComponentWithRef)(function (inProps, ref) {
14
14
  var props = (0, useThemeProps_1.useThemeProps)({ props: inProps, name: 'List' });
15
- var _a = props.as, Tag = _a === void 0 ? constants_1.LIST_DEFAULT_TAG : _a, _b = props.size, size = _b === void 0 ? constants_1.LIST_DEFAULT_SIZE : _b, children = props.children, className = props.className, other = tslib_1.__rest(props, ["as", "size", "children", "className"]);
15
+ var _a = props.as, Tag = _a === void 0 ? constants_1.LIST_DEFAULT_TAG : _a, _b = props.size, size = _b === void 0 ? constants_1.LIST_DEFAULT_SIZE : _b, _c = props.disablePadding, disablePadding = _c === void 0 ? constants_1.LIST_DEFAULT_DISABLE_PADDING : _c, children = props.children, className = props.className, other = tslib_1.__rest(props, ["as", "size", "disablePadding", "children", "className"]);
16
16
  return (react_1.default.createElement(ListContext_1.ListContext.Provider, { value: { size: size } },
17
- react_1.default.createElement(Tag, tslib_1.__assign({ className: (0, exports.cnList)({ size: size }, [className]) }, other, { ref: ref }), children)));
17
+ react_1.default.createElement(Tag, tslib_1.__assign({ className: (0, exports.cnList)({ size: size, disablePadding: disablePadding }, [className]) }, other, { ref: ref }), children)));
18
18
  });
19
19
  exports.List.displayName = 'List';
@@ -1,4 +1,5 @@
1
1
  export declare const LIST_DEFAULT_SIZE = "m";
2
+ export declare const LIST_DEFAULT_DISABLE_PADDING = false;
2
3
  export declare const LIST_DEFAULT_TAG = "ul";
3
4
  export declare const LIST_ITEM_DEFAULT_TAG = "li";
4
5
  export declare const LIST_ITEM_DEFAULT_ALIGN = "center";
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LIST_ITEM_BUTTON_DEFAULT_ALIGN = exports.LIST_ITEM_BUTTON_DEFAULT_TAG = exports.LIST_ITEM_DEFAULT_ALIGN = exports.LIST_ITEM_DEFAULT_TAG = exports.LIST_DEFAULT_TAG = exports.LIST_DEFAULT_SIZE = void 0;
3
+ exports.LIST_ITEM_BUTTON_DEFAULT_ALIGN = exports.LIST_ITEM_BUTTON_DEFAULT_TAG = exports.LIST_ITEM_DEFAULT_ALIGN = exports.LIST_ITEM_DEFAULT_TAG = exports.LIST_DEFAULT_TAG = exports.LIST_DEFAULT_DISABLE_PADDING = exports.LIST_DEFAULT_SIZE = void 0;
4
4
  exports.LIST_DEFAULT_SIZE = 'm';
5
+ exports.LIST_DEFAULT_DISABLE_PADDING = false;
5
6
  exports.LIST_DEFAULT_TAG = 'ul';
6
7
  exports.LIST_ITEM_DEFAULT_TAG = 'li';
7
8
  exports.LIST_ITEM_DEFAULT_ALIGN = 'center';
@@ -11,6 +11,8 @@ export type ListBaseProps = {
11
11
  children?: ReactNode;
12
12
  /** Размер компонента */
13
13
  size?: ListSizeVariant;
14
+ /** Если {true} отключает боковые отступы */
15
+ disablePadding?: boolean;
14
16
  /** Идентификатор компонента для тестов */
15
17
  'data-testid'?: string;
16
18
  };
@@ -1,5 +1,6 @@
1
1
  import type { AccordionProps, AccordionSummaryProps } from '../Accordion';
2
2
  import type { AlertProps } from '../Alert';
3
+ import type { AutocompleteProps } from '../Autocomplete';
3
4
  import type { AvatarProps } from '../Avatar';
4
5
  import type { BackdropProps } from '../Backdrop';
5
6
  import type { BadgeProps } from '../Badge';
@@ -64,6 +65,7 @@ export type Theme = {
64
65
  Accordion?: Partial<AccordionProps>;
65
66
  AccordionSummary?: Partial<AccordionSummaryProps>;
66
67
  Alert?: Partial<AlertProps>;
68
+ Autocomplete?: Partial<AutocompleteProps>;
67
69
  Avatar?: Partial<AvatarProps>;
68
70
  Backdrop?: Partial<BackdropProps>;
69
71
  Badge?: Partial<BadgeProps>;
@@ -2,13 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useEventListener = void 0;
4
4
  var react_1 = require("react");
5
+ var useMutableRef_1 = require("../../hooks/useMutableRef");
5
6
  /** Хук добавляющий обработчики событий и удаляющий их на выходе */
6
7
  function useEventListener(_a) {
7
8
  var eventName = _a.eventName, handler = _a.handler, element = _a.element, options = _a.options, _b = _a.active, active = _b === void 0 ? true : _b;
8
- var savedListener = (0, react_1.useRef)();
9
- (0, react_1.useEffect)(function () {
10
- savedListener.current = handler;
11
- }, [handler]);
9
+ var savedListener = (0, useMutableRef_1.useMutableRef)(handler);
12
10
  var handleEventListener = (0, react_1.useCallback)(function (event) {
13
11
  var _a;
14
12
  (_a = savedListener.current) === null || _a === void 0 ? void 0 : _a.call(savedListener, event);
@@ -0,0 +1 @@
1
+ export * from './useMutableRef';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./useMutableRef"), exports);
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function useMutableRef<T>(value: T): import("react").MutableRefObject<T>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useMutableRef = void 0;
4
+ var react_1 = require("react");
5
+ function useMutableRef(value) {
6
+ var ref = (0, react_1.useRef)(value);
7
+ ref.current = value;
8
+ return ref;
9
+ }
10
+ exports.useMutableRef = useMutableRef;
@@ -3,6 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.enUS = exports.kkKZ = exports.ruRU = void 0;
4
4
  exports.ruRU = {
5
5
  defaultProps: {
6
+ Autocomplete: {
7
+ noOptionsText: 'Ничего не найдено',
8
+ closeText: 'Закрыть',
9
+ openText: 'Открыть',
10
+ clearText: 'Очистить',
11
+ loadingText: 'Загрузка…',
12
+ },
6
13
  Loader: {
7
14
  'aria-label': 'Загрузка',
8
15
  },
@@ -18,6 +25,13 @@ exports.ruRU = {
18
25
  };
19
26
  exports.kkKZ = {
20
27
  defaultProps: {
28
+ Autocomplete: {
29
+ noOptionsText: 'Ештеңе табылған жоқ',
30
+ closeText: 'Жабу',
31
+ openText: 'Ашу',
32
+ clearText: 'Тазалау',
33
+ loadingText: 'Жүктеу…',
34
+ },
21
35
  Loader: {
22
36
  'aria-label': 'Жүктеу',
23
37
  },
@@ -33,6 +47,13 @@ exports.kkKZ = {
33
47
  };
34
48
  exports.enUS = {
35
49
  defaultProps: {
50
+ Autocomplete: {
51
+ noOptionsText: 'No options',
52
+ closeText: 'Close',
53
+ openText: 'Open',
54
+ clearText: 'Clear',
55
+ loadingText: 'Loading…',
56
+ },
36
57
  Loader: {
37
58
  'aria-label': 'Loading',
38
59
  },
@@ -0,0 +1,46 @@
1
+ .Autocomplete {
2
+ --autocomplete-gutter-x: 0 var(--textfield-gutter-x);
3
+ }
4
+
5
+ .Autocomplete_hasChevron.Autocomplete_size_2xs {
6
+ --autocomplete-gutter-x: 0 var(--control-padding-2xs) 0
7
+ var(--control-padding-xs);
8
+ }
9
+
10
+ .Autocomplete_hasChevron.Autocomplete_size_xs {
11
+ --autocomplete-gutter-x: 0 var(--control-padding-2xs) 0
12
+ var(--control-padding-xs);
13
+ }
14
+
15
+ .Autocomplete_hasChevron.Autocomplete_size_s {
16
+ --autocomplete-gutter-x: 0 var(--control-padding-2xs) 0
17
+ var(--control-padding-s);
18
+ }
19
+
20
+ .Autocomplete_hasChevron.Autocomplete_size_m {
21
+ --autocomplete-gutter-x: 0 var(--control-padding-2xs) 0
22
+ var(--control-padding-m);
23
+ }
24
+
25
+ .Autocomplete_hasChevron.Autocomplete_size_l {
26
+ --autocomplete-gutter-x: 0 var(--control-padding-2xs) 0
27
+ var(--control-padding-l);
28
+ }
29
+
30
+ .Autocomplete-RenderRight {
31
+ display: flex;
32
+ gap: var(--spacing-2xs);
33
+ }
34
+
35
+ .Autocomplete-ClearButton {
36
+ visibility: hidden;
37
+ transition: visibility var(--transition-default);
38
+ }
39
+
40
+ .Autocomplete-ClearButton_visibility {
41
+ visibility: visible;
42
+ }
43
+
44
+ .Autocomplete .Input-Body {
45
+ padding: var(--autocomplete-gutter-x);
46
+ }
@@ -0,0 +1,4 @@
1
+ import './Autocomplete.css';
2
+ import type { AutocompleteComponent } from './types';
3
+ export declare const cnAutocomplete: import("@bem-react/classname").ClassNameFormatter;
4
+ export declare const Autocomplete: AutocompleteComponent;
@@ -0,0 +1,199 @@
1
+ import { __assign, __read, __rest, __spreadArray } from "tslib";
2
+ import './Autocomplete.css';
3
+ import React, { useEffect, useRef, forwardRef, useState } from 'react';
4
+ import { useControlled } from '../../hooks/useControlled';
5
+ import { useMutableRef } from '../../hooks/useMutableRef';
6
+ import { useThemeProps } from '../../hooks/useThemeProps';
7
+ import { cn } from '../../utils/classname';
8
+ import { isKeys } from '../../utils/isKeys';
9
+ import { DataList, DataListOption } from '../DataList';
10
+ import { Input } from '../Input';
11
+ import { AutocompleteLoading, AutocompleteNoOptions, AutocompleteRenderRight, } from './components';
12
+ import { AUTOCOMPLETE_DEFAULT_SIZE, AUTOCOMPLETE_DEFAULT_DISABLED, AUTOCOMPLETE_DEFAULT_REQUIRED, AUTOCOMPLETE_DEFAULT_FULLWIDTH, AUTOCOMPLETE_DEFAULT_AUTOFOCUS, AUTOCOMPLETE_DEFAULT_ALLOW_CUSTOM_VALUE, AUTOCOMPLETE_DEFAULT_DISABLE_SHOW_CHEVRON, AUTOCOMPLETE_DEFAULT_DISABLE_CLEAR_BUTTON, AUTOCOMPLETE_DEFAULT_DISABLE_SHOW_EMPTY_OPTIONS_LIST, AUTOCOMPLETE_DEFAULT_DISABLE_CLOSE_ON_SELECT, } from './constants';
13
+ import { withDefaultGetters } from './helper';
14
+ export var cnAutocomplete = cn('Autocomplete');
15
+ function AutocompleteRender(inProps, ref) {
16
+ var props = useThemeProps({
17
+ props: inProps,
18
+ name: 'Autocomplete',
19
+ });
20
+ var _a = withDefaultGetters(props), _b = _a.disabled, disabled = _b === void 0 ? AUTOCOMPLETE_DEFAULT_DISABLED : _b, _c = _a.required, required = _c === void 0 ? AUTOCOMPLETE_DEFAULT_REQUIRED : _c, _d = _a.autoFocus, autoFocus = _d === void 0 ? AUTOCOMPLETE_DEFAULT_AUTOFOCUS : _d, _e = _a.fullWidth, fullWidth = _e === void 0 ? AUTOCOMPLETE_DEFAULT_FULLWIDTH : _e, _f = _a.size, size = _f === void 0 ? AUTOCOMPLETE_DEFAULT_SIZE : _f, _g = _a.allowCustomValue, allowCustomValue = _g === void 0 ? AUTOCOMPLETE_DEFAULT_ALLOW_CUSTOM_VALUE : _g, _h = _a.disableShowChevron, disableShowChevron = _h === void 0 ? AUTOCOMPLETE_DEFAULT_DISABLE_SHOW_CHEVRON : _h, _j = _a.disableClearButton, disableClearButton = _j === void 0 ? AUTOCOMPLETE_DEFAULT_DISABLE_CLEAR_BUTTON : _j, _k = _a.disableShowEmptyOptionsList, disableShowEmptyOptionsList = _k === void 0 ? AUTOCOMPLETE_DEFAULT_DISABLE_SHOW_EMPTY_OPTIONS_LIST : _k, _l = _a.disableCloseOnSelect, disableCloseOnSelect = _l === void 0 ? AUTOCOMPLETE_DEFAULT_DISABLE_CLOSE_ON_SELECT : _l, _m = _a.renderInput, renderInput = _m === void 0 ? function (props) { return React.createElement(Input, __assign({}, props, { ref: ref })); } : _m, searchFunctionProp = _a.searchFunction, renderOptionProp = _a.renderOption, inputValueProp = _a.inputValue, className = _a.className, valueProp = _a.value, options = _a.options, defaultValue = _a.defaultValue, error = _a.error, onChange = _a.onChange, onInputChange = _a.onInputChange, label = _a.label, placeholder = _a.placeholder, renderLeft = _a.renderLeft, hint = _a.hint, getOptionKey = _a.getOptionKey, getOptionLabel = _a.getOptionLabel, getOptionDisabled = _a.getOptionDisabled, dataListProps = _a.dataListProps, onCloseProp = _a.onClose, onOpenProp = _a.onOpen, openProp = _a.open, defaultOpen = _a.defaultOpen, loading = _a.loading, inputProps = _a.inputProps, onKeyDown = _a.onKeyDown, noOptionsText = _a.noOptionsText, clearText = _a.clearText, openText = _a.openText, loadingText = _a.loadingText, closeText = _a.closeText, other = __rest(_a, ["disabled", "required", "autoFocus", "fullWidth", "size", "allowCustomValue", "disableShowChevron", "disableClearButton", "disableShowEmptyOptionsList", "disableCloseOnSelect", "renderInput", "searchFunction", "renderOption", "inputValue", "className", "value", "options", "defaultValue", "error", "onChange", "onInputChange", "label", "placeholder", "renderLeft", "hint", "getOptionKey", "getOptionLabel", "getOptionDisabled", "dataListProps", "onClose", "onOpen", "open", "defaultOpen", "loading", "inputProps", "onKeyDown", "noOptionsText", "clearText", "openText", "loadingText", "closeText"]);
21
+ var anchorRef = useRef(null);
22
+ var _o = __read(useControlled({
23
+ value: inputValueProp,
24
+ defaultValue: '',
25
+ name: 'Autocomplete',
26
+ state: 'inputValue',
27
+ }), 2), inputValue = _o[0], setInputValue = _o[1];
28
+ var _p = __read(useControlled({
29
+ value: valueProp,
30
+ defaultValue: defaultValue,
31
+ name: 'Autocomplete',
32
+ state: 'value',
33
+ }), 2), valueState = _p[0], setValueState = _p[1];
34
+ var _q = __read(useControlled({
35
+ value: openProp,
36
+ defaultValue: defaultOpen,
37
+ name: 'Autocomplete',
38
+ state: 'open',
39
+ }), 2), open = _q[0], setOpen = _q[1];
40
+ var searchFunctionDefault = function (options, searchValue) {
41
+ return options === null || options === void 0 ? void 0 : options.filter(function (option) {
42
+ return getOptionLabel(option).toLowerCase().includes(searchValue.toLowerCase());
43
+ });
44
+ };
45
+ var savedOnInputChange = useMutableRef(onInputChange);
46
+ var savedGetOptionLabel = useMutableRef(getOptionLabel);
47
+ var _r = __read(useState(__spreadArray([], __read(options), false)), 2), filteredOptions = _r[0], setFilteredOptions = _r[1];
48
+ var searchFunction = searchFunctionProp || searchFunctionDefault;
49
+ var dataListValue = valueState ? getOptionLabel(valueState) : '';
50
+ var hasOptions = !!(filteredOptions === null || filteredOptions === void 0 ? void 0 : filteredOptions.length);
51
+ var showNoOptions = !hasOptions && !loading;
52
+ var showLoading = !hasOptions && !!loading;
53
+ var _s = __read(useState(undefined), 2), search = _s[0], setSearch = _s[1];
54
+ /** Эффект – фильтрация списка */
55
+ useEffect(function () {
56
+ if (!open) {
57
+ return;
58
+ }
59
+ setFilteredOptions(search ? search(options) : __spreadArray([], __read(options), false));
60
+ }, [search, options, open, searchFunctionProp]);
61
+ /** Эффект – синхронизируем значение текстового поля со значением в списке */
62
+ useEffect(function () {
63
+ var _a, _b;
64
+ var value = valueState ? (_a = savedGetOptionLabel.current) === null || _a === void 0 ? void 0 : _a.call(savedGetOptionLabel, valueState) : '';
65
+ if (allowCustomValue) {
66
+ value = inputValue || '';
67
+ }
68
+ if (value !== inputValue) {
69
+ setInputValue(value);
70
+ (_b = savedOnInputChange.current) === null || _b === void 0 ? void 0 : _b.call(savedOnInputChange, null, value);
71
+ }
72
+ }, [valueState]);
73
+ /** Эффект – автофокусировка в текстовом поле */
74
+ useEffect(function () {
75
+ var _a;
76
+ if (autoFocus) {
77
+ (_a = anchorRef.current) === null || _a === void 0 ? void 0 : _a.focus();
78
+ }
79
+ }, [autoFocus]);
80
+ /** Актуализация значения текстового поля после его покидания */
81
+ var onBlur = function (e) {
82
+ var _a;
83
+ if (allowCustomValue) {
84
+ return;
85
+ }
86
+ var value = valueState ? getOptionLabel(valueState) : '';
87
+ if (inputValue !== value) {
88
+ setInputValue(value);
89
+ onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(null, value);
90
+ }
91
+ (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
92
+ };
93
+ /** Ждем выполнения анимации на закрытие и делаем сброс */
94
+ var onExited = function () {
95
+ var _a;
96
+ setSearch(undefined);
97
+ (_a = dataListProps === null || dataListProps === void 0 ? void 0 : dataListProps.onExited) === null || _a === void 0 ? void 0 : _a.call(dataListProps);
98
+ };
99
+ /** Закрытие */
100
+ var handleClose = function () {
101
+ setOpen(false);
102
+ onCloseProp === null || onCloseProp === void 0 ? void 0 : onCloseProp();
103
+ };
104
+ /** Открытие */
105
+ var handleOpen = function () {
106
+ setOpen(true);
107
+ onOpenProp === null || onOpenProp === void 0 ? void 0 : onOpenProp();
108
+ };
109
+ /** Переключатель открытия и закрытия */
110
+ var handleToggle = function () {
111
+ if (disabled)
112
+ return;
113
+ if (open) {
114
+ handleClose();
115
+ }
116
+ else {
117
+ handleOpen();
118
+ }
119
+ };
120
+ /** Очистка поля */
121
+ var onClear = function (e) {
122
+ setValueState(null);
123
+ setInputValue('');
124
+ onChange === null || onChange === void 0 ? void 0 : onChange(e, null);
125
+ onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(null, '');
126
+ setSearch(undefined);
127
+ };
128
+ /** Открытие списка по клику на текстовом поле */
129
+ var handleClickOnInput = function (e) {
130
+ var _a;
131
+ handleToggle();
132
+ (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onClick) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
133
+ };
134
+ /** Управление элементом контроля через клавиатуру */
135
+ var handleKeyDown = function (event) {
136
+ if (isKeys(event, ['ArrowDown', 'ArrowUp']) && !open) {
137
+ event.preventDefault();
138
+ handleToggle();
139
+ }
140
+ onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
141
+ };
142
+ /** Событие ввода значения в текстовом поле */
143
+ var handleChangeInput = function (e) {
144
+ var value = e.target.value;
145
+ // Открываем список при вводе первого символа (при условии, что список еще не открыт)
146
+ if (value.length && !open) {
147
+ handleOpen();
148
+ }
149
+ // Делаем сброс при пустом значении в текстовом поле
150
+ if (!value) {
151
+ setValueState(null);
152
+ onChange === null || onChange === void 0 ? void 0 : onChange(e, null);
153
+ }
154
+ // Назначаем значение
155
+ setInputValue(value);
156
+ onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(e, value);
157
+ // Задаем функцию фильтрации
158
+ setSearch(function () { return function (options) { return searchFunction(__spreadArray([], __read(options), false), value); }; });
159
+ };
160
+ /** Событие выбора значения из раскрывающегося списка */
161
+ var handleChangeDataList = function (event, _a) {
162
+ var value = _a.value;
163
+ var selectedOption = filteredOptions === null || filteredOptions === void 0 ? void 0 : filteredOptions.find(function (option) { return (getOptionLabel === null || getOptionLabel === void 0 ? void 0 : getOptionLabel(option)) === value; });
164
+ if (selectedOption) {
165
+ var newInputValue = getOptionLabel(selectedOption);
166
+ setValueState(selectedOption);
167
+ onChange === null || onChange === void 0 ? void 0 : onChange(event, selectedOption);
168
+ setInputValue(newInputValue);
169
+ onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(null, newInputValue);
170
+ }
171
+ // Закрываем список после выбора
172
+ if (!disableCloseOnSelect) {
173
+ handleClose();
174
+ }
175
+ };
176
+ /** Отображение текстового поля */
177
+ var input = renderInput(__assign(__assign({ size: size, hint: hint, disabled: disabled, label: label, required: required, error: error, fullWidth: fullWidth, placeholder: placeholder, renderLeft: renderLeft }, other), { renderRight: (React.createElement(AutocompleteRenderRight, { open: open, size: size, disabled: disabled, clearText: clearText, closeText: closeText, openText: openText, hasValue: !!inputValue, onClear: onClear, onOpen: handleToggle, disableShowChevron: disableShowChevron, disableClearButton: disableClearButton })), onChange: handleChangeInput, onKeyDown: handleKeyDown, value: inputValue || '', inputProps: __assign(__assign({}, inputProps), { onBlur: onBlur, onClick: handleClickOnInput }), bodyProps: { ref: anchorRef, 'aria-expanded': open }, className: cnAutocomplete({ size: size, hasChevron: !disableShowChevron }, [
178
+ className,
179
+ ]), ref: ref }));
180
+ /** Отображение опций */
181
+ var renderOptions = filteredOptions === null || filteredOptions === void 0 ? void 0 : filteredOptions.map(function (option) {
182
+ var selected = valueState
183
+ ? getOptionLabel(valueState) === getOptionLabel(option)
184
+ : false;
185
+ var renderOptionDefault = function (_a) {
186
+ var option = _a.option, selected = _a.selected;
187
+ return (React.createElement(DataListOption, { key: getOptionKey === null || getOptionKey === void 0 ? void 0 : getOptionKey(option), label: getOptionLabel === null || getOptionLabel === void 0 ? void 0 : getOptionLabel(option), value: getOptionLabel === null || getOptionLabel === void 0 ? void 0 : getOptionLabel(option), disabled: getOptionDisabled === null || getOptionDisabled === void 0 ? void 0 : getOptionDisabled(option), selected: selected }));
188
+ };
189
+ var renderOption = renderOptionProp || renderOptionDefault;
190
+ return renderOption({ option: option, selected: selected });
191
+ });
192
+ return (React.createElement(React.Fragment, null,
193
+ input,
194
+ React.createElement(DataList, __assign({ size: size, equalAnchorWidth: true, offset: [0, 4], placement: "bottom-start" }, dataListProps, { open: open, onExited: onExited, onClose: handleClose, anchorRef: anchorRef, selected: dataListValue, onSelect: handleChangeDataList, listProps: __assign({ role: 'listbox' }, dataListProps === null || dataListProps === void 0 ? void 0 : dataListProps.listProps) }),
195
+ renderOptions,
196
+ !disableShowEmptyOptionsList && (React.createElement(AutocompleteNoOptions, { showNoOptions: showNoOptions, noOptionsText: noOptionsText })),
197
+ React.createElement(AutocompleteLoading, { showLoading: showLoading, loadingText: loadingText, size: size }))));
198
+ }
199
+ export var Autocomplete = forwardRef(AutocompleteRender);
@@ -0,0 +1,6 @@
1
+ import type { FC } from 'react';
2
+ import type { AutocompleteProps } from '../../index';
3
+ export type AutocompleteLoadingProps = Pick<AutocompleteProps, 'loadingText' | 'size'> & {
4
+ showLoading: boolean;
5
+ };
6
+ export declare const AutocompleteLoading: FC<AutocompleteLoadingProps>;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { getIconSizeToFormElement } from '../../../../utils/getIconSizeToFormElement';
3
+ import { isNumber } from '../../../../utils/isNumber';
4
+ import { isString } from '../../../../utils/isString';
5
+ import { ListItem, ListItemIcon, ListItemText } from '../../../List';
6
+ import { Loader } from '../../../Loader';
7
+ import { AUTOCOMPLETE_DEFAULT_SIZE } from '../../constants';
8
+ export var AutocompleteLoading = function (_a) {
9
+ var _b = _a.size, sizeProp = _b === void 0 ? AUTOCOMPLETE_DEFAULT_SIZE : _b, showLoading = _a.showLoading, loadingText = _a.loadingText;
10
+ if (!showLoading) {
11
+ return null;
12
+ }
13
+ var size = getIconSizeToFormElement(sizeProp);
14
+ return isString(loadingText) || isNumber(loadingText) ? (React.createElement(ListItem, null,
15
+ React.createElement(ListItemIcon, null,
16
+ React.createElement(Loader, { size: size })),
17
+ React.createElement(ListItemText, { primary: loadingText }))) : (loadingText);
18
+ };
@@ -0,0 +1 @@
1
+ export * from './AutocompleteLoading';
@@ -0,0 +1 @@
1
+ export * from './AutocompleteLoading';
@@ -0,0 +1,6 @@
1
+ import type { FC } from 'react';
2
+ import type { AutocompleteProps } from '../../index';
3
+ export type AutocompleteNoOptionsProps = Pick<AutocompleteProps, 'noOptionsText'> & {
4
+ showNoOptions: boolean;
5
+ };
6
+ export declare const AutocompleteNoOptions: FC<AutocompleteNoOptionsProps>;
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { isNumber } from '../../../../utils/isNumber';
3
+ import { isString } from '../../../../utils/isString';
4
+ import { ListItem, ListItemText } from '../../../List';
5
+ export var AutocompleteNoOptions = function (_a) {
6
+ var showNoOptions = _a.showNoOptions, noOptionsText = _a.noOptionsText;
7
+ if (!showNoOptions) {
8
+ return null;
9
+ }
10
+ return isString(noOptionsText) || isNumber(noOptionsText) ? (React.createElement(ListItem, null,
11
+ React.createElement(ListItemText, { primary: noOptionsText }))) : (noOptionsText);
12
+ };
@@ -0,0 +1 @@
1
+ export * from './AutocompleteNoOptions';
@@ -0,0 +1 @@
1
+ export * from './AutocompleteNoOptions';
@@ -0,0 +1,10 @@
1
+ import type { FC } from 'react';
2
+ import React from 'react';
3
+ import type { AutocompleteProps } from '../../index';
4
+ type AutocompleteRenderRightProps = {
5
+ onOpen: () => void;
6
+ onClear: (e: React.MouseEvent<HTMLElement>) => void;
7
+ hasValue: boolean;
8
+ } & Pick<AutocompleteProps, 'clearText' | 'closeText' | 'openText' | 'size' | 'disabled' | 'open' | 'disableClearButton' | 'disableShowChevron'>;
9
+ export declare const AutocompleteRenderRight: FC<AutocompleteRenderRightProps>;
10
+ export {};