123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- "use strict";
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
- var _typeof = require("@babel/runtime/helpers/typeof");
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.getFocusableElements = getFocusableElements;
- exports.refreshElements = void 0;
- exports.useAccessibility = useAccessibility;
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
- var _focus = require("rc-util/lib/Dom/focus");
- var _KeyCode = _interopRequireDefault(require("rc-util/lib/KeyCode"));
- var _raf = _interopRequireDefault(require("rc-util/lib/raf"));
- var React = _interopRequireWildcard(require("react"));
- var _IdContext = require("../context/IdContext");
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
- // destruct to reduce minify size
- var LEFT = _KeyCode.default.LEFT,
- RIGHT = _KeyCode.default.RIGHT,
- UP = _KeyCode.default.UP,
- DOWN = _KeyCode.default.DOWN,
- ENTER = _KeyCode.default.ENTER,
- ESC = _KeyCode.default.ESC,
- HOME = _KeyCode.default.HOME,
- END = _KeyCode.default.END;
- var ArrowKeys = [UP, DOWN, LEFT, RIGHT];
- function getOffset(mode, isRootLevel, isRtl, which) {
- var _offsets;
- var prev = 'prev';
- var next = 'next';
- var children = 'children';
- var parent = 'parent';
- // Inline enter is special that we use unique operation
- if (mode === 'inline' && which === ENTER) {
- return {
- inlineTrigger: true
- };
- }
- var inline = (0, _defineProperty2.default)((0, _defineProperty2.default)({}, UP, prev), DOWN, next);
- var horizontal = (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, LEFT, isRtl ? next : prev), RIGHT, isRtl ? prev : next), DOWN, children), ENTER, children);
- var vertical = (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, UP, prev), DOWN, next), ENTER, children), ESC, parent), LEFT, isRtl ? children : parent), RIGHT, isRtl ? parent : children);
- var offsets = {
- inline: inline,
- horizontal: horizontal,
- vertical: vertical,
- inlineSub: inline,
- horizontalSub: vertical,
- verticalSub: vertical
- };
- var type = (_offsets = offsets["".concat(mode).concat(isRootLevel ? '' : 'Sub')]) === null || _offsets === void 0 ? void 0 : _offsets[which];
- switch (type) {
- case prev:
- return {
- offset: -1,
- sibling: true
- };
- case next:
- return {
- offset: 1,
- sibling: true
- };
- case parent:
- return {
- offset: -1,
- sibling: false
- };
- case children:
- return {
- offset: 1,
- sibling: false
- };
- default:
- return null;
- }
- }
- function findContainerUL(element) {
- var current = element;
- while (current) {
- if (current.getAttribute('data-menu-list')) {
- return current;
- }
- current = current.parentElement;
- }
- // Normally should not reach this line
- /* istanbul ignore next */
- return null;
- }
- /**
- * Find focused element within element set provided
- */
- function getFocusElement(activeElement, elements) {
- var current = activeElement || document.activeElement;
- while (current) {
- if (elements.has(current)) {
- return current;
- }
- current = current.parentElement;
- }
- return null;
- }
- /**
- * Get focusable elements from the element set under provided container
- */
- function getFocusableElements(container, elements) {
- var list = (0, _focus.getFocusNodeList)(container, true);
- return list.filter(function (ele) {
- return elements.has(ele);
- });
- }
- function getNextFocusElement(parentQueryContainer, elements, focusMenuElement) {
- var offset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
- // Key on the menu item will not get validate parent container
- if (!parentQueryContainer) {
- return null;
- }
- // List current level menu item elements
- var sameLevelFocusableMenuElementList = getFocusableElements(parentQueryContainer, elements);
- // Find next focus index
- var count = sameLevelFocusableMenuElementList.length;
- var focusIndex = sameLevelFocusableMenuElementList.findIndex(function (ele) {
- return focusMenuElement === ele;
- });
- if (offset < 0) {
- if (focusIndex === -1) {
- focusIndex = count - 1;
- } else {
- focusIndex -= 1;
- }
- } else if (offset > 0) {
- focusIndex += 1;
- }
- focusIndex = (focusIndex + count) % count;
- // Focus menu item
- return sameLevelFocusableMenuElementList[focusIndex];
- }
- var refreshElements = exports.refreshElements = function refreshElements(keys, id) {
- var elements = new Set();
- var key2element = new Map();
- var element2key = new Map();
- keys.forEach(function (key) {
- var element = document.querySelector("[data-menu-id='".concat((0, _IdContext.getMenuId)(id, key), "']"));
- if (element) {
- elements.add(element);
- element2key.set(element, key);
- key2element.set(key, element);
- }
- });
- return {
- elements: elements,
- key2element: key2element,
- element2key: element2key
- };
- };
- function useAccessibility(mode, activeKey, isRtl, id, containerRef, getKeys, getKeyPath, triggerActiveKey, triggerAccessibilityOpen, originOnKeyDown) {
- var rafRef = React.useRef();
- var activeRef = React.useRef();
- activeRef.current = activeKey;
- var cleanRaf = function cleanRaf() {
- _raf.default.cancel(rafRef.current);
- };
- React.useEffect(function () {
- return function () {
- cleanRaf();
- };
- }, []);
- return function (e) {
- var which = e.which;
- if ([].concat(ArrowKeys, [ENTER, ESC, HOME, END]).includes(which)) {
- var keys = getKeys();
- var refreshedElements = refreshElements(keys, id);
- var _refreshedElements = refreshedElements,
- elements = _refreshedElements.elements,
- key2element = _refreshedElements.key2element,
- element2key = _refreshedElements.element2key;
- // First we should find current focused MenuItem/SubMenu element
- var activeElement = key2element.get(activeKey);
- var focusMenuElement = getFocusElement(activeElement, elements);
- var focusMenuKey = element2key.get(focusMenuElement);
- var offsetObj = getOffset(mode, getKeyPath(focusMenuKey, true).length === 1, isRtl, which);
- // Some mode do not have fully arrow operation like inline
- if (!offsetObj && which !== HOME && which !== END) {
- return;
- }
- // Arrow prevent default to avoid page scroll
- if (ArrowKeys.includes(which) || [HOME, END].includes(which)) {
- e.preventDefault();
- }
- var tryFocus = function tryFocus(menuElement) {
- if (menuElement) {
- var focusTargetElement = menuElement;
- // Focus to link instead of menu item if possible
- var link = menuElement.querySelector('a');
- if (link !== null && link !== void 0 && link.getAttribute('href')) {
- focusTargetElement = link;
- }
- var targetKey = element2key.get(menuElement);
- triggerActiveKey(targetKey);
- /**
- * Do not `useEffect` here since `tryFocus` may trigger async
- * which makes React sync update the `activeKey`
- * that force render before `useRef` set the next activeKey
- */
- cleanRaf();
- rafRef.current = (0, _raf.default)(function () {
- if (activeRef.current === targetKey) {
- focusTargetElement.focus();
- }
- });
- }
- };
- if ([HOME, END].includes(which) || offsetObj.sibling || !focusMenuElement) {
- // ========================== Sibling ==========================
- // Find walkable focus menu element container
- var parentQueryContainer;
- if (!focusMenuElement || mode === 'inline') {
- parentQueryContainer = containerRef.current;
- } else {
- parentQueryContainer = findContainerUL(focusMenuElement);
- }
- // Get next focus element
- var targetElement;
- var focusableElements = getFocusableElements(parentQueryContainer, elements);
- if (which === HOME) {
- targetElement = focusableElements[0];
- } else if (which === END) {
- targetElement = focusableElements[focusableElements.length - 1];
- } else {
- targetElement = getNextFocusElement(parentQueryContainer, elements, focusMenuElement, offsetObj.offset);
- }
- // Focus menu item
- tryFocus(targetElement);
- // ======================= InlineTrigger =======================
- } else if (offsetObj.inlineTrigger) {
- // Inline trigger no need switch to sub menu item
- triggerAccessibilityOpen(focusMenuKey);
- // =========================== Level ===========================
- } else if (offsetObj.offset > 0) {
- triggerAccessibilityOpen(focusMenuKey, true);
- cleanRaf();
- rafRef.current = (0, _raf.default)(function () {
- // Async should resync elements
- refreshedElements = refreshElements(keys, id);
- var controlId = focusMenuElement.getAttribute('aria-controls');
- var subQueryContainer = document.getElementById(controlId);
- // Get sub focusable menu item
- var targetElement = getNextFocusElement(subQueryContainer, refreshedElements.elements);
- // Focus menu item
- tryFocus(targetElement);
- }, 5);
- } else if (offsetObj.offset < 0) {
- var keyPath = getKeyPath(focusMenuKey, true);
- var parentKey = keyPath[keyPath.length - 2];
- var parentMenuElement = key2element.get(parentKey);
- // Focus menu item
- triggerAccessibilityOpen(parentKey, false);
- tryFocus(parentMenuElement);
- }
- }
- // Pass origin key down event
- originOnKeyDown === null || originOnKeyDown === void 0 || originOnKeyDown(e);
- };
- }
|