UNPKG

rsuite

Version:

A suite of react components

246 lines (238 loc) 10.1 kB
'use client'; "use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _react = require("react"); var _isFunction = _interopRequireDefault(require("lodash/isFunction")); var _isUndefined = _interopRequireDefault(require("lodash/isUndefined")); var _find = _interopRequireDefault(require("lodash/find")); var _domLib = require("dom-lib"); var _hooks = require("../../hooks"); var _utils = require("../../utils"); var _utils2 = require("../../Tree/utils"); var _utils3 = require("../utils"); /** * A hook that manages the focus state of the option. * @param defaultFocusItemValue * @param props */ var useFocusItemValue = function useFocusItemValue(defaultFocusItemValue, props) { var _props$valueKey = props.valueKey, valueKey = _props$valueKey === void 0 ? 'value' : _props$valueKey, _props$focusableQuery = props.focusableQueryKey, focusableQueryKey = _props$focusableQuery === void 0 ? '[data-key][aria-disabled="false"]' : _props$focusableQuery, _props$defaultLayer = props.defaultLayer, defaultLayer = _props$defaultLayer === void 0 ? 0 : _props$defaultLayer, _props$focusToOption = props.focusToOption, focusToOption = _props$focusToOption === void 0 ? true : _props$focusToOption, data = props.data, target = props.target, rtl = props.rtl, callback = props.callback, _props$getParent = props.getParent, getParent = _props$getParent === void 0 ? function (item) { return item === null || item === void 0 ? void 0 : item.parent; } : _props$getParent; var _useState = (0, _react.useState)(defaultFocusItemValue), focusItemValue = _useState[0], setFocusItemValue = _useState[1]; var _useState2 = (0, _react.useState)(defaultLayer), layer = _useState2[0], setLayer = _useState2[1]; var _useState3 = (0, _react.useState)([]), keys = _useState3[0], setKeys = _useState3[1]; var focusCallback = (0, _hooks.useEventCallback)(function (value, event) { if (focusToOption) { var menu = (0, _isFunction.default)(target) ? target() : target; var focusElement = menu === null || menu === void 0 ? void 0 : menu.querySelector("[data-key=\"" + value + "\"]"); focusElement === null || focusElement === void 0 || focusElement.focus(); } callback === null || callback === void 0 || callback(value, event); }); var getScrollContainer = (0, _hooks.useEventCallback)(function () { var menu = (0, _isFunction.default)(target) ? target() : target; // For Cascader and MutiCascader var subMenu = menu === null || menu === void 0 ? void 0 : menu.querySelector("[data-layer=\"" + layer + "\"]"); if (subMenu) { return subMenu; } // For SelectPicker、CheckPicker、Autocomplete、InputPicker、TagPicker return menu === null || menu === void 0 ? void 0 : menu.querySelector('[role="listbox"]'); }); /** * Get the elements visible in all options. */ var getFocusableMenuItems = function getFocusableMenuItems() { if (!target) { return []; } var currentKeys = keys; if (layer < 1) { var popup = (0, _isFunction.default)(target) ? target() : target; var rootMenu = popup === null || popup === void 0 ? void 0 : popup.querySelector('[data-layer="0"]'); if (rootMenu) { var _rootMenu$querySelect; currentKeys = Array.from((_rootMenu$querySelect = rootMenu.querySelectorAll(focusableQueryKey)) !== null && _rootMenu$querySelect !== void 0 ? _rootMenu$querySelect : []).map(function (item) { var _item$dataset; return (_item$dataset = item.dataset) === null || _item$dataset === void 0 ? void 0 : _item$dataset.key; }); } else { var _popup$querySelectorA; currentKeys = Array.from((_popup$querySelectorA = popup === null || popup === void 0 ? void 0 : popup.querySelectorAll(focusableQueryKey)) !== null && _popup$querySelectorA !== void 0 ? _popup$querySelectorA : []).map(function (item) { var _item$dataset2; return (_item$dataset2 = item.dataset) === null || _item$dataset2 === void 0 ? void 0 : _item$dataset2.key; }); } } // 1. It is necessary to traverse the `keys` instead of `data` here to preserve the order of the array. // 2. The values ​​in `keys` are all string, so the corresponding value of `data` should also be converted to string return currentKeys.map(function (key) { return (0, _find.default)(data, function (i) { return "" + i[valueKey] === key; }); }); }; /** * Get the index of the focus item. */ var findFocusItemIndex = (0, _hooks.useEventCallback)(function (callback) { var items = getFocusableMenuItems(); for (var i = 0; i < items.length; i += 1) { var _items$i; if ((0, _utils.shallowEqual)(focusItemValue, (_items$i = items[i]) === null || _items$i === void 0 ? void 0 : _items$i[valueKey])) { callback(items, i); return; } } callback(items, -1); }); var scrollListItem = (0, _hooks.useEventCallback)(function (direction, itemValue, willOverflow) { var container = getScrollContainer(); var item = container === null || container === void 0 ? void 0 : container.querySelector("[data-key=\"" + itemValue + "\"]"); if (willOverflow && container) { var scrollHeight = container.scrollHeight, clientHeight = container.clientHeight; container.scrollTop = direction === 'top' ? scrollHeight - clientHeight : 0; return; } if (item && container) { if (!isVisible(item, container, direction)) { var height = (0, _domLib.getHeight)(item); scrollTo(container, direction, height); } } }); var focusNextMenuItem = (0, _hooks.useEventCallback)(function (event) { findFocusItemIndex(function (items, index) { var willOverflow = index + 2 > items.length; var nextIndex = willOverflow ? 0 : index + 1; var focusItem = items[nextIndex]; if (!(0, _isUndefined.default)(focusItem)) { setFocusItemValue(focusItem[valueKey]); focusCallback(focusItem[valueKey], event); scrollListItem('bottom', focusItem[valueKey], willOverflow); } }); }); var focusPrevMenuItem = (0, _hooks.useEventCallback)(function (event) { findFocusItemIndex(function (items, index) { var willOverflow = index === 0; var nextIndex = willOverflow ? items.length - 1 : index - 1; var focusItem = items[nextIndex]; if (!(0, _isUndefined.default)(focusItem)) { setFocusItemValue(focusItem[valueKey]); focusCallback(focusItem[valueKey], event); scrollListItem('top', focusItem[valueKey], willOverflow); } }); }); var getSubMenuKeys = function getSubMenuKeys(nextLayer) { var menu = (0, _isFunction.default)(target) ? target() : target; var subMenu = menu === null || menu === void 0 ? void 0 : menu.querySelector("[data-layer=\"" + nextLayer + "\"]"); if (subMenu) { var _Array$from; return (_Array$from = Array.from(subMenu.querySelectorAll(focusableQueryKey))) === null || _Array$from === void 0 ? void 0 : _Array$from.map(function (item) { var _item$dataset3; return (_item$dataset3 = item.dataset) === null || _item$dataset3 === void 0 ? void 0 : _item$dataset3.key; }); } return null; }; var focusNextLevelMenu = (0, _hooks.useEventCallback)(function (event) { var nextLayer = layer + 1; var nextKeys = getSubMenuKeys(nextLayer); if (nextKeys) { setKeys(nextKeys); setLayer(nextLayer); setFocusItemValue(nextKeys[0]); focusCallback(nextKeys[0], event); } }); var focusPrevLevelMenu = (0, _hooks.useEventCallback)(function (event) { var nextLayer = layer - 1; var nextKeys = getSubMenuKeys(nextLayer); if (nextKeys) { var _getParent; setKeys(nextKeys); setLayer(nextLayer); var focusItem = (0, _utils2.findNodeOfTree)(data, function (item) { return item[valueKey] === focusItemValue; }); var parentItemValue = (_getParent = getParent(focusItem)) === null || _getParent === void 0 ? void 0 : _getParent[valueKey]; if (parentItemValue) { setFocusItemValue(parentItemValue); focusCallback(parentItemValue, event); } } }); var handleKeyDown = (0, _hooks.useEventCallback)(function (event) { var _onMenuKeyDown; (0, _utils3.onMenuKeyDown)(event, (_onMenuKeyDown = { down: focusNextMenuItem, up: focusPrevMenuItem }, _onMenuKeyDown[rtl ? 'left' : 'right'] = focusNextLevelMenu, _onMenuKeyDown[rtl ? 'right' : 'left'] = focusPrevLevelMenu, _onMenuKeyDown)); }); return { focusItemValue: focusItemValue, setFocusItemValue: setFocusItemValue, layer: layer, setLayer: setLayer, keys: keys, setKeys: setKeys, onKeyDown: handleKeyDown }; }; function scrollTo(container, direction, step) { var scrollTop = container.scrollTop; container.scrollTop = direction === 'top' ? scrollTop - step : scrollTop + step; } /** * Checks if the element has a vertical scrollbar. */ function hasVerticalScroll(element) { var scrollHeight = element.scrollHeight, clientHeight = element.clientHeight; return scrollHeight > clientHeight; } /** * Checks if the element is within the visible area of the container */ function isVisible(element, container, direction) { if (!hasVerticalScroll(container)) { return true; } var _element$getBoundingC = element.getBoundingClientRect(), top = _element$getBoundingC.top, bottom = _element$getBoundingC.bottom, height = _element$getBoundingC.height; var _container$getBoundin = container.getBoundingClientRect(), containerTop = _container$getBoundin.top, containerBottom = _container$getBoundin.bottom; if (direction === 'top') { return top + height > containerTop; } return bottom - height < containerBottom; } var _default = exports.default = useFocusItemValue;