1 | import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
2 | import * as React from 'react';
|
3 | import KeyCode from "rc-util/es/KeyCode";
|
4 | import raf from "rc-util/es/raf";
|
5 | import { getFocusNodeList } from "rc-util/es/Dom/focus";
|
6 | import { getMenuId } from '../context/IdContext';
|
7 |
|
8 | var LEFT = KeyCode.LEFT,
|
9 | RIGHT = KeyCode.RIGHT,
|
10 | UP = KeyCode.UP,
|
11 | DOWN = KeyCode.DOWN,
|
12 | ENTER = KeyCode.ENTER,
|
13 | ESC = KeyCode.ESC;
|
14 | var ArrowKeys = [UP, DOWN, LEFT, RIGHT];
|
15 |
|
16 | function getOffset(mode, isRootLevel, isRtl, which) {
|
17 | var _inline, _horizontal, _vertical, _offsets$;
|
18 |
|
19 | var prev = 'prev';
|
20 | var next = 'next';
|
21 | var children = 'children';
|
22 | var parent = 'parent';
|
23 |
|
24 | if (mode === 'inline' && which === ENTER) {
|
25 | return {
|
26 | inlineTrigger: true
|
27 | };
|
28 | }
|
29 |
|
30 | var inline = (_inline = {}, _defineProperty(_inline, UP, prev), _defineProperty(_inline, DOWN, next), _inline);
|
31 | var horizontal = (_horizontal = {}, _defineProperty(_horizontal, LEFT, isRtl ? next : prev), _defineProperty(_horizontal, RIGHT, isRtl ? prev : next), _defineProperty(_horizontal, DOWN, children), _defineProperty(_horizontal, ENTER, children), _horizontal);
|
32 | var vertical = (_vertical = {}, _defineProperty(_vertical, UP, prev), _defineProperty(_vertical, DOWN, next), _defineProperty(_vertical, ENTER, children), _defineProperty(_vertical, ESC, parent), _defineProperty(_vertical, LEFT, isRtl ? children : parent), _defineProperty(_vertical, RIGHT, isRtl ? parent : children), _vertical);
|
33 | var offsets = {
|
34 | inline: inline,
|
35 | horizontal: horizontal,
|
36 | vertical: vertical,
|
37 | inlineSub: inline,
|
38 | horizontalSub: vertical,
|
39 | verticalSub: vertical
|
40 | };
|
41 | var type = (_offsets$ = offsets["".concat(mode).concat(isRootLevel ? '' : 'Sub')]) === null || _offsets$ === void 0 ? void 0 : _offsets$[which];
|
42 |
|
43 | switch (type) {
|
44 | case prev:
|
45 | return {
|
46 | offset: -1,
|
47 | sibling: true
|
48 | };
|
49 |
|
50 | case next:
|
51 | return {
|
52 | offset: 1,
|
53 | sibling: true
|
54 | };
|
55 |
|
56 | case parent:
|
57 | return {
|
58 | offset: -1,
|
59 | sibling: false
|
60 | };
|
61 |
|
62 | case children:
|
63 | return {
|
64 | offset: 1,
|
65 | sibling: false
|
66 | };
|
67 |
|
68 | default:
|
69 | return null;
|
70 | }
|
71 | }
|
72 |
|
73 | function findContainerUL(element) {
|
74 | var current = element;
|
75 |
|
76 | while (current) {
|
77 | if (current.getAttribute('data-menu-list')) {
|
78 | return current;
|
79 | }
|
80 |
|
81 | current = current.parentElement;
|
82 | }
|
83 |
|
84 |
|
85 |
|
86 |
|
87 | return null;
|
88 | }
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 | function getFocusElement(activeElement, elements) {
|
95 | var current = activeElement || document.activeElement;
|
96 |
|
97 | while (current) {
|
98 | if (elements.has(current)) {
|
99 | return current;
|
100 | }
|
101 |
|
102 | current = current.parentElement;
|
103 | }
|
104 |
|
105 | return null;
|
106 | }
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 | function getFocusableElements(container, elements) {
|
113 | var list = getFocusNodeList(container, true);
|
114 | return list.filter(function (ele) {
|
115 | return elements.has(ele);
|
116 | });
|
117 | }
|
118 |
|
119 | function getNextFocusElement(parentQueryContainer, elements, focusMenuElement) {
|
120 | var offset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
|
121 |
|
122 |
|
123 | if (!parentQueryContainer) {
|
124 | return null;
|
125 | }
|
126 |
|
127 |
|
128 | var sameLevelFocusableMenuElementList = getFocusableElements(parentQueryContainer, elements);
|
129 |
|
130 | var count = sameLevelFocusableMenuElementList.length;
|
131 | var focusIndex = sameLevelFocusableMenuElementList.findIndex(function (ele) {
|
132 | return focusMenuElement === ele;
|
133 | });
|
134 |
|
135 | if (offset < 0) {
|
136 | if (focusIndex === -1) {
|
137 | focusIndex = count - 1;
|
138 | } else {
|
139 | focusIndex -= 1;
|
140 | }
|
141 | } else if (offset > 0) {
|
142 | focusIndex += 1;
|
143 | }
|
144 |
|
145 | focusIndex = (focusIndex + count) % count;
|
146 |
|
147 | return sameLevelFocusableMenuElementList[focusIndex];
|
148 | }
|
149 |
|
150 | export default function useAccessibility(mode, activeKey, isRtl, id, containerRef, getKeys, getKeyPath, triggerActiveKey, triggerAccessibilityOpen, originOnKeyDown) {
|
151 | var rafRef = React.useRef();
|
152 | var activeRef = React.useRef();
|
153 | activeRef.current = activeKey;
|
154 |
|
155 | var cleanRaf = function cleanRaf() {
|
156 | raf.cancel(rafRef.current);
|
157 | };
|
158 |
|
159 | React.useEffect(function () {
|
160 | return function () {
|
161 | cleanRaf();
|
162 | };
|
163 | }, []);
|
164 | return function (e) {
|
165 | var which = e.which;
|
166 |
|
167 | if ([].concat(ArrowKeys, [ENTER, ESC]).includes(which)) {
|
168 |
|
169 | var elements;
|
170 | var key2element;
|
171 | var element2key;
|
172 |
|
173 | var refreshElements = function refreshElements() {
|
174 | elements = new Set();
|
175 | key2element = new Map();
|
176 | element2key = new Map();
|
177 | var keys = getKeys();
|
178 | keys.forEach(function (key) {
|
179 | var element = document.querySelector("[data-menu-id='".concat(getMenuId(id, key), "']"));
|
180 |
|
181 | if (element) {
|
182 | elements.add(element);
|
183 | element2key.set(element, key);
|
184 | key2element.set(key, element);
|
185 | }
|
186 | });
|
187 | return elements;
|
188 | };
|
189 |
|
190 | refreshElements();
|
191 |
|
192 | var activeElement = key2element.get(activeKey);
|
193 | var focusMenuElement = getFocusElement(activeElement, elements);
|
194 | var focusMenuKey = element2key.get(focusMenuElement);
|
195 | var offsetObj = getOffset(mode, getKeyPath(focusMenuKey, true).length === 1, isRtl, which);
|
196 |
|
197 | if (!offsetObj) {
|
198 | return;
|
199 | }
|
200 |
|
201 |
|
202 | if (ArrowKeys.includes(which)) {
|
203 | e.preventDefault();
|
204 | }
|
205 |
|
206 | var tryFocus = function tryFocus(menuElement) {
|
207 | if (menuElement) {
|
208 | var focusTargetElement = menuElement;
|
209 |
|
210 | var link = menuElement.querySelector('a');
|
211 |
|
212 | if (link === null || link === void 0 ? void 0 : link.getAttribute('href')) {
|
213 | focusTargetElement = link;
|
214 | }
|
215 |
|
216 | var targetKey = element2key.get(menuElement);
|
217 | triggerActiveKey(targetKey);
|
218 | |
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 | cleanRaf();
|
225 | rafRef.current = raf(function () {
|
226 | if (activeRef.current === targetKey) {
|
227 | focusTargetElement.focus();
|
228 | }
|
229 | });
|
230 | }
|
231 | };
|
232 |
|
233 | if (offsetObj.sibling || !focusMenuElement) {
|
234 |
|
235 |
|
236 | var parentQueryContainer;
|
237 |
|
238 | if (!focusMenuElement || mode === 'inline') {
|
239 | parentQueryContainer = containerRef.current;
|
240 | } else {
|
241 | parentQueryContainer = findContainerUL(focusMenuElement);
|
242 | }
|
243 |
|
244 |
|
245 | var targetElement = getNextFocusElement(parentQueryContainer, elements, focusMenuElement, offsetObj.offset);
|
246 |
|
247 | tryFocus(targetElement);
|
248 | } else if (offsetObj.inlineTrigger) {
|
249 |
|
250 | triggerAccessibilityOpen(focusMenuKey);
|
251 | } else if (offsetObj.offset > 0) {
|
252 | triggerAccessibilityOpen(focusMenuKey, true);
|
253 | cleanRaf();
|
254 | rafRef.current = raf(function () {
|
255 |
|
256 | refreshElements();
|
257 | var controlId = focusMenuElement.getAttribute('aria-controls');
|
258 | var subQueryContainer = document.getElementById(controlId);
|
259 |
|
260 | var targetElement = getNextFocusElement(subQueryContainer, elements);
|
261 |
|
262 | tryFocus(targetElement);
|
263 | }, 5);
|
264 | } else if (offsetObj.offset < 0) {
|
265 | var keyPath = getKeyPath(focusMenuKey, true);
|
266 | var parentKey = keyPath[keyPath.length - 2];
|
267 | var parentMenuElement = key2element.get(parentKey);
|
268 |
|
269 | triggerAccessibilityOpen(parentKey, false);
|
270 | tryFocus(parentMenuElement);
|
271 | }
|
272 | }
|
273 |
|
274 |
|
275 | originOnKeyDown === null || originOnKeyDown === void 0 ? void 0 : originOnKeyDown(e);
|
276 | };
|
277 | } |
\ | No newline at end of file |