@ozen-ui/kit 0.17.0-canary.0 → 0.18.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 (27) hide show
  1. package/__inner__/cjs/components/List/List.css +1 -0
  2. package/__inner__/cjs/components/Menu/Menu.css +0 -1
  3. package/__inner__/cjs/components/Menu/components/MenuItem/MenuItem.js +4 -4
  4. package/__inner__/cjs/components/Menu/components/MenuList/MenuList.d.ts +2 -2
  5. package/__inner__/cjs/components/Menu/components/MenuList/MenuList.js +44 -26
  6. package/__inner__/cjs/components/Menu/useMenuFocusList.js +11 -1
  7. package/__inner__/cjs/components/Select/Select.js +2 -5
  8. package/__inner__/cjs/hooks/useFocusList/useFocusList.js +10 -1
  9. package/__inner__/cjs/hooks/useMultiRef/useMultiRef.js +2 -7
  10. package/__inner__/cjs/utils/isKeys.d.ts +3 -0
  11. package/__inner__/cjs/utils/isKeys.js +6 -0
  12. package/__inner__/cjs/utils/setRef.d.ts +4 -0
  13. package/__inner__/cjs/utils/setRef.js +13 -0
  14. package/__inner__/esm/components/List/List.css +1 -0
  15. package/__inner__/esm/components/Menu/Menu.css +0 -1
  16. package/__inner__/esm/components/Menu/components/MenuItem/MenuItem.js +4 -4
  17. package/__inner__/esm/components/Menu/components/MenuList/MenuList.d.ts +2 -2
  18. package/__inner__/esm/components/Menu/components/MenuList/MenuList.js +46 -28
  19. package/__inner__/esm/components/Menu/useMenuFocusList.js +11 -1
  20. package/__inner__/esm/components/Select/Select.js +2 -5
  21. package/__inner__/esm/hooks/useFocusList/useFocusList.js +10 -1
  22. package/__inner__/esm/hooks/useMultiRef/useMultiRef.js +2 -7
  23. package/__inner__/esm/utils/isKeys.d.ts +3 -0
  24. package/__inner__/esm/utils/isKeys.js +2 -0
  25. package/__inner__/esm/utils/setRef.d.ts +4 -0
  26. package/__inner__/esm/utils/setRef.js +9 -0
  27. package/package.json +1 -1
@@ -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
  }
@@ -12,14 +12,14 @@ var constants_1 = require("../../../List/constants");
12
12
  exports.cnMenuItem = (0, classname_1.cn)('MenuItem');
13
13
  exports.MenuItem = (0, polymorphicComponentWithRef_1.polymorphicComponentWithRef)(function (inProps, ref) {
14
14
  var props = (0, useThemeProps_1.useThemeProps)({ props: inProps, name: 'MenuItem' });
15
- 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 ? constants_1.LIST_ITEM_BUTTON_DEFAULT_TAG : _b, other = tslib_1.__rest(props, ["children", "selected", "value", "label", "autoFocus", "className", "as"]);
15
+ 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 ? constants_1.LIST_ITEM_BUTTON_DEFAULT_TAG : _b, other = tslib_1.__rest(props, ["children", "selected", "value", "label", "autoFocus", "disabled", "className", "as"]);
16
16
  var innerRef = (0, react_1.useRef)(null);
17
17
  (0, react_1.useEffect)(function () {
18
18
  var _a;
19
- if (autoFocus) {
19
+ if (autoFocus && !disabled) {
20
20
  (_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
21
21
  }
22
- }, [autoFocus]);
23
- return (react_1.default.createElement(List_1.ListItemButton, tslib_1.__assign({ role: "menuitem", as: Tag }, other, { ref: (0, useMultiRef_1.useMultiRef)([ref, innerRef]), className: (0, List_1.cnListItemButton)({ selected: selected }, [className, (0, exports.cnMenuItem)()]), "data-value": value, "data-label": label }), children));
22
+ }, [autoFocus, disabled]);
23
+ return (react_1.default.createElement(List_1.ListItemButton, tslib_1.__assign({ role: "menuitem", as: Tag, disabled: disabled }, other, { ref: (0, useMultiRef_1.useMultiRef)([ref, innerRef]), className: (0, List_1.cnListItemButton)({ selected: selected }, [className, (0, exports.cnMenuItem)()]), "data-value": value, "data-label": label }), children));
24
24
  });
25
25
  exports.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>>;
@@ -6,61 +6,79 @@ var react_1 = tslib_1.__importStar(require("react"));
6
6
  var react_is_1 = require("react-is");
7
7
  var useMultiRef_1 = require("../../../../hooks/useMultiRef");
8
8
  var useThemeProps_1 = require("../../../../hooks/useThemeProps");
9
+ var setRef_1 = require("../../../../utils/setRef");
9
10
  var List_1 = require("../../../List");
10
11
  var useMenuFocusList_1 = require("../../useMenuFocusList");
11
12
  var MenuItem_1 = require("../MenuItem");
13
+ var isNotSelectOption = function (child) {
14
+ return !(0, react_1.isValidElement)(child) || (child === null || child === void 0 ? void 0 : child.type) !== MenuItem_1.MenuItem || !!child.props.disabled;
15
+ };
12
16
  exports.MenuList = (0, react_1.forwardRef)(function (inProps, ref) {
13
17
  var props = (0, useThemeProps_1.useThemeProps)({ props: inProps, name: 'MenuList' });
14
- var children = props.children, _a = props.autoFocus, autoFocus = _a === void 0 ? false : _a, other = tslib_1.__rest(props, ["children", "autoFocus"]);
15
- var nodesRef = (0, react_1.useRef)([]);
16
- var onKeyDown = (0, useMenuFocusList_1.useMenuFocusList)(nodesRef.current).onKeyDown;
18
+ var _a = props.autoFocus, autoFocus = _a === void 0 ? false : _a, children = props.children, onMouseDownProp = props.onMouseDown, other = tslib_1.__rest(props, ["autoFocus", "children", "onMouseDown"]);
19
+ var listRef = (0, react_1.useRef)(null);
20
+ var _b = tslib_1.__read((0, react_1.useState)({}), 2), nodes = _b[0], setNodes = _b[1];
21
+ var onKeyDown = (0, useMenuFocusList_1.useMenuFocusList)(Object.values(nodes)).onKeyDown;
17
22
  var activeItemIndex = -1;
23
+ var focusedItemIndex = -1;
18
24
  var resolvedChildren = (0, react_is_1.isFragment)(children)
19
25
  ? children.props.children
20
26
  : children;
21
27
  react_1.Children.forEach(resolvedChildren, function (child, index) {
22
- if (!(0, react_1.isValidElement)(child) ||
23
- (child === null || child === void 0 ? void 0 : child.type) !== MenuItem_1.MenuItem ||
24
- child.props.disabled) {
28
+ if (isNotSelectOption(child)) {
25
29
  return;
26
30
  }
27
- if (child.props.selected) {
31
+ if (child.props.autoFocus || child.props.selected) {
28
32
  activeItemIndex = index;
33
+ focusedItemIndex = index;
29
34
  }
30
35
  else if (activeItemIndex === -1) {
31
36
  activeItemIndex = index;
37
+ if (autoFocus) {
38
+ focusedItemIndex = index;
39
+ }
32
40
  }
33
41
  });
34
- return (react_1.default.createElement(List_1.List, tslib_1.__assign({ role: "menu", as: "div", tabIndex: -1, onClick: function (e) {
35
- var _a;
36
- if (e.target === e.currentTarget) {
37
- (_a = nodesRef.current[0]) === null || _a === void 0 ? void 0 : _a.focus();
38
- }
39
- }, ref: ref }, other), react_1.Children.map(resolvedChildren, function (child, index) {
40
- if (!(0, react_1.isValidElement)(child) ||
41
- (child === null || child === void 0 ? void 0 : child.type) !== MenuItem_1.MenuItem ||
42
- child.props.disabled) {
42
+ var renderChildren = react_1.Children.map(resolvedChildren, function (child, index) {
43
+ if (isNotSelectOption(child)) {
43
44
  return child;
44
45
  }
45
46
  var isActiveElement = activeItemIndex === index;
47
+ var isFocusedElement = focusedItemIndex === index;
46
48
  var elementChild = child;
49
+ var ref = function (ref) {
50
+ (0, setRef_1.setRef)(elementChild.ref, ref);
51
+ if (ref) {
52
+ setNodes(function (prevNodes) {
53
+ var _a;
54
+ return (tslib_1.__assign(tslib_1.__assign({}, prevNodes), (_a = {}, _a[index] = ref, _a)));
55
+ });
56
+ }
57
+ else {
58
+ setNodes(function (prevNodes) {
59
+ var obj = tslib_1.__assign({}, prevNodes);
60
+ delete obj[index];
61
+ return obj;
62
+ });
63
+ }
64
+ };
47
65
  var props = {
66
+ ref: ref,
48
67
  tabIndex: isActiveElement ? 0 : -1,
49
- autoFocus: autoFocus && isActiveElement,
68
+ autoFocus: isFocusedElement,
50
69
  onKeyDown: function (event) {
51
70
  var _a, _b;
52
71
  onKeyDown(event);
53
72
  (_b = (_a = child.props).onKeyDown) === null || _b === void 0 ? void 0 : _b.call(_a, event);
54
73
  },
55
74
  };
56
- // eslint-disable-next-line react-hooks/rules-of-hooks
57
- var ref = (0, useMultiRef_1.useMultiRef)([
58
- elementChild.ref,
59
- function (ref) {
60
- nodesRef.current.push(ref);
61
- },
62
- ]);
63
- return react_1.default.cloneElement(elementChild, tslib_1.__assign(tslib_1.__assign({}, props), { ref: ref }));
64
- })));
75
+ return react_1.default.cloneElement(elementChild, tslib_1.__assign({}, props));
76
+ });
77
+ return (react_1.default.createElement(List_1.List, tslib_1.__assign({ onMouseDown: function (event) {
78
+ if (event.target === listRef.current) {
79
+ event.preventDefault();
80
+ }
81
+ onMouseDownProp === null || onMouseDownProp === void 0 ? void 0 : onMouseDownProp(event);
82
+ }, role: "menu", as: "div", tabIndex: -1, ref: (0, useMultiRef_1.useMultiRef)([ref, listRef]) }, other), renderChildren));
65
83
  });
66
84
  exports.MenuList.displayName = 'MenuList';
@@ -5,17 +5,27 @@ 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
  function useMenuFocusList(nodes) {
9
10
  var savedNodes = (0, react_1.useRef)(nodes);
10
11
  (0, react_1.useEffect)(function () {
11
12
  savedNodes.current = nodes;
12
13
  }, [nodes]);
13
14
  var onKeyDown = (0, react_1.useCallback)(function (event) {
14
- if (!(0, isKey_1.isKey)(event, 'ArrowUp') && !(0, isKey_1.isKey)(event, 'ArrowDown')) {
15
+ var _a, _b;
16
+ if (!(0, isKeys_1.isKeys)(event, ['ArrowUp', 'ArrowDown', 'Home', 'End'])) {
15
17
  return;
16
18
  }
17
19
  event.preventDefault();
18
20
  var items = savedNodes.current;
21
+ if ((0, isKey_1.isKey)(event, 'Home')) {
22
+ (_a = items === null || items === void 0 ? void 0 : items[0]) === null || _a === void 0 ? void 0 : _a.focus();
23
+ return;
24
+ }
25
+ if ((0, isKey_1.isKey)(event, 'End')) {
26
+ (_b = items === null || items === void 0 ? void 0 : items[items.length - 1]) === null || _b === void 0 ? void 0 : _b.focus();
27
+ return;
28
+ }
19
29
  var currentEl = event.target;
20
30
  var currentIndex = items.indexOf(currentEl);
21
31
  var newIndex = (0, isKey_1.isKey)(event, 'ArrowUp')
@@ -9,7 +9,7 @@ var useControlled_1 = require("../../hooks/useControlled");
9
9
  var useMultiRef_1 = require("../../hooks/useMultiRef");
10
10
  var useThemeProps_1 = require("../../hooks/useThemeProps");
11
11
  var classname_1 = require("../../utils/classname");
12
- var isKey_1 = require("../../utils/isKey");
12
+ var isKeys_1 = require("../../utils/isKeys");
13
13
  var DataList_1 = require("../DataList");
14
14
  var components_1 = require("./components");
15
15
  var constants_1 = require("./constants");
@@ -93,10 +93,7 @@ var SelectRender = function (inProps, ref) {
93
93
  };
94
94
  /** Управление элементом контроля через клавиатуру */
95
95
  var handleKeyDown = function (event) {
96
- if (((0, isKey_1.isKey)(event, 'Space') ||
97
- (0, isKey_1.isKey)(event, 'ArrowDown') ||
98
- (0, isKey_1.isKey)(event, 'ArrowUp')) &&
99
- !open) {
96
+ if ((0, isKeys_1.isKeys)(event, ['Space', 'ArrowDown', 'ArrowUp']) && !open) {
100
97
  event.preventDefault();
101
98
  handleToggle();
102
99
  }
@@ -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,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;
@@ -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')
@@ -6,7 +6,7 @@ import { useControlled } from '../../hooks/useControlled';
6
6
  import { useMultiRef } from '../../hooks/useMultiRef';
7
7
  import { useThemeProps } from '../../hooks/useThemeProps';
8
8
  import { cn } from '../../utils/classname';
9
- import { isKey } from '../../utils/isKey';
9
+ import { isKeys } from '../../utils/isKeys';
10
10
  import { DataList, DataListOption } from '../DataList';
11
11
  import { SelectInput } from './components';
12
12
  import { SELECT_DEFAULT_AUTO_FOCUS, SELECT_DEFAULT_DEFAULT_OPEN, SELECT_DEFAULT_DISABLED, SELECT_DEFAULT_FULL_WIDTH, SELECT_DEFAULT_MULTILINE, SELECT_DEFAULT_REQUIRED, SELECT_DEFAULT_SIZE, } from './constants';
@@ -90,10 +90,7 @@ var SelectRender = function (inProps, ref) {
90
90
  };
91
91
  /** Управление элементом контроля через клавиатуру */
92
92
  var handleKeyDown = function (event) {
93
- if ((isKey(event, 'Space') ||
94
- isKey(event, 'ArrowDown') ||
95
- isKey(event, 'ArrowUp')) &&
96
- !open) {
93
+ if (isKeys(event, ['Space', 'ArrowDown', 'ArrowUp']) && !open) {
97
94
  event.preventDefault();
98
95
  handleToggle();
99
96
  }
@@ -2,15 +2,24 @@ import { useCallback } 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
  import { useUniqueId } from '../useUniqueId';
6
7
  export function useFocusList() {
7
8
  var name = useUniqueId();
8
9
  var onKeyDown = useCallback(function (event) {
9
- if (!isKey(event, 'ArrowUp') && !isKey(event, 'ArrowDown')) {
10
+ if (!isKeys(event, ['ArrowUp', 'ArrowDown', 'Home', 'End'])) {
10
11
  return;
11
12
  }
12
13
  event.preventDefault();
13
14
  var items = document.querySelectorAll("[data-focus-list=\"".concat(name, "\"]"));
15
+ if (isKey(event, 'Home')) {
16
+ items.item(0).focus();
17
+ return;
18
+ }
19
+ if (isKey(event, 'Home')) {
20
+ items.item(items.length - 1).focus();
21
+ return;
22
+ }
14
23
  var currentEl = event.target;
15
24
  var currentIndex = Array.from(items).indexOf(currentEl);
16
25
  var newIndex = isKey(event, 'ArrowUp')
@@ -1,4 +1,5 @@
1
1
  import { useMemo, useRef } from 'react';
2
+ import { setRef } from '../../utils/setRef';
2
3
  /** Создает несколько ссылок (ref) на один DOM-элемент. */
3
4
  export function useMultiRef(refs) {
4
5
  // Мемоизирует массив ref'ов
@@ -9,13 +10,7 @@ export function useMultiRef(refs) {
9
10
  }
10
11
  return function (node) {
11
12
  arrRefs.current.forEach(function (ref) {
12
- if (typeof ref === 'function') {
13
- ref(node);
14
- }
15
- else if (ref) {
16
- // eslint-disable-next-line no-param-reassign
17
- ref.current = node;
18
- }
13
+ setRef(ref, node);
19
14
  });
20
15
  };
21
16
  }, [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,2 @@
1
+ import { isKey } from './isKey';
2
+ export var isKeys = function (event, keys) { return keys.some(function (key) { return isKey(event, key); }); };
@@ -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,9 @@
1
+ export var setRef = function (ref, value) {
2
+ if (typeof ref === 'function') {
3
+ ref(value);
4
+ }
5
+ else if (ref) {
6
+ // eslint-disable-next-line no-param-reassign
7
+ ref.current = value;
8
+ }
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ozen-ui/kit",
3
- "version": "0.17.0-canary.0",
3
+ "version": "0.18.0",
4
4
  "description": "React component library",
5
5
  "files": [
6
6
  "*"