@zag-js/aria-hidden 0.65.1 → 0.66.1
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/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +9 -111
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -110
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +10 -159
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
interface AriaHiddenOptions {
|
|
2
|
-
rootEl?: HTMLElement;
|
|
3
|
-
defer?: boolean;
|
|
4
|
-
}
|
|
5
1
|
type MaybeElement = HTMLElement | null;
|
|
6
2
|
type Targets = Array<MaybeElement>;
|
|
7
3
|
type TargetsOrFn = Targets | (() => Targets);
|
|
8
|
-
|
|
4
|
+
type Options = {
|
|
5
|
+
defer?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare function ariaHidden(targetsOrFn: TargetsOrFn, options?: Options): () => void;
|
|
9
8
|
|
|
10
|
-
export {
|
|
9
|
+
export { ariaHidden };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
interface AriaHiddenOptions {
|
|
2
|
-
rootEl?: HTMLElement;
|
|
3
|
-
defer?: boolean;
|
|
4
|
-
}
|
|
5
1
|
type MaybeElement = HTMLElement | null;
|
|
6
2
|
type Targets = Array<MaybeElement>;
|
|
7
3
|
type TargetsOrFn = Targets | (() => Targets);
|
|
8
|
-
|
|
4
|
+
type Options = {
|
|
5
|
+
defer?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare function ariaHidden(targetsOrFn: TargetsOrFn, options?: Options): () => void;
|
|
9
8
|
|
|
10
|
-
export {
|
|
9
|
+
export { ariaHidden };
|
package/dist/index.js
CHANGED
|
@@ -23,122 +23,20 @@ __export(src_exports, {
|
|
|
23
23
|
ariaHidden: () => ariaHidden
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(src_exports);
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const exclude = targets.filter(Boolean);
|
|
32
|
-
if (exclude.length === 0) return;
|
|
33
|
-
const doc = exclude[0].ownerDocument || document;
|
|
34
|
-
const win = doc.defaultView ?? window;
|
|
35
|
-
const visibleNodes = new Set(exclude);
|
|
36
|
-
const hiddenNodes = /* @__PURE__ */ new Set();
|
|
37
|
-
const root = rootEl ?? doc.body;
|
|
38
|
-
let walk = (root2) => {
|
|
39
|
-
for (let element of root2.querySelectorAll("[data-live-announcer], [data-zag-top-layer]")) {
|
|
40
|
-
visibleNodes.add(element);
|
|
41
|
-
}
|
|
42
|
-
let acceptNode = (node) => {
|
|
43
|
-
if (visibleNodes.has(node) || hiddenNodes.has(node.parentElement) && node.parentElement.getAttribute("role") !== "row") {
|
|
44
|
-
return NodeFilter.FILTER_REJECT;
|
|
45
|
-
}
|
|
46
|
-
for (let target of visibleNodes) {
|
|
47
|
-
if (node.contains(target)) {
|
|
48
|
-
return NodeFilter.FILTER_SKIP;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
52
|
-
};
|
|
53
|
-
let walker = doc.createTreeWalker(root2, NodeFilter.SHOW_ELEMENT, { acceptNode });
|
|
54
|
-
let acceptRoot = acceptNode(root2);
|
|
55
|
-
if (acceptRoot === NodeFilter.FILTER_ACCEPT) {
|
|
56
|
-
hide(root2);
|
|
57
|
-
}
|
|
58
|
-
if (acceptRoot !== NodeFilter.FILTER_REJECT) {
|
|
59
|
-
let node = walker.nextNode();
|
|
60
|
-
while (node != null) {
|
|
61
|
-
hide(node);
|
|
62
|
-
node = walker.nextNode();
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
let hide = (node) => {
|
|
67
|
-
let refCount = refCountMap.get(node) ?? 0;
|
|
68
|
-
if (node.getAttribute("aria-hidden") === "true" && refCount === 0) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (refCount === 0) {
|
|
72
|
-
node.setAttribute("aria-hidden", "true");
|
|
73
|
-
}
|
|
74
|
-
hiddenNodes.add(node);
|
|
75
|
-
refCountMap.set(node, refCount + 1);
|
|
76
|
-
};
|
|
77
|
-
if (observerStack.length) {
|
|
78
|
-
observerStack[observerStack.length - 1].disconnect();
|
|
79
|
-
}
|
|
80
|
-
walk(root);
|
|
81
|
-
const observer = new win.MutationObserver((changes) => {
|
|
82
|
-
for (let change of changes) {
|
|
83
|
-
if (change.type !== "childList" || change.addedNodes.length === 0) {
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
if (![...visibleNodes, ...hiddenNodes].some((node) => node.contains(change.target))) {
|
|
87
|
-
for (let node of change.removedNodes) {
|
|
88
|
-
if (node instanceof win.Element) {
|
|
89
|
-
visibleNodes.delete(node);
|
|
90
|
-
hiddenNodes.delete(node);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
for (let node of change.addedNodes) {
|
|
94
|
-
if ((node instanceof win.HTMLElement || node instanceof win.SVGElement) && (node.dataset.liveAnnouncer === "true" || node.dataset.zagTopLayer === "true")) {
|
|
95
|
-
visibleNodes.add(node);
|
|
96
|
-
} else if (node instanceof win.Element) {
|
|
97
|
-
walk(node);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
observer.observe(root, { childList: true, subtree: true });
|
|
104
|
-
let observerWrapper = {
|
|
105
|
-
observe() {
|
|
106
|
-
observer.observe(root, { childList: true, subtree: true });
|
|
107
|
-
},
|
|
108
|
-
disconnect() {
|
|
109
|
-
observer.disconnect();
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
observerStack.push(observerWrapper);
|
|
113
|
-
return () => {
|
|
114
|
-
observer.disconnect();
|
|
115
|
-
for (let node of hiddenNodes) {
|
|
116
|
-
let count = refCountMap.get(node);
|
|
117
|
-
if (count === 1) {
|
|
118
|
-
node.removeAttribute("aria-hidden");
|
|
119
|
-
refCountMap.delete(node);
|
|
120
|
-
} else {
|
|
121
|
-
refCountMap.set(node, count - 1);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
if (observerWrapper === observerStack[observerStack.length - 1]) {
|
|
125
|
-
observerStack.pop();
|
|
126
|
-
if (observerStack.length) {
|
|
127
|
-
observerStack[observerStack.length - 1].observe();
|
|
128
|
-
}
|
|
129
|
-
} else {
|
|
130
|
-
observerStack.splice(observerStack.indexOf(observerWrapper), 1);
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
}
|
|
26
|
+
var import_aria_hidden = require("aria-hidden");
|
|
27
|
+
var raf = (fn) => {
|
|
28
|
+
const frameId = requestAnimationFrame(() => fn());
|
|
29
|
+
return () => cancelAnimationFrame(frameId);
|
|
30
|
+
};
|
|
134
31
|
function ariaHidden(targetsOrFn, options = {}) {
|
|
135
|
-
const { defer } = options;
|
|
136
|
-
const func = defer ?
|
|
32
|
+
const { defer = true } = options;
|
|
33
|
+
const func = defer ? raf : (v) => v();
|
|
137
34
|
const cleanups = [];
|
|
138
35
|
cleanups.push(
|
|
139
36
|
func(() => {
|
|
140
37
|
const targets = typeof targetsOrFn === "function" ? targetsOrFn() : targetsOrFn;
|
|
141
|
-
|
|
38
|
+
const elements = targets.filter(Boolean);
|
|
39
|
+
cleanups.push((0, import_aria_hidden.hideOthers)(elements));
|
|
142
40
|
})
|
|
143
41
|
);
|
|
144
42
|
return () => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { hideOthers } from \"aria-hidden\"\n\nconst raf = (fn: VoidFunction) => {\n const frameId = requestAnimationFrame(() => fn())\n return () => cancelAnimationFrame(frameId)\n}\n\ntype MaybeElement = HTMLElement | null\ntype Targets = Array<MaybeElement>\ntype TargetsOrFn = Targets | (() => Targets)\n\ntype Options = {\n defer?: boolean\n}\n\nexport function ariaHidden(targetsOrFn: TargetsOrFn, options: Options = {}) {\n const { defer = true } = options\n const func = defer ? raf : (v: any) => v()\n const cleanups: (VoidFunction | undefined)[] = []\n cleanups.push(\n func(() => {\n const targets = typeof targetsOrFn === \"function\" ? targetsOrFn() : targetsOrFn\n const elements = targets.filter(Boolean) as HTMLElement[]\n cleanups.push(hideOthers(elements))\n }),\n )\n return () => {\n cleanups.forEach((fn) => fn?.())\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAA2B;AAE3B,IAAM,MAAM,CAAC,OAAqB;AAChC,QAAM,UAAU,sBAAsB,MAAM,GAAG,CAAC;AAChD,SAAO,MAAM,qBAAqB,OAAO;AAC3C;AAUO,SAAS,WAAW,aAA0B,UAAmB,CAAC,GAAG;AAC1E,QAAM,EAAE,QAAQ,KAAK,IAAI;AACzB,QAAM,OAAO,QAAQ,MAAM,CAAC,MAAW,EAAE;AACzC,QAAM,WAAyC,CAAC;AAChD,WAAS;AAAA,IACP,KAAK,MAAM;AACT,YAAM,UAAU,OAAO,gBAAgB,aAAa,YAAY,IAAI;AACpE,YAAM,WAAW,QAAQ,OAAO,OAAO;AACvC,eAAS,SAAK,+BAAW,QAAQ,CAAC;AAAA,IACpC,CAAC;AAAA,EACH;AACA,SAAO,MAAM;AACX,aAAS,QAAQ,CAAC,OAAO,KAAK,CAAC;AAAA,EACjC;AACF;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,120 +1,18 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import {
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const exclude = targets.filter(Boolean);
|
|
8
|
-
if (exclude.length === 0) return;
|
|
9
|
-
const doc = exclude[0].ownerDocument || document;
|
|
10
|
-
const win = doc.defaultView ?? window;
|
|
11
|
-
const visibleNodes = new Set(exclude);
|
|
12
|
-
const hiddenNodes = /* @__PURE__ */ new Set();
|
|
13
|
-
const root = rootEl ?? doc.body;
|
|
14
|
-
let walk = (root2) => {
|
|
15
|
-
for (let element of root2.querySelectorAll("[data-live-announcer], [data-zag-top-layer]")) {
|
|
16
|
-
visibleNodes.add(element);
|
|
17
|
-
}
|
|
18
|
-
let acceptNode = (node) => {
|
|
19
|
-
if (visibleNodes.has(node) || hiddenNodes.has(node.parentElement) && node.parentElement.getAttribute("role") !== "row") {
|
|
20
|
-
return NodeFilter.FILTER_REJECT;
|
|
21
|
-
}
|
|
22
|
-
for (let target of visibleNodes) {
|
|
23
|
-
if (node.contains(target)) {
|
|
24
|
-
return NodeFilter.FILTER_SKIP;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
28
|
-
};
|
|
29
|
-
let walker = doc.createTreeWalker(root2, NodeFilter.SHOW_ELEMENT, { acceptNode });
|
|
30
|
-
let acceptRoot = acceptNode(root2);
|
|
31
|
-
if (acceptRoot === NodeFilter.FILTER_ACCEPT) {
|
|
32
|
-
hide(root2);
|
|
33
|
-
}
|
|
34
|
-
if (acceptRoot !== NodeFilter.FILTER_REJECT) {
|
|
35
|
-
let node = walker.nextNode();
|
|
36
|
-
while (node != null) {
|
|
37
|
-
hide(node);
|
|
38
|
-
node = walker.nextNode();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
let hide = (node) => {
|
|
43
|
-
let refCount = refCountMap.get(node) ?? 0;
|
|
44
|
-
if (node.getAttribute("aria-hidden") === "true" && refCount === 0) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
if (refCount === 0) {
|
|
48
|
-
node.setAttribute("aria-hidden", "true");
|
|
49
|
-
}
|
|
50
|
-
hiddenNodes.add(node);
|
|
51
|
-
refCountMap.set(node, refCount + 1);
|
|
52
|
-
};
|
|
53
|
-
if (observerStack.length) {
|
|
54
|
-
observerStack[observerStack.length - 1].disconnect();
|
|
55
|
-
}
|
|
56
|
-
walk(root);
|
|
57
|
-
const observer = new win.MutationObserver((changes) => {
|
|
58
|
-
for (let change of changes) {
|
|
59
|
-
if (change.type !== "childList" || change.addedNodes.length === 0) {
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
if (![...visibleNodes, ...hiddenNodes].some((node) => node.contains(change.target))) {
|
|
63
|
-
for (let node of change.removedNodes) {
|
|
64
|
-
if (node instanceof win.Element) {
|
|
65
|
-
visibleNodes.delete(node);
|
|
66
|
-
hiddenNodes.delete(node);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
for (let node of change.addedNodes) {
|
|
70
|
-
if ((node instanceof win.HTMLElement || node instanceof win.SVGElement) && (node.dataset.liveAnnouncer === "true" || node.dataset.zagTopLayer === "true")) {
|
|
71
|
-
visibleNodes.add(node);
|
|
72
|
-
} else if (node instanceof win.Element) {
|
|
73
|
-
walk(node);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
observer.observe(root, { childList: true, subtree: true });
|
|
80
|
-
let observerWrapper = {
|
|
81
|
-
observe() {
|
|
82
|
-
observer.observe(root, { childList: true, subtree: true });
|
|
83
|
-
},
|
|
84
|
-
disconnect() {
|
|
85
|
-
observer.disconnect();
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
observerStack.push(observerWrapper);
|
|
89
|
-
return () => {
|
|
90
|
-
observer.disconnect();
|
|
91
|
-
for (let node of hiddenNodes) {
|
|
92
|
-
let count = refCountMap.get(node);
|
|
93
|
-
if (count === 1) {
|
|
94
|
-
node.removeAttribute("aria-hidden");
|
|
95
|
-
refCountMap.delete(node);
|
|
96
|
-
} else {
|
|
97
|
-
refCountMap.set(node, count - 1);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (observerWrapper === observerStack[observerStack.length - 1]) {
|
|
101
|
-
observerStack.pop();
|
|
102
|
-
if (observerStack.length) {
|
|
103
|
-
observerStack[observerStack.length - 1].observe();
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
observerStack.splice(observerStack.indexOf(observerWrapper), 1);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
}
|
|
2
|
+
import { hideOthers } from "aria-hidden";
|
|
3
|
+
var raf = (fn) => {
|
|
4
|
+
const frameId = requestAnimationFrame(() => fn());
|
|
5
|
+
return () => cancelAnimationFrame(frameId);
|
|
6
|
+
};
|
|
110
7
|
function ariaHidden(targetsOrFn, options = {}) {
|
|
111
|
-
const { defer } = options;
|
|
8
|
+
const { defer = true } = options;
|
|
112
9
|
const func = defer ? raf : (v) => v();
|
|
113
10
|
const cleanups = [];
|
|
114
11
|
cleanups.push(
|
|
115
12
|
func(() => {
|
|
116
13
|
const targets = typeof targetsOrFn === "function" ? targetsOrFn() : targetsOrFn;
|
|
117
|
-
|
|
14
|
+
const elements = targets.filter(Boolean);
|
|
15
|
+
cleanups.push(hideOthers(elements));
|
|
118
16
|
})
|
|
119
17
|
);
|
|
120
18
|
return () => {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { hideOthers } from \"aria-hidden\"\n\nconst raf = (fn: VoidFunction) => {\n const frameId = requestAnimationFrame(() => fn())\n return () => cancelAnimationFrame(frameId)\n}\n\ntype MaybeElement = HTMLElement | null\ntype Targets = Array<MaybeElement>\ntype TargetsOrFn = Targets | (() => Targets)\n\ntype Options = {\n defer?: boolean\n}\n\nexport function ariaHidden(targetsOrFn: TargetsOrFn, options: Options = {}) {\n const { defer = true } = options\n const func = defer ? raf : (v: any) => v()\n const cleanups: (VoidFunction | undefined)[] = []\n cleanups.push(\n func(() => {\n const targets = typeof targetsOrFn === \"function\" ? targetsOrFn() : targetsOrFn\n const elements = targets.filter(Boolean) as HTMLElement[]\n cleanups.push(hideOthers(elements))\n }),\n )\n return () => {\n cleanups.forEach((fn) => fn?.())\n }\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAE3B,IAAM,MAAM,CAAC,OAAqB;AAChC,QAAM,UAAU,sBAAsB,MAAM,GAAG,CAAC;AAChD,SAAO,MAAM,qBAAqB,OAAO;AAC3C;AAUO,SAAS,WAAW,aAA0B,UAAmB,CAAC,GAAG;AAC1E,QAAM,EAAE,QAAQ,KAAK,IAAI;AACzB,QAAM,OAAO,QAAQ,MAAM,CAAC,MAAW,EAAE;AACzC,QAAM,WAAyC,CAAC;AAChD,WAAS;AAAA,IACP,KAAK,MAAM;AACT,YAAM,UAAU,OAAO,gBAAgB,aAAa,YAAY,IAAI;AACpE,YAAM,WAAW,QAAQ,OAAO,OAAO;AACvC,eAAS,KAAK,WAAW,QAAQ,CAAC;AAAA,IACpC,CAAC;AAAA,EACH;AACA,SAAO,MAAM;AACX,aAAS,QAAQ,CAAC,OAAO,KAAK,CAAC;AAAA,EACjC;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zag-js/aria-hidden",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.66.1",
|
|
4
4
|
"description": "Hide targets from screen readers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"clean-package": "../../../clean-package.config.json",
|
|
26
26
|
"main": "dist/index.js",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"
|
|
28
|
+
"aria-hidden": "1.2.4"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"clean-package": "2.2.0"
|
package/src/index.ts
CHANGED
|
@@ -1,176 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
import { raf } from "@zag-js/dom-query"
|
|
1
|
+
import { hideOthers } from "aria-hidden"
|
|
3
2
|
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
export interface AriaHiddenOptions {
|
|
8
|
-
rootEl?: HTMLElement
|
|
9
|
-
defer?: boolean
|
|
3
|
+
const raf = (fn: VoidFunction) => {
|
|
4
|
+
const frameId = requestAnimationFrame(() => fn())
|
|
5
|
+
return () => cancelAnimationFrame(frameId)
|
|
10
6
|
}
|
|
11
7
|
|
|
12
8
|
type MaybeElement = HTMLElement | null
|
|
13
9
|
type Targets = Array<MaybeElement>
|
|
14
10
|
type TargetsOrFn = Targets | (() => Targets)
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const exclude = targets.filter(Boolean) as HTMLElement[]
|
|
20
|
-
if (exclude.length === 0) return
|
|
21
|
-
|
|
22
|
-
const doc = exclude[0].ownerDocument || document
|
|
23
|
-
const win = doc.defaultView ?? window
|
|
24
|
-
|
|
25
|
-
const visibleNodes = new Set<Element>(exclude)
|
|
26
|
-
const hiddenNodes = new Set<Element>()
|
|
27
|
-
|
|
28
|
-
const root = rootEl ?? doc.body
|
|
29
|
-
|
|
30
|
-
let walk = (root: Element) => {
|
|
31
|
-
// Keep live announcer and top layer elements (e.g. toasts) visible.
|
|
32
|
-
for (let element of root.querySelectorAll("[data-live-announcer], [data-zag-top-layer]")) {
|
|
33
|
-
visibleNodes.add(element)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let acceptNode = (node: Element) => {
|
|
37
|
-
// Skip this node and its children if it is one of the target nodes, or a live announcer.
|
|
38
|
-
// Also skip children of already hidden nodes, as aria-hidden is recursive. An exception is
|
|
39
|
-
// made for elements with role="row" since VoiceOver on iOS has issues hiding elements with role="row".
|
|
40
|
-
// For that case we want to hide the cells inside as well (https://bugs.webkit.org/show_bug.cgi?id=222623).
|
|
41
|
-
if (
|
|
42
|
-
visibleNodes.has(node) ||
|
|
43
|
-
(hiddenNodes.has(node.parentElement!) && node.parentElement!.getAttribute("role") !== "row")
|
|
44
|
-
) {
|
|
45
|
-
return NodeFilter.FILTER_REJECT
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Skip this node but continue to children if one of the targets is inside the node.
|
|
49
|
-
for (let target of visibleNodes) {
|
|
50
|
-
if (node.contains(target)) {
|
|
51
|
-
return NodeFilter.FILTER_SKIP
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return NodeFilter.FILTER_ACCEPT
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
let walker = doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, { acceptNode })
|
|
59
|
-
|
|
60
|
-
// TreeWalker does not include the root.
|
|
61
|
-
let acceptRoot = acceptNode(root)
|
|
62
|
-
if (acceptRoot === NodeFilter.FILTER_ACCEPT) {
|
|
63
|
-
hide(root)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (acceptRoot !== NodeFilter.FILTER_REJECT) {
|
|
67
|
-
let node = walker.nextNode() as Element
|
|
68
|
-
while (node != null) {
|
|
69
|
-
hide(node)
|
|
70
|
-
node = walker.nextNode() as Element
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
let hide = (node: Element) => {
|
|
76
|
-
let refCount = refCountMap.get(node) ?? 0
|
|
77
|
-
|
|
78
|
-
// If already aria-hidden, and the ref count is zero, then this element
|
|
79
|
-
// was already hidden and there's nothing for us to do.
|
|
80
|
-
if (node.getAttribute("aria-hidden") === "true" && refCount === 0) {
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (refCount === 0) {
|
|
85
|
-
node.setAttribute("aria-hidden", "true")
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
hiddenNodes.add(node)
|
|
89
|
-
refCountMap.set(node, refCount + 1)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (observerStack.length) {
|
|
93
|
-
observerStack[observerStack.length - 1].disconnect()
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
walk(root)
|
|
97
|
-
|
|
98
|
-
const observer = new win.MutationObserver((changes) => {
|
|
99
|
-
for (let change of changes) {
|
|
100
|
-
if (change.type !== "childList" || change.addedNodes.length === 0) {
|
|
101
|
-
continue
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// If the parent element of the added nodes is not within one of the targets,
|
|
105
|
-
// and not already inside a hidden node, hide all of the new children.
|
|
106
|
-
if (![...visibleNodes, ...hiddenNodes].some((node) => node.contains(change.target))) {
|
|
107
|
-
for (let node of change.removedNodes) {
|
|
108
|
-
if (node instanceof win.Element) {
|
|
109
|
-
visibleNodes.delete(node)
|
|
110
|
-
hiddenNodes.delete(node)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
for (let node of change.addedNodes) {
|
|
115
|
-
if (
|
|
116
|
-
(node instanceof win.HTMLElement || node instanceof win.SVGElement) &&
|
|
117
|
-
(node.dataset.liveAnnouncer === "true" || node.dataset.zagTopLayer === "true")
|
|
118
|
-
) {
|
|
119
|
-
visibleNodes.add(node)
|
|
120
|
-
} else if (node instanceof win.Element) {
|
|
121
|
-
walk(node)
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
observer.observe(root, { childList: true, subtree: true })
|
|
129
|
-
|
|
130
|
-
let observerWrapper = {
|
|
131
|
-
observe() {
|
|
132
|
-
observer.observe(root, { childList: true, subtree: true })
|
|
133
|
-
},
|
|
134
|
-
disconnect() {
|
|
135
|
-
observer.disconnect()
|
|
136
|
-
},
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
observerStack.push(observerWrapper)
|
|
140
|
-
|
|
141
|
-
return () => {
|
|
142
|
-
observer.disconnect()
|
|
143
|
-
|
|
144
|
-
for (let node of hiddenNodes) {
|
|
145
|
-
let count = refCountMap.get(node)
|
|
146
|
-
if (count === 1) {
|
|
147
|
-
node.removeAttribute("aria-hidden")
|
|
148
|
-
refCountMap.delete(node)
|
|
149
|
-
} else {
|
|
150
|
-
refCountMap.set(node, count! - 1)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Remove this observer from the stack, and start the previous one.
|
|
155
|
-
if (observerWrapper === observerStack[observerStack.length - 1]) {
|
|
156
|
-
observerStack.pop()
|
|
157
|
-
if (observerStack.length) {
|
|
158
|
-
observerStack[observerStack.length - 1].observe()
|
|
159
|
-
}
|
|
160
|
-
} else {
|
|
161
|
-
observerStack.splice(observerStack.indexOf(observerWrapper), 1)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
12
|
+
type Options = {
|
|
13
|
+
defer?: boolean
|
|
164
14
|
}
|
|
165
15
|
|
|
166
|
-
export function ariaHidden(targetsOrFn: TargetsOrFn, options:
|
|
167
|
-
const { defer } = options
|
|
16
|
+
export function ariaHidden(targetsOrFn: TargetsOrFn, options: Options = {}) {
|
|
17
|
+
const { defer = true } = options
|
|
168
18
|
const func = defer ? raf : (v: any) => v()
|
|
169
19
|
const cleanups: (VoidFunction | undefined)[] = []
|
|
170
20
|
cleanups.push(
|
|
171
21
|
func(() => {
|
|
172
22
|
const targets = typeof targetsOrFn === "function" ? targetsOrFn() : targetsOrFn
|
|
173
|
-
|
|
23
|
+
const elements = targets.filter(Boolean) as HTMLElement[]
|
|
24
|
+
cleanups.push(hideOthers(elements))
|
|
174
25
|
}),
|
|
175
26
|
)
|
|
176
27
|
return () => {
|