UNPKG

4.56 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.focusLastElement = exports.focusFirstElement = exports.focusPrevElement = exports.focusNextElement = exports.getRelativeFocusable = void 0;
4var commands_1 = require("./commands");
5var DOMutils_1 = require("./utils/DOMutils");
6var array_1 = require("./utils/array");
7/**
8 * for a given `element` in a given `scope` returns focusable siblings
9 * @param element - base element
10 * @param scope - common parent. Can be document, but better to narrow it down for performance reasons
11 * @returns {prev,next} - references to a focusable element before and after
12 * @returns undefined - if operation is not applicable
13 */
14var getRelativeFocusable = function (element, scope, useTabbables) {
15 if (!element || !scope) {
16 console.error('no element or scope given');
17 return {};
18 }
19 var shards = (0, array_1.asArray)(scope);
20 if (shards.every(function (shard) { return !(0, DOMutils_1.contains)(shard, element); })) {
21 console.error('Active element is not contained in the scope');
22 return {};
23 }
24 var focusables = useTabbables
25 ? (0, DOMutils_1.getTabbableNodes)(shards, new Map())
26 : (0, DOMutils_1.getFocusableNodes)(shards, new Map());
27 var current = focusables.findIndex(function (_a) {
28 var node = _a.node;
29 return node === element;
30 });
31 if (current === -1) {
32 // an edge case, when anchor element is not found
33 return undefined;
34 }
35 return {
36 prev: focusables[current - 1],
37 next: focusables[current + 1],
38 first: focusables[0],
39 last: focusables[focusables.length - 1],
40 };
41};
42exports.getRelativeFocusable = getRelativeFocusable;
43var getBoundary = function (shards, useTabbables) {
44 var set = useTabbables
45 ? (0, DOMutils_1.getTabbableNodes)((0, array_1.asArray)(shards), new Map())
46 : (0, DOMutils_1.getFocusableNodes)((0, array_1.asArray)(shards), new Map());
47 return {
48 first: set[0],
49 last: set[set.length - 1],
50 };
51};
52var defaultOptions = function (options) {
53 return Object.assign({
54 scope: document.body,
55 cycle: true,
56 onlyTabbable: true,
57 }, options);
58};
59var moveFocus = function (fromElement, options, cb) {
60 if (options === void 0) { options = {}; }
61 var newOptions = defaultOptions(options);
62 var solution = (0, exports.getRelativeFocusable)(fromElement, newOptions.scope, newOptions.onlyTabbable);
63 if (!solution) {
64 return;
65 }
66 var target = cb(solution, newOptions.cycle);
67 if (target) {
68 (0, commands_1.focusOn)(target.node, newOptions.focusOptions);
69 }
70};
71/**
72 * focuses next element in the tab-order
73 * @param fromElement - common parent to scope active element search or tab cycle order
74 * @param {FocusNextOptions} [options] - focus options
75 */
76var focusNextElement = function (fromElement, options) {
77 if (options === void 0) { options = {}; }
78 moveFocus(fromElement, options, function (_a, cycle) {
79 var next = _a.next, first = _a.first;
80 return next || (cycle && first);
81 });
82};
83exports.focusNextElement = focusNextElement;
84/**
85 * focuses prev element in the tab order
86 * @param fromElement - common parent to scope active element search or tab cycle order
87 * @param {FocusNextOptions} [options] - focus options
88 */
89var focusPrevElement = function (fromElement, options) {
90 if (options === void 0) { options = {}; }
91 moveFocus(fromElement, options, function (_a, cycle) {
92 var prev = _a.prev, last = _a.last;
93 return prev || (cycle && last);
94 });
95};
96exports.focusPrevElement = focusPrevElement;
97var pickBoundary = function (scope, options, what) {
98 var _a;
99 var boundary = getBoundary(scope, (_a = options.onlyTabbable) !== null && _a !== void 0 ? _a : true);
100 var node = boundary[what];
101 if (node) {
102 (0, commands_1.focusOn)(node.node, options.focusOptions);
103 }
104};
105/**
106 * focuses first element in the tab-order
107 * @param {FocusNextOptions} options - focus options
108 */
109var focusFirstElement = function (scope, options) {
110 if (options === void 0) { options = {}; }
111 pickBoundary(scope, options, 'first');
112};
113exports.focusFirstElement = focusFirstElement;
114/**
115 * focuses last element in the tab order
116 * @param {FocusNextOptions} options - focus options
117 */
118var focusLastElement = function (scope, options) {
119 if (options === void 0) { options = {}; }
120 pickBoundary(scope, options, 'last');
121};
122exports.focusLastElement = focusLastElement;