@ozen-ui/kit 0.17.0 → 0.19.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 (64) hide show
  1. package/ChipNext/package.json +5 -0
  2. package/__inner__/cjs/components/Chip/Chip.d.ts +3 -0
  3. package/__inner__/cjs/components/Chip/Chip.js +3 -0
  4. package/__inner__/cjs/components/ChipNext/Chip.css +108 -0
  5. package/__inner__/cjs/components/ChipNext/Chip.d.ts +42 -0
  6. package/__inner__/cjs/components/ChipNext/Chip.js +46 -0
  7. package/__inner__/cjs/components/ChipNext/constants.d.ts +4 -0
  8. package/__inner__/cjs/components/ChipNext/constants.js +7 -0
  9. package/__inner__/cjs/components/ChipNext/index.d.ts +1 -0
  10. package/__inner__/cjs/components/ChipNext/index.js +4 -0
  11. package/__inner__/cjs/components/FieldIcon/FieldIcon.d.ts +4 -7
  12. package/__inner__/cjs/components/FieldIcon/FieldIcon.js +5 -21
  13. package/__inner__/cjs/components/List/List.css +1 -0
  14. package/__inner__/cjs/components/Menu/Menu.css +0 -1
  15. package/__inner__/cjs/components/Menu/components/MenuItem/MenuItem.js +4 -4
  16. package/__inner__/cjs/components/Menu/components/MenuList/MenuList.d.ts +2 -2
  17. package/__inner__/cjs/components/Menu/components/MenuList/MenuList.js +44 -26
  18. package/__inner__/cjs/components/Menu/useMenuFocusList.js +11 -1
  19. package/__inner__/cjs/components/Modal/Modal.js +3 -7
  20. package/__inner__/cjs/components/Popover/Popover.js +1 -5
  21. package/__inner__/cjs/components/Select/Select.js +2 -5
  22. package/__inner__/cjs/components/ThemeProvider/types.d.ts +2 -0
  23. package/__inner__/cjs/hooks/useFocusList/useFocusList.js +10 -1
  24. package/__inner__/cjs/hooks/useMultiRef/useMultiRef.js +2 -7
  25. package/__inner__/cjs/utils/isKeys.d.ts +3 -0
  26. package/__inner__/cjs/utils/isKeys.js +6 -0
  27. package/__inner__/cjs/utils/renderContent/index.d.ts +1 -0
  28. package/__inner__/cjs/utils/renderContent/index.js +4 -0
  29. package/__inner__/cjs/utils/renderContent/renderContent.d.ts +6 -0
  30. package/__inner__/cjs/utils/renderContent/renderContent.js +29 -0
  31. package/__inner__/cjs/utils/setRef.d.ts +4 -0
  32. package/__inner__/cjs/utils/setRef.js +13 -0
  33. package/__inner__/esm/components/Chip/Chip.d.ts +3 -0
  34. package/__inner__/esm/components/Chip/Chip.js +3 -0
  35. package/__inner__/esm/components/ChipNext/Chip.css +108 -0
  36. package/__inner__/esm/components/ChipNext/Chip.d.ts +42 -0
  37. package/__inner__/esm/components/ChipNext/Chip.js +43 -0
  38. package/__inner__/esm/components/ChipNext/constants.d.ts +4 -0
  39. package/__inner__/esm/components/ChipNext/constants.js +4 -0
  40. package/__inner__/esm/components/ChipNext/index.d.ts +1 -0
  41. package/__inner__/esm/components/ChipNext/index.js +1 -0
  42. package/__inner__/esm/components/FieldIcon/FieldIcon.d.ts +4 -7
  43. package/__inner__/esm/components/FieldIcon/FieldIcon.js +5 -21
  44. package/__inner__/esm/components/List/List.css +1 -0
  45. package/__inner__/esm/components/Menu/Menu.css +0 -1
  46. package/__inner__/esm/components/Menu/components/MenuItem/MenuItem.js +4 -4
  47. package/__inner__/esm/components/Menu/components/MenuList/MenuList.d.ts +2 -2
  48. package/__inner__/esm/components/Menu/components/MenuList/MenuList.js +46 -28
  49. package/__inner__/esm/components/Menu/useMenuFocusList.js +11 -1
  50. package/__inner__/esm/components/Modal/Modal.js +3 -7
  51. package/__inner__/esm/components/Popover/Popover.js +1 -5
  52. package/__inner__/esm/components/Select/Select.js +2 -5
  53. package/__inner__/esm/components/ThemeProvider/types.d.ts +2 -0
  54. package/__inner__/esm/hooks/useFocusList/useFocusList.js +10 -1
  55. package/__inner__/esm/hooks/useMultiRef/useMultiRef.js +2 -7
  56. package/__inner__/esm/utils/isKeys.d.ts +3 -0
  57. package/__inner__/esm/utils/isKeys.js +2 -0
  58. package/__inner__/esm/utils/renderContent/index.d.ts +1 -0
  59. package/__inner__/esm/utils/renderContent/index.js +1 -0
  60. package/__inner__/esm/utils/renderContent/renderContent.d.ts +6 -0
  61. package/__inner__/esm/utils/renderContent/renderContent.js +25 -0
  62. package/__inner__/esm/utils/setRef.d.ts +4 -0
  63. package/__inner__/esm/utils/setRef.js +9 -0
  64. package/package.json +1 -1
@@ -5,15 +5,24 @@ var react_1 = require("react");
5
5
  var getNextIndex_1 = require("../../utils/getNextIndex");
6
6
  var getPrevIndex_1 = require("../../utils/getPrevIndex");
7
7
  var isKey_1 = require("../../utils/isKey");
8
+ var isKeys_1 = require("../../utils/isKeys");
8
9
  var useUniqueId_1 = require("../useUniqueId");
9
10
  function useFocusList() {
10
11
  var name = (0, useUniqueId_1.useUniqueId)();
11
12
  var onKeyDown = (0, react_1.useCallback)(function (event) {
12
- if (!(0, isKey_1.isKey)(event, 'ArrowUp') && !(0, isKey_1.isKey)(event, 'ArrowDown')) {
13
+ if (!(0, isKeys_1.isKeys)(event, ['ArrowUp', 'ArrowDown', 'Home', 'End'])) {
13
14
  return;
14
15
  }
15
16
  event.preventDefault();
16
17
  var items = document.querySelectorAll("[data-focus-list=\"".concat(name, "\"]"));
18
+ if ((0, isKey_1.isKey)(event, 'Home')) {
19
+ items.item(0).focus();
20
+ return;
21
+ }
22
+ if ((0, isKey_1.isKey)(event, 'Home')) {
23
+ items.item(items.length - 1).focus();
24
+ return;
25
+ }
17
26
  var currentEl = event.target;
18
27
  var currentIndex = Array.from(items).indexOf(currentEl);
19
28
  var newIndex = (0, isKey_1.isKey)(event, 'ArrowUp')
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useMultiRef = void 0;
4
4
  var react_1 = require("react");
5
+ var setRef_1 = require("../../utils/setRef");
5
6
  /** Создает несколько ссылок (ref) на один DOM-элемент. */
6
7
  function useMultiRef(refs) {
7
8
  // Мемоизирует массив ref'ов
@@ -12,13 +13,7 @@ function useMultiRef(refs) {
12
13
  }
13
14
  return function (node) {
14
15
  arrRefs.current.forEach(function (ref) {
15
- if (typeof ref === 'function') {
16
- ref(node);
17
- }
18
- else if (ref) {
19
- // eslint-disable-next-line no-param-reassign
20
- ref.current = node;
21
- }
16
+ (0, setRef_1.setRef)(ref, node);
22
17
  });
23
18
  };
24
19
  }, [arrRefs]);
@@ -0,0 +1,3 @@
1
+ import type { KeyboardEvent as ReactKeyboardEvent } from 'react';
2
+ import type { KeyCode } from '../types/KeyCode';
3
+ export declare const isKeys: (event: KeyboardEvent | ReactKeyboardEvent, keys: KeyCode[]) => boolean;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isKeys = void 0;
4
+ var isKey_1 = require("./isKey");
5
+ var isKeys = function (event, keys) { return keys.some(function (key) { return (0, isKey_1.isKey)(event, key); }); };
6
+ exports.isKeys = isKeys;
@@ -0,0 +1 @@
1
+ export * from './renderContent';
@@ -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("./renderContent"), exports);
@@ -0,0 +1,6 @@
1
+ import type { FC, ReactElement, ReactNode } from 'react';
2
+ export type RenderContentType<Props extends object> = {
3
+ content?: string | number | FC<Props> | ReactElement<Props> | (() => ReactElement<Props>);
4
+ props?: Props;
5
+ };
6
+ export declare function renderContent<Props extends object>({ content, props, }: RenderContentType<Props>): ReactNode;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderContent = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var react_1 = tslib_1.__importStar(require("react"));
6
+ var react_is_1 = require("react-is");
7
+ var mergeDeep_1 = require("../../utils/mergeDeep");
8
+ function renderContent(_a) {
9
+ var content = _a.content, props = _a.props;
10
+ // primitives: string or number
11
+ if (typeof content === 'string' || typeof content === 'number') {
12
+ return content;
13
+ }
14
+ // react-element
15
+ if ((0, react_is_1.isElement)(content)) {
16
+ return (0, react_1.cloneElement)(content, (0, mergeDeep_1.mergeDeep)(props, content.props));
17
+ }
18
+ // render-function
19
+ if (typeof content === 'function' && !(0, react_1.isValidElement)(content)) {
20
+ return content(props);
21
+ }
22
+ // react-component
23
+ if ((0, react_is_1.isValidElementType)(content)) {
24
+ var Content = content;
25
+ return react_1.default.createElement(Content, tslib_1.__assign({}, props));
26
+ }
27
+ return null;
28
+ }
29
+ exports.renderContent = renderContent;
@@ -0,0 +1,4 @@
1
+ import type { Dispatch, SetStateAction, Ref as ReactRef } from 'react';
2
+ type Ref<T> = ReactRef<T> | Dispatch<SetStateAction<T | undefined>> | null;
3
+ export declare const setRef: <T>(ref: Ref<T> | undefined, value: T) => void;
4
+ export {};
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setRef = void 0;
4
+ var setRef = function (ref, value) {
5
+ if (typeof ref === 'function') {
6
+ ref(value);
7
+ }
8
+ else if (ref) {
9
+ // eslint-disable-next-line no-param-reassign
10
+ ref.current = value;
11
+ }
12
+ };
13
+ exports.setRef = setRef;
@@ -33,4 +33,7 @@ export type ChipBaseProps = {
33
33
  'data-testid'?: string;
34
34
  };
35
35
  export type ChipProps = ExtendableProps<InputHTMLAttributes<HTMLInputElement>, ChipBaseProps>;
36
+ /**
37
+ * @deprecated Компонент устарел. Для замены используйте компонент ChipNext
38
+ */
36
39
  export declare const Chip: React.ForwardRefExoticComponent<ChipBaseProps & Omit<React.InputHTMLAttributes<HTMLInputElement>, keyof ChipBaseProps> & React.RefAttributes<HTMLLabelElement>>;
@@ -8,6 +8,9 @@ import { CHIP_DEFAULT_SIZE, CHIP_DEFAULT_VARIANT, CHIP_DEFAULT_DISABLED, } from
8
8
  export var cnChip = cn('Chip');
9
9
  export var chipSizeVariant = ['xs', 's', 'm', 'l'];
10
10
  export var chipColorVariant = ['primary', 'secondary'];
11
+ /**
12
+ * @deprecated Компонент устарел. Для замены используйте компонент ChipNext
13
+ */
11
14
  export var Chip = forwardRef(function (inProps, ref) {
12
15
  var _a = useThemeProps({ name: 'Chip', props: inProps }), _b = _a.size, size = _b === void 0 ? CHIP_DEFAULT_SIZE : _b, _c = _a.color, color = _c === void 0 ? CHIP_DEFAULT_VARIANT : _c, _d = _a.disabled, disabled = _d === void 0 ? CHIP_DEFAULT_DISABLED : _d, IconLeft = _a.iconLeft, IconRight = _a.iconRight, labelProps = _a.labelProps, inputRef = _a.inputRef, className = _a.className, children = _a.children, dataTestId = _a["data-testid"], other = __rest(_a, ["size", "color", "disabled", "iconLeft", "iconRight", "labelProps", "inputRef", "className", "children", 'data-testid']);
13
16
  var iconSize = useMemo(function () { return getIconSizeToFormElement(size); }, [size]);
@@ -0,0 +1,108 @@
1
+ /* stylelint-disable */
2
+ .ChipNext {
3
+ --chip-border-radius: 24px;
4
+ --chip-text-wrap: nowrap;
5
+ background-color: var(--chip-bg-color);
6
+ border-radius: var(--chip-border-radius);
7
+ min-block-size: var(--chip-height);
8
+ padding: 0 var(--chip-padding-x);
9
+ min-inline-size: var(--chip-min-width);
10
+ color: var(--chip-text-color);
11
+ gap: var(--space-s);
12
+ display: inline-flex;
13
+ justify-content: center;
14
+ align-items: center;
15
+ cursor: pointer;
16
+ box-sizing: border-box;
17
+ text-decoration: none;
18
+ border: none;
19
+ outline: none;
20
+ transition:
21
+ border-color var(--transition-default),
22
+ color var(--transition-default),
23
+ background-color var(--transition-default),
24
+ box-shadow var(--transition-default);
25
+ }
26
+ .ChipNext-Content {
27
+ overflow: hidden;
28
+ text-overflow: ellipsis;
29
+ white-space: var(--chip-text-wrap);
30
+ }
31
+ .ChipNext-Icon {
32
+ color: inherit;
33
+ flex-shrink: 0;
34
+ }
35
+ .ChipNext_multiline {
36
+ --chip-text-wrap: normal;
37
+ }
38
+ .ChipNext_size_xs {
39
+ font: var(--typography-text-2xs-font);
40
+ letter-spacing: var(--typography-text-2xs-letter_spacing, 0);
41
+ text-transform: var(--typography-text-2xs-text_transform, none);
42
+
43
+ --chip-min-width: 64px;
44
+ --chip-height: var(--space-xl);
45
+ --chip-padding-x: var(--space-m);
46
+ }
47
+ .ChipNext_size_s {
48
+ font: var(--typography-text-s-font);
49
+ letter-spacing: var(--typography-text-s-letter_spacing, 0);
50
+ text-transform: var(--typography-text-s-text_transform, none);
51
+
52
+ --chip-min-width: 72px;
53
+ --chip-height: var(--space-2xl);
54
+ --chip-padding-x: var(--space-l);
55
+ }
56
+ .ChipNext_size_m {
57
+ font: var(--typography-text-m-font);
58
+ letter-spacing: var(--typography-text-m-letter_spacing, 0);
59
+ text-transform: var(--typography-text-m-text_transform, none);
60
+
61
+ --chip-min-width: 80px;
62
+ --chip-height: var(--space-3xl);
63
+ --chip-padding-x: 20px;
64
+ }
65
+ .ChipNext_size_l {
66
+ font: var(--typography-text-l-font);
67
+ letter-spacing: var(--typography-text-l-letter_spacing, 0);
68
+ text-transform: var(--typography-text-l-text_transform, none);
69
+
70
+ --chip-min-width: 88px;
71
+ --chip-height: var(--space-4xl);
72
+ --chip-padding-x: var(--space-xl);
73
+ }
74
+ .ChipNext_color_primary {
75
+ --chip-bg-color: var(--color-background-action-light);
76
+ --chip-bg-color-hover: var(--color-background-action-light-hover);
77
+ --chip-bg-color-active: var(--color-background-action-light-pressed);
78
+ --chip-text-color: var(--color-content-action-dark);
79
+ }
80
+ .ChipNext_color_secondary {
81
+ --chip-bg-color: var(--color-background-secondary);
82
+ --chip-bg-color-hover: var(--color-background-secondary-hover);
83
+ --chip-bg-color-active: var(--color-background-secondary-pressed);
84
+ --chip-text-color: var(--color-content-primary);
85
+ }
86
+ .ChipNext:hover {
87
+ --chip-bg-color: var(--chip-bg-color-hover);
88
+ }
89
+ .ChipNext:active {
90
+ --chip-bg-color: var(--chip-bg-color-active);
91
+ }
92
+ .ChipNext:focus {
93
+ box-shadow: var(--shadow-outline-focused);
94
+ }
95
+ .ChipNext:focus:not(:focus-visible) {
96
+ box-shadow: none;
97
+ }
98
+ .ChipNext_checked,
99
+ .ChipNext_checked:hover,
100
+ .ChipNext_checked:active {
101
+ --chip-bg-color: var(--color-background-action);
102
+ --chip-text-color: var(--color-content-action-on);
103
+ }
104
+ .ChipNext_disabled {
105
+ --chip-bg-color: var(--color-background-disabled);
106
+ --chip-text-color: var(--color-content-disabled);
107
+ pointer-events: none;
108
+ }
@@ -0,0 +1,42 @@
1
+ import './Chip.css';
2
+ import type { ReactNode, MouseEvent, ElementType } from 'react';
3
+ import type { IconProps, IconSize } from '@ozen-ui/icons';
4
+ import type { PolymorphicComponentPropsWithRef } from '../../utils/polymorphicComponentWithRef';
5
+ import type { RenderContentType } from '../../utils/renderContent';
6
+ import { CHIP_DEFAULT_TAG } from './constants';
7
+ export declare const cnChip: import("@bem-react/classname").ClassNameFormatter;
8
+ export declare const chipSizeVariant: readonly ["xs", "s", "m", "l"];
9
+ export declare const chipColorVariant: readonly ["primary", "secondary"];
10
+ export type ChipSizeVariant = (typeof chipSizeVariant)[number];
11
+ export type ChipColorVariant = (typeof chipColorVariant)[number];
12
+ export type ChipIcon = RenderContentType<IconProps & {
13
+ size?: IconSize;
14
+ }>['content'];
15
+ export type ChipBaseProps = {
16
+ /** Размер компонента */
17
+ size?: ChipSizeVariant;
18
+ /** Вариант представления компонента */
19
+ color?: ChipColorVariant;
20
+ /** Если {true} компонент отображается как заблокированный */
21
+ disabled?: boolean;
22
+ /** Если {true} делает элемент выбранным */
23
+ checked?: boolean;
24
+ /** Обработчик нажатия */
25
+ onClick?: (e: MouseEvent<HTMLElement>, payload: {
26
+ checked: boolean;
27
+ }) => void;
28
+ /** Иконка слева */
29
+ iconLeft?: ChipIcon;
30
+ /** Иконка справа */
31
+ iconRight?: ChipIcon;
32
+ /** Если {true} разбивает длинный текст на несколько строк */
33
+ multiline?: boolean;
34
+ /** Дополнительные СSS-классы */
35
+ className?: string;
36
+ /** Содержимое компонента */
37
+ children?: ReactNode;
38
+ /** Идентификатор компонента для тестов */
39
+ 'data-testid'?: string;
40
+ };
41
+ export type ChipProps<As extends ElementType = typeof CHIP_DEFAULT_TAG> = PolymorphicComponentPropsWithRef<ChipBaseProps, As>;
42
+ export declare const Chip: import("../../utils/polymorphicComponentWithRef").PolymorphicComponentWithRef<ChipBaseProps, "button">;
@@ -0,0 +1,43 @@
1
+ import { __assign, __read, __rest } from "tslib";
2
+ import './Chip.css';
3
+ import React from 'react';
4
+ import { useControlled } from '../../hooks/useControlled';
5
+ import { useThemeProps } from '../../hooks/useThemeProps';
6
+ import { cn } from '../../utils/classname';
7
+ import { getIconSizeToFormElement } from '../../utils/getIconSizeToFormElement';
8
+ import { polymorphicComponentWithRef } from '../../utils/polymorphicComponentWithRef';
9
+ import { renderContent } from '../../utils/renderContent';
10
+ import { CHIP_DEFAULT_TAG, CHIP_DEFAULT_SIZE, CHIP_DEFAULT_VARIANT, CHIP_DEFAULT_DISABLED, } from './constants';
11
+ export var cnChip = cn('ChipNext');
12
+ export var chipSizeVariant = ['xs', 's', 'm', 'l'];
13
+ export var chipColorVariant = ['primary', 'secondary'];
14
+ export var Chip = polymorphicComponentWithRef(function (inProps, ref) {
15
+ var _a = useThemeProps({ name: 'ChipNext', props: inProps }), _b = _a.size, size = _b === void 0 ? CHIP_DEFAULT_SIZE : _b, _c = _a.color, color = _c === void 0 ? CHIP_DEFAULT_VARIANT : _c, _d = _a.disabled, disabled = _d === void 0 ? CHIP_DEFAULT_DISABLED : _d, iconLeft = _a.iconLeft, iconRight = _a.iconRight, multiline = _a.multiline, className = _a.className, children = _a.children, onClick = _a.onClick, checkedProp = _a.checked, _e = _a.as, Tag = _e === void 0 ? CHIP_DEFAULT_TAG : _e, dataTestId = _a["data-testid"], other = __rest(_a, ["size", "color", "disabled", "iconLeft", "iconRight", "multiline", "className", "children", "onClick", "checked", "as", 'data-testid']);
16
+ var _f = __read(useControlled({
17
+ value: checkedProp,
18
+ defaultValue: false,
19
+ name: 'ChipNext',
20
+ state: 'open',
21
+ }), 2), checkedState = _f[0], setCheckedState = _f[1];
22
+ var handleClick = function (event) {
23
+ if (disabled) {
24
+ return;
25
+ }
26
+ setCheckedState(!checkedState);
27
+ onClick === null || onClick === void 0 ? void 0 : onClick(event, { checked: !checkedState });
28
+ };
29
+ var renderIcon = function (content) {
30
+ return renderContent({
31
+ content: content,
32
+ props: {
33
+ size: getIconSizeToFormElement(size),
34
+ className: cnChip('Icon'),
35
+ },
36
+ });
37
+ };
38
+ return (React.createElement(Tag, __assign({ type: "button", "data-testid": dataTestId, disabled: disabled }, other, { className: cnChip({ size: size, disabled: disabled, color: color, multiline: multiline, checked: checkedState }, [className]), onClick: handleClick, ref: ref }),
39
+ renderIcon(iconLeft),
40
+ children && React.createElement("span", { className: cnChip('Content') }, children),
41
+ renderIcon(iconRight)));
42
+ });
43
+ Chip.displayName = 'Chip';
@@ -0,0 +1,4 @@
1
+ export declare const CHIP_DEFAULT_TAG = "button";
2
+ export declare const CHIP_DEFAULT_VARIANT = "primary";
3
+ export declare const CHIP_DEFAULT_SIZE = "m";
4
+ export declare const CHIP_DEFAULT_DISABLED = false;
@@ -0,0 +1,4 @@
1
+ export var CHIP_DEFAULT_TAG = 'button';
2
+ export var CHIP_DEFAULT_VARIANT = 'primary';
3
+ export var CHIP_DEFAULT_SIZE = 'm';
4
+ export var CHIP_DEFAULT_DISABLED = false;
@@ -0,0 +1 @@
1
+ export * from './Chip';
@@ -0,0 +1 @@
1
+ export * from './Chip';
@@ -1,18 +1,15 @@
1
1
  import './FieldIcon.css';
2
- import type { ComponentPropsWithRef, ComponentRef, FC, ReactElement } from 'react';
2
+ import type { ComponentPropsWithRef, ComponentRef } from 'react';
3
3
  import React from 'react';
4
4
  import type { IconProps, IconSize } from '@ozen-ui/icons';
5
5
  import type { FormElementSizeVariant } from '../../types/FormElementSizeVariant';
6
+ import type { RenderContentType } from '../../utils/renderContent';
6
7
  export declare const FIELD_ICON_DEFAULT_TAG = "div";
7
8
  export type FieldIconRef = ComponentRef<typeof FIELD_ICON_DEFAULT_TAG>;
8
9
  export type FieldIconProps = ComponentPropsWithRef<typeof FIELD_ICON_DEFAULT_TAG> & {
9
- icon?: string | ReactElement<IconProps & {
10
+ icon?: RenderContentType<IconProps & {
10
11
  size?: IconSize;
11
- }> | (() => ReactElement<IconProps & {
12
- size?: IconSize;
13
- }>) | FC<IconProps & {
14
- size?: IconSize;
15
- }>;
12
+ }>['content'];
16
13
  size?: FormElementSizeVariant;
17
14
  children?: never;
18
15
  };
@@ -1,31 +1,12 @@
1
1
  import { __assign, __read, __rest } from "tslib";
2
2
  import './FieldIcon.css';
3
3
  import React, { forwardRef, useContext } from 'react';
4
- import { isValidElementType, isElement } from 'react-is';
5
4
  import { cn } from '../../utils/classname';
6
5
  import { getIconSizeToFormElement } from '../../utils/getIconSizeToFormElement';
6
+ import { renderContent } from '../../utils/renderContent';
7
7
  import { FieldControlContext } from '../FieldControl';
8
8
  export var FIELD_ICON_DEFAULT_TAG = 'div';
9
9
  export var cnFieldIcon = cn('FieldIcon');
10
- // TODO: взять за основу для всех рендер-функций
11
- var resolveChildren = function (content, size) {
12
- if (typeof content === 'string') {
13
- return content;
14
- }
15
- if (isElement(content)) {
16
- return React.cloneElement(content, {
17
- size: content.props.size || (size && getIconSizeToFormElement(size)),
18
- });
19
- }
20
- if (typeof content === 'function' && !React.isValidElement(content)) {
21
- return content({ size: size && getIconSizeToFormElement(size) });
22
- }
23
- if (isValidElementType(content)) {
24
- var Content = content;
25
- return React.createElement(Content, { size: size && getIconSizeToFormElement(size) });
26
- }
27
- return null;
28
- };
29
10
  export var FieldIcon = forwardRef(function (_a, ref) {
30
11
  var icon = _a.icon, className = _a.className, sizeProp = _a.size, other = __rest(_a, ["icon", "className", "size"]);
31
12
  var context = useContext(FieldControlContext);
@@ -40,6 +21,9 @@ export var FieldIcon = forwardRef(function (_a, ref) {
40
21
  size = fieldControl.size;
41
22
  }
42
23
  }
43
- return (React.createElement(Tag, __assign({ className: cnFieldIcon({ size: size }, [className]) }, other, { ref: ref }), resolveChildren(icon, size)));
24
+ return (React.createElement(Tag, __assign({ className: cnFieldIcon({ size: size }, [className]) }, other, { ref: ref }), renderContent({
25
+ content: icon,
26
+ props: { size: size && getIconSizeToFormElement(size) },
27
+ })));
44
28
  });
45
29
  FieldIcon.displayName = 'FieldIcon';
@@ -8,6 +8,7 @@
8
8
  gap: var(--list-gap);
9
9
  padding: var(--list-gutter) 0;
10
10
  margin: 0;
11
+ position: relative;
11
12
  outline: none;
12
13
  }
13
14
 
@@ -27,7 +27,6 @@
27
27
  background: transparent;
28
28
  }
29
29
  .Menu {
30
- scroll-behavior: smooth;
31
30
  overflow: hidden auto;
32
31
  max-block-size: 40vb;
33
32
  }
@@ -9,14 +9,14 @@ import { LIST_ITEM_BUTTON_DEFAULT_TAG } from '../../../List/constants';
9
9
  export var cnMenuItem = cn('MenuItem');
10
10
  export var MenuItem = polymorphicComponentWithRef(function (inProps, ref) {
11
11
  var props = useThemeProps({ props: inProps, name: 'MenuItem' });
12
- var children = props.children, selected = props.selected, value = props.value, label = props.label, _a = props.autoFocus, autoFocus = _a === void 0 ? false : _a, className = props.className, _b = props.as, Tag = _b === void 0 ? LIST_ITEM_BUTTON_DEFAULT_TAG : _b, other = __rest(props, ["children", "selected", "value", "label", "autoFocus", "className", "as"]);
12
+ var children = props.children, selected = props.selected, value = props.value, label = props.label, _a = props.autoFocus, autoFocus = _a === void 0 ? false : _a, disabled = props.disabled, className = props.className, _b = props.as, Tag = _b === void 0 ? LIST_ITEM_BUTTON_DEFAULT_TAG : _b, other = __rest(props, ["children", "selected", "value", "label", "autoFocus", "disabled", "className", "as"]);
13
13
  var innerRef = useRef(null);
14
14
  useEffect(function () {
15
15
  var _a;
16
- if (autoFocus) {
16
+ if (autoFocus && !disabled) {
17
17
  (_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
18
18
  }
19
- }, [autoFocus]);
20
- return (React.createElement(ListItemButton, __assign({ role: "menuitem", as: Tag }, other, { ref: useMultiRef([ref, innerRef]), className: cnListItemButton({ selected: selected }, [className, cnMenuItem()]), "data-value": value, "data-label": label }), children));
19
+ }, [autoFocus, disabled]);
20
+ return (React.createElement(ListItemButton, __assign({ role: "menuitem", as: Tag, disabled: disabled }, other, { ref: useMultiRef([ref, innerRef]), className: cnListItemButton({ selected: selected }, [className, cnMenuItem()]), "data-value": value, "data-label": label }), children));
21
21
  });
22
22
  MenuItem.displayName = 'MenuItem';
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { ListProps } from '../../../List';
3
3
  export type MenuListProps = {
4
- /** Если {true} устанавливает автофокус на первый или выбранный элемент в списке */
4
+ /** Если {true} устанавливает автофокус на первый активный элемент в списке */
5
5
  autoFocus?: boolean;
6
- } & ListProps;
6
+ } & ListProps<'div'>;
7
7
  export declare const MenuList: React.ForwardRefExoticComponent<Omit<MenuListProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
@@ -1,63 +1,81 @@
1
- import { __assign, __rest } from "tslib";
2
- import React, { forwardRef, useRef, isValidElement, Children } from 'react';
1
+ import { __assign, __read, __rest } from "tslib";
2
+ import React, { forwardRef, isValidElement, Children, useRef, useState, } from 'react';
3
3
  import { isFragment } from 'react-is';
4
4
  import { useMultiRef } from '../../../../hooks/useMultiRef';
5
5
  import { useThemeProps } from '../../../../hooks/useThemeProps';
6
+ import { setRef } from '../../../../utils/setRef';
6
7
  import { List } from '../../../List';
7
8
  import { useMenuFocusList } from '../../useMenuFocusList';
8
9
  import { MenuItem } from '../MenuItem';
10
+ var isNotSelectOption = function (child) {
11
+ return !isValidElement(child) || (child === null || child === void 0 ? void 0 : child.type) !== MenuItem || !!child.props.disabled;
12
+ };
9
13
  export var MenuList = forwardRef(function (inProps, ref) {
10
14
  var props = useThemeProps({ props: inProps, name: 'MenuList' });
11
- var children = props.children, _a = props.autoFocus, autoFocus = _a === void 0 ? false : _a, other = __rest(props, ["children", "autoFocus"]);
12
- var nodesRef = useRef([]);
13
- var onKeyDown = useMenuFocusList(nodesRef.current).onKeyDown;
15
+ var _a = props.autoFocus, autoFocus = _a === void 0 ? false : _a, children = props.children, onMouseDownProp = props.onMouseDown, other = __rest(props, ["autoFocus", "children", "onMouseDown"]);
16
+ var listRef = useRef(null);
17
+ var _b = __read(useState({}), 2), nodes = _b[0], setNodes = _b[1];
18
+ var onKeyDown = useMenuFocusList(Object.values(nodes)).onKeyDown;
14
19
  var activeItemIndex = -1;
20
+ var focusedItemIndex = -1;
15
21
  var resolvedChildren = isFragment(children)
16
22
  ? children.props.children
17
23
  : children;
18
24
  Children.forEach(resolvedChildren, function (child, index) {
19
- if (!isValidElement(child) ||
20
- (child === null || child === void 0 ? void 0 : child.type) !== MenuItem ||
21
- child.props.disabled) {
25
+ if (isNotSelectOption(child)) {
22
26
  return;
23
27
  }
24
- if (child.props.selected) {
28
+ if (child.props.autoFocus || child.props.selected) {
25
29
  activeItemIndex = index;
30
+ focusedItemIndex = index;
26
31
  }
27
32
  else if (activeItemIndex === -1) {
28
33
  activeItemIndex = index;
34
+ if (autoFocus) {
35
+ focusedItemIndex = index;
36
+ }
29
37
  }
30
38
  });
31
- return (React.createElement(List, __assign({ role: "menu", as: "div", tabIndex: -1, onClick: function (e) {
32
- var _a;
33
- if (e.target === e.currentTarget) {
34
- (_a = nodesRef.current[0]) === null || _a === void 0 ? void 0 : _a.focus();
35
- }
36
- }, ref: ref }, other), Children.map(resolvedChildren, function (child, index) {
37
- if (!isValidElement(child) ||
38
- (child === null || child === void 0 ? void 0 : child.type) !== MenuItem ||
39
- child.props.disabled) {
39
+ var renderChildren = Children.map(resolvedChildren, function (child, index) {
40
+ if (isNotSelectOption(child)) {
40
41
  return child;
41
42
  }
42
43
  var isActiveElement = activeItemIndex === index;
44
+ var isFocusedElement = focusedItemIndex === index;
43
45
  var elementChild = child;
46
+ var ref = function (ref) {
47
+ setRef(elementChild.ref, ref);
48
+ if (ref) {
49
+ setNodes(function (prevNodes) {
50
+ var _a;
51
+ return (__assign(__assign({}, prevNodes), (_a = {}, _a[index] = ref, _a)));
52
+ });
53
+ }
54
+ else {
55
+ setNodes(function (prevNodes) {
56
+ var obj = __assign({}, prevNodes);
57
+ delete obj[index];
58
+ return obj;
59
+ });
60
+ }
61
+ };
44
62
  var props = {
63
+ ref: ref,
45
64
  tabIndex: isActiveElement ? 0 : -1,
46
- autoFocus: autoFocus && isActiveElement,
65
+ autoFocus: isFocusedElement,
47
66
  onKeyDown: function (event) {
48
67
  var _a, _b;
49
68
  onKeyDown(event);
50
69
  (_b = (_a = child.props).onKeyDown) === null || _b === void 0 ? void 0 : _b.call(_a, event);
51
70
  },
52
71
  };
53
- // eslint-disable-next-line react-hooks/rules-of-hooks
54
- var ref = useMultiRef([
55
- elementChild.ref,
56
- function (ref) {
57
- nodesRef.current.push(ref);
58
- },
59
- ]);
60
- return React.cloneElement(elementChild, __assign(__assign({}, props), { ref: ref }));
61
- })));
72
+ return React.cloneElement(elementChild, __assign({}, props));
73
+ });
74
+ return (React.createElement(List, __assign({ onMouseDown: function (event) {
75
+ if (event.target === listRef.current) {
76
+ event.preventDefault();
77
+ }
78
+ onMouseDownProp === null || onMouseDownProp === void 0 ? void 0 : onMouseDownProp(event);
79
+ }, role: "menu", as: "div", tabIndex: -1, ref: useMultiRef([ref, listRef]) }, other), renderChildren));
62
80
  });
63
81
  MenuList.displayName = 'MenuList';
@@ -2,17 +2,27 @@ import { useCallback, useEffect, useRef } from 'react';
2
2
  import { getNextIndex } from '../../utils/getNextIndex';
3
3
  import { getPrevIndex } from '../../utils/getPrevIndex';
4
4
  import { isKey } from '../../utils/isKey';
5
+ import { isKeys } from '../../utils/isKeys';
5
6
  export function useMenuFocusList(nodes) {
6
7
  var savedNodes = useRef(nodes);
7
8
  useEffect(function () {
8
9
  savedNodes.current = nodes;
9
10
  }, [nodes]);
10
11
  var onKeyDown = useCallback(function (event) {
11
- if (!isKey(event, 'ArrowUp') && !isKey(event, 'ArrowDown')) {
12
+ var _a, _b;
13
+ if (!isKeys(event, ['ArrowUp', 'ArrowDown', 'Home', 'End'])) {
12
14
  return;
13
15
  }
14
16
  event.preventDefault();
15
17
  var items = savedNodes.current;
18
+ if (isKey(event, 'Home')) {
19
+ (_a = items === null || items === void 0 ? void 0 : items[0]) === null || _a === void 0 ? void 0 : _a.focus();
20
+ return;
21
+ }
22
+ if (isKey(event, 'End')) {
23
+ (_b = items === null || items === void 0 ? void 0 : items[items.length - 1]) === null || _b === void 0 ? void 0 : _b.focus();
24
+ return;
25
+ }
16
26
  var currentEl = event.target;
17
27
  var currentIndex = items.indexOf(currentEl);
18
28
  var newIndex = isKey(event, 'ArrowUp')