arrowtab 0.0.4 → 0.0.5

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.
package/README.md CHANGED
@@ -80,7 +80,10 @@ cleanup()
80
80
  You can pass options to the `initArrowTab` function. For example:
81
81
 
82
82
  ```ts
83
- initArrowTab({ debug: true })
83
+ initArrowTab({
84
+ debug: true,
85
+ autoDetectHistory: true,
86
+ })
84
87
  ```
85
88
 
86
89
  ### debug
@@ -103,6 +106,12 @@ If you click on a focusable element, debug information will be logged to the con
103
106
 
104
107
  To deactivate the visual debug mode, press `Esc`.
105
108
 
109
+ ### autoDetectHistory
110
+
111
+ default: `false`
112
+
113
+ If `true`, ArrowTab will automatically detect dialogs and refocuses the last focused element when the dialog closes.
114
+
106
115
  ## data-arrowtab
107
116
 
108
117
  You can control the behavior of ArrowTab by adding a `data-arrowtab` attribute to any element. Separate the keywords with a space. For example: `<div data-arrowtab="disable-left disable-right">`
@@ -0,0 +1,10 @@
1
+ export declare const setHistoryCandidate: ({ element }: {
2
+ element: Element;
3
+ }) => void;
4
+ export declare const pushCandidateIntoHistory: () => void;
5
+ export declare const focusPrevious: () => void;
6
+ export declare const startAutoDetectHistory: ({ active }: {
7
+ active: boolean;
8
+ }) => {
9
+ cleanup: () => void;
10
+ };
@@ -0,0 +1,60 @@
1
+ const focusHistory = [];
2
+ let historyCandidate;
3
+ export const setHistoryCandidate = ({ element }) => {
4
+ if (!(element instanceof HTMLElement)) {
5
+ return;
6
+ }
7
+ historyCandidate = element;
8
+ };
9
+ export const pushCandidateIntoHistory = () => {
10
+ if (historyCandidate) {
11
+ focusHistory.push(historyCandidate);
12
+ }
13
+ };
14
+ export const focusPrevious = () => {
15
+ const lastHistoryElement = focusHistory.pop();
16
+ if (lastHistoryElement) {
17
+ lastHistoryElement.focus();
18
+ }
19
+ };
20
+ export const startAutoDetectHistory = ({ active }) => {
21
+ if (!active) {
22
+ return {
23
+ cleanup: () => { },
24
+ };
25
+ }
26
+ let dialogObserver = null;
27
+ // TODO: Support multiple dialogs
28
+ let lastDialogElement = null;
29
+ dialogObserver = new MutationObserver((mutationList) => {
30
+ for (const mutation of mutationList) {
31
+ if (mutation.type === 'childList') {
32
+ for (const node of mutation.addedNodes) {
33
+ if (node.nodeType === 1 &&
34
+ node instanceof HTMLElement &&
35
+ node.getAttribute('role') === 'dialog') {
36
+ lastDialogElement = node;
37
+ pushCandidateIntoHistory();
38
+ }
39
+ }
40
+ for (const node of mutation.removedNodes) {
41
+ if (node === lastDialogElement || node.contains(lastDialogElement)) {
42
+ lastDialogElement = null;
43
+ focusPrevious();
44
+ return;
45
+ }
46
+ }
47
+ }
48
+ }
49
+ });
50
+ dialogObserver.observe(document.body, {
51
+ childList: true,
52
+ subtree: true,
53
+ });
54
+ return {
55
+ cleanup: () => {
56
+ dialogObserver?.disconnect();
57
+ },
58
+ };
59
+ };
60
+ //# sourceMappingURL=focusHistory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focusHistory.js","sourceRoot":"","sources":["../../src/lib/focusHistory.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAkB,EAAE,CAAA;AACtC,IAAI,gBAAyC,CAAA;AAE7C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAAE,OAAO,EAAwB,EAAE,EAAE;IACvE,IAAI,CAAC,CAAC,OAAO,YAAY,WAAW,CAAC,EAAE,CAAC;QACtC,OAAM;IACR,CAAC;IACD,gBAAgB,GAAG,OAAO,CAAA;AAC5B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,EAAE;IAC3C,IAAI,gBAAgB,EAAE,CAAC;QACrB,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;IACrC,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE;IAChC,MAAM,kBAAkB,GAAG,YAAY,CAAC,GAAG,EAAE,CAAA;IAC7C,IAAI,kBAAkB,EAAE,CAAC;QACvB,kBAAkB,CAAC,KAAK,EAAE,CAAA;IAC5B,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,EAAE,MAAM,EAAuB,EAAE,EAAE;IACxE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC;SAClB,CAAA;IACH,CAAC;IACD,IAAI,cAAc,GAA4B,IAAI,CAAA;IAClD,iCAAiC;IACjC,IAAI,iBAAiB,GAAuB,IAAI,CAAA;IAChD,cAAc,GAAG,IAAI,gBAAgB,CAAC,CAAC,YAAY,EAAE,EAAE;QACrD,KAAK,MAAM,QAAQ,IAAI,YAAY,EAAE,CAAC;YACpC,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAClC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;oBACvC,IACE,IAAI,CAAC,QAAQ,KAAK,CAAC;wBACnB,IAAI,YAAY,WAAW;wBAC3B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,QAAQ,EACtC,CAAC;wBACD,iBAAiB,GAAG,IAAI,CAAA;wBACxB,wBAAwB,EAAE,CAAA;oBAC5B,CAAC;gBACH,CAAC;gBAED,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;oBACzC,IAAI,IAAI,KAAK,iBAAiB,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;wBACnE,iBAAiB,GAAG,IAAI,CAAA;wBACxB,aAAa,EAAE,CAAA;wBACf,OAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QACpC,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,IAAI;KACd,CAAC,CAAA;IAEF,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,cAAc,EAAE,UAAU,EAAE,CAAA;QAC9B,CAAC;KACF,CAAA;AACH,CAAC,CAAA"}
@@ -1,5 +1,6 @@
1
- export declare const initArrowTab: ({ debug }?: {
1
+ export declare const initArrowTab: ({ debug, autoDetectHistory, }?: {
2
2
  debug?: boolean;
3
+ autoDetectHistory?: boolean;
3
4
  }) => {
4
5
  cleanup: () => void;
5
6
  };
@@ -1,4 +1,5 @@
1
1
  import { activateDebugMode, deactivateDebugMode, isInDebugMode, } from './debugMode.js';
2
+ import { setHistoryCandidate, startAutoDetectHistory } from './focusHistory.js';
2
3
  import { getFocusable } from './getFocusable.js';
3
4
  import { hasDisabledKeys } from './hasDisabledKeys.js';
4
5
  import { hasTextSelection } from './hasTextSelection.js';
@@ -16,7 +17,7 @@ import { getByGrid } from './strategies.js';
16
17
  // TODO: Check if tab focuses the same elements as arrowTab
17
18
  // TODO: select, details, summary, iframe
18
19
  // TODO: Investigate links that don't show focus outline sometimes
19
- export const initArrowTab = ({ debug = false } = {}) => {
20
+ export const initArrowTab = ({ debug = false, autoDetectHistory = false, } = {}) => {
20
21
  const onKeyDown = (event) => {
21
22
  if (event.key === 'Escape' && isInDebugMode()) {
22
23
  deactivateDebugMode();
@@ -90,12 +91,17 @@ export const initArrowTab = ({ debug = false } = {}) => {
90
91
  console.log('focusing element', nearest);
91
92
  }
92
93
  nearest.element.focus();
94
+ setHistoryCandidate({ element: nearest.element });
93
95
  }
94
96
  };
95
97
  document.addEventListener('keydown', onKeyDown, { capture: true });
98
+ const { cleanup: cleanupAutoDetectHistory } = startAutoDetectHistory({
99
+ active: autoDetectHistory,
100
+ });
96
101
  return {
97
102
  cleanup: () => {
98
103
  document.removeEventListener('keydown', onKeyDown, { capture: true });
104
+ cleanupAutoDetectHistory();
99
105
  },
100
106
  };
101
107
  };
@@ -1 +1 @@
1
- {"version":3,"file":"initArrowTab.js","sourceRoot":"","sources":["../../src/lib/initArrowTab.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"initArrowTab.js","sourceRoot":"","sources":["../../src/lib/initArrowTab.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arrowtab",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Use arrow keys to \"tab\" between focusable elements",
5
5
  "keywords": [
6
6
  "arrowkeys",