@zag-js/aria-hidden 1.45.0 → 1.46.0

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.
@@ -35,8 +35,7 @@ var hideOthers = (originalTarget, parentNode = getParentNode(originalTarget), ma
35
35
  return (0, import_walk_tree_outside.walkTreeOutside)(originalTarget, {
36
36
  parentNode,
37
37
  markerName,
38
- controlAttribute: "aria-hidden",
39
- explicitBooleanValue: true,
38
+ attribute: "aria-hidden",
40
39
  followControlledElements
41
40
  });
42
41
  };
@@ -45,8 +44,7 @@ var inertOthers = (originalTarget, parentNode = getParentNode(originalTarget), m
45
44
  return (0, import_walk_tree_outside.walkTreeOutside)(originalTarget, {
46
45
  parentNode,
47
46
  markerName,
48
- controlAttribute: "inert",
49
- explicitBooleanValue: false,
47
+ attribute: "inert",
50
48
  followControlledElements
51
49
  });
52
50
  };
@@ -9,8 +9,7 @@ var hideOthers = (originalTarget, parentNode = getParentNode(originalTarget), ma
9
9
  return walkTreeOutside(originalTarget, {
10
10
  parentNode,
11
11
  markerName,
12
- controlAttribute: "aria-hidden",
13
- explicitBooleanValue: true,
12
+ attribute: "aria-hidden",
14
13
  followControlledElements
15
14
  });
16
15
  };
@@ -19,8 +18,7 @@ var inertOthers = (originalTarget, parentNode = getParentNode(originalTarget), m
19
18
  return walkTreeOutside(originalTarget, {
20
19
  parentNode,
21
20
  markerName,
22
- controlAttribute: "inert",
23
- explicitBooleanValue: false,
21
+ attribute: "inert",
24
22
  followControlledElements
25
23
  });
26
24
  };
@@ -1,8 +1,7 @@
1
1
  interface WalkTreeOutsideOptions {
2
2
  parentNode: HTMLElement;
3
3
  markerName: string;
4
- controlAttribute: string;
5
- explicitBooleanValue: boolean;
4
+ attribute: "aria-hidden" | "inert";
6
5
  followControlledElements?: boolean;
7
6
  }
8
7
  declare const walkTreeOutside: (originalTarget: Element | Element[], props: WalkTreeOutsideOptions) => VoidFunction;
@@ -1,8 +1,7 @@
1
1
  interface WalkTreeOutsideOptions {
2
2
  parentNode: HTMLElement;
3
3
  markerName: string;
4
- controlAttribute: string;
5
- explicitBooleanValue: boolean;
4
+ attribute: "aria-hidden" | "inert";
6
5
  followControlledElements?: boolean;
7
6
  }
8
7
  declare const walkTreeOutside: (originalTarget: Element | Element[], props: WalkTreeOutsideOptions) => VoidFunction;
@@ -45,9 +45,12 @@ var isIgnoredNode = (node) => {
45
45
  if (node.hasAttribute("aria-live")) return true;
46
46
  return node.matches("[data-live-announcer]");
47
47
  };
48
- var walkTreeOutside = (originalTarget, props) => {
49
- const { parentNode, markerName, controlAttribute, explicitBooleanValue, followControlledElements = true } = props;
50
- const targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
48
+ var applyAttributeToOthers = (allTargets, props) => {
49
+ const { parentNode, markerName, attribute, followControlledElements = true } = props;
50
+ const attributeValue = attribute === "aria-hidden" ? "true" : "";
51
+ const targets = allTargets.filter((target) => parentNode.contains(target));
52
+ if (!targets.length) return () => {
53
+ };
51
54
  markerMap[markerName] || (markerMap[markerName] = /* @__PURE__ */ new WeakMap());
52
55
  const markerCounter = markerMap[markerName];
53
56
  const hiddenNodes = [];
@@ -63,6 +66,7 @@ var walkTreeOutside = (originalTarget, props) => {
63
66
  if (followControlledElements && (0, import_dom_query.isHTMLElement)(target)) {
64
67
  (0, import_dom_query.findControlledElements)(target, (controlledElement) => {
65
68
  keep(controlledElement);
69
+ elementsToStop.add(controlledElement);
66
70
  });
67
71
  }
68
72
  });
@@ -76,8 +80,7 @@ var walkTreeOutside = (originalTarget, props) => {
76
80
  } else {
77
81
  try {
78
82
  if (isIgnoredNode(node)) return;
79
- const attr = node.getAttribute(controlAttribute);
80
- const alreadyHidden = explicitBooleanValue ? attr === "true" : attr !== null && attr !== "false";
83
+ const alreadyHidden = attribute === "aria-hidden" ? node.getAttribute(attribute) === "true" : node.hasAttribute(attribute);
81
84
  const counterValue = (counterMap.get(node) || 0) + 1;
82
85
  const markerValue = (markerCounter.get(node) || 0) + 1;
83
86
  counterMap.set(node, counterValue);
@@ -90,7 +93,7 @@ var walkTreeOutside = (originalTarget, props) => {
90
93
  node.setAttribute(markerName, "");
91
94
  }
92
95
  if (!alreadyHidden) {
93
- node.setAttribute(controlAttribute, explicitBooleanValue ? "true" : "");
96
+ node.setAttribute(attribute, attributeValue);
94
97
  }
95
98
  } catch (e) {
96
99
  console.error("[zag-js > ariaHidden] cannot operate on ", node, e);
@@ -109,7 +112,7 @@ var walkTreeOutside = (originalTarget, props) => {
109
112
  markerCounter.set(node, markerValue);
110
113
  if (!counterValue) {
111
114
  if (!uncontrolledNodes.has(node)) {
112
- node.removeAttribute(controlAttribute);
115
+ node.removeAttribute(attribute);
113
116
  }
114
117
  uncontrolledNodes.delete(node);
115
118
  }
@@ -119,13 +122,77 @@ var walkTreeOutside = (originalTarget, props) => {
119
122
  });
120
123
  lockCount--;
121
124
  if (!lockCount) {
122
- counterMap = /* @__PURE__ */ new WeakMap();
123
125
  counterMap = /* @__PURE__ */ new WeakMap();
124
126
  uncontrolledNodes = /* @__PURE__ */ new WeakMap();
125
127
  markerMap = {};
126
128
  }
127
129
  };
128
130
  };
131
+ function createLockStack() {
132
+ const locks = [];
133
+ return {
134
+ add(lock) {
135
+ locks[locks.length - 1]?.pause();
136
+ locks.push(lock);
137
+ lock.resume();
138
+ },
139
+ remove(lock) {
140
+ const index = locks.indexOf(lock);
141
+ if (index === -1) return;
142
+ const isTop = index === locks.length - 1;
143
+ locks.splice(index, 1);
144
+ if (!isTop) return;
145
+ lock.pause();
146
+ locks[locks.length - 1]?.resume();
147
+ }
148
+ };
149
+ }
150
+ var lockStacks = /* @__PURE__ */ new WeakMap();
151
+ var getLockStack = (doc) => {
152
+ let stack = lockStacks.get(doc);
153
+ if (!stack) {
154
+ stack = createLockStack();
155
+ lockStacks.set(doc, stack);
156
+ }
157
+ return stack;
158
+ };
159
+ var walkTreeOutside = (originalTarget, props) => {
160
+ const { parentNode, attribute, followControlledElements = true } = props;
161
+ const targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
162
+ if (!targets.length) return () => {
163
+ };
164
+ const hiddenSelector = attribute === "aria-hidden" ? '[aria-hidden="true"]' : "[inert]";
165
+ let undo;
166
+ let observer;
167
+ const apply = () => {
168
+ const prevUndo = undo;
169
+ undo = applyAttributeToOthers(targets, props);
170
+ prevUndo?.();
171
+ };
172
+ const release = () => {
173
+ undo?.();
174
+ undo = void 0;
175
+ };
176
+ const lock = {
177
+ pause() {
178
+ observer?.disconnect();
179
+ observer = void 0;
180
+ release();
181
+ },
182
+ resume() {
183
+ apply();
184
+ if (!followControlledElements) return;
185
+ const win = (0, import_dom_query.getWindow)(parentNode);
186
+ observer = new win.MutationObserver((records) => {
187
+ if (records.some(({ target }) => (0, import_dom_query.isElement)(target) && !target.closest(hiddenSelector))) apply();
188
+ });
189
+ observer.observe(parentNode, { attributes: true, attributeFilter: ["aria-expanded"], subtree: true });
190
+ }
191
+ };
192
+ const lockStack = getLockStack(parentNode.ownerDocument);
193
+ lockStack.add(lock);
194
+ return () => lockStack.remove(lock);
195
+ };
129
196
  // Annotate the CommonJS export names for ESM import in node:
130
197
  0 && (module.exports = {
131
198
  walkTreeOutside
@@ -1,5 +1,5 @@
1
1
  // src/walk-tree-outside.ts
2
- import { findControlledElements, isHTMLElement } from "@zag-js/dom-query";
2
+ import { findControlledElements, getWindow, isElement, isHTMLElement } from "@zag-js/dom-query";
3
3
  var counterMap = /* @__PURE__ */ new WeakMap();
4
4
  var uncontrolledNodes = /* @__PURE__ */ new WeakMap();
5
5
  var markerMap = {};
@@ -21,9 +21,12 @@ var isIgnoredNode = (node) => {
21
21
  if (node.hasAttribute("aria-live")) return true;
22
22
  return node.matches("[data-live-announcer]");
23
23
  };
24
- var walkTreeOutside = (originalTarget, props) => {
25
- const { parentNode, markerName, controlAttribute, explicitBooleanValue, followControlledElements = true } = props;
26
- const targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
24
+ var applyAttributeToOthers = (allTargets, props) => {
25
+ const { parentNode, markerName, attribute, followControlledElements = true } = props;
26
+ const attributeValue = attribute === "aria-hidden" ? "true" : "";
27
+ const targets = allTargets.filter((target) => parentNode.contains(target));
28
+ if (!targets.length) return () => {
29
+ };
27
30
  markerMap[markerName] || (markerMap[markerName] = /* @__PURE__ */ new WeakMap());
28
31
  const markerCounter = markerMap[markerName];
29
32
  const hiddenNodes = [];
@@ -39,6 +42,7 @@ var walkTreeOutside = (originalTarget, props) => {
39
42
  if (followControlledElements && isHTMLElement(target)) {
40
43
  findControlledElements(target, (controlledElement) => {
41
44
  keep(controlledElement);
45
+ elementsToStop.add(controlledElement);
42
46
  });
43
47
  }
44
48
  });
@@ -52,8 +56,7 @@ var walkTreeOutside = (originalTarget, props) => {
52
56
  } else {
53
57
  try {
54
58
  if (isIgnoredNode(node)) return;
55
- const attr = node.getAttribute(controlAttribute);
56
- const alreadyHidden = explicitBooleanValue ? attr === "true" : attr !== null && attr !== "false";
59
+ const alreadyHidden = attribute === "aria-hidden" ? node.getAttribute(attribute) === "true" : node.hasAttribute(attribute);
57
60
  const counterValue = (counterMap.get(node) || 0) + 1;
58
61
  const markerValue = (markerCounter.get(node) || 0) + 1;
59
62
  counterMap.set(node, counterValue);
@@ -66,7 +69,7 @@ var walkTreeOutside = (originalTarget, props) => {
66
69
  node.setAttribute(markerName, "");
67
70
  }
68
71
  if (!alreadyHidden) {
69
- node.setAttribute(controlAttribute, explicitBooleanValue ? "true" : "");
72
+ node.setAttribute(attribute, attributeValue);
70
73
  }
71
74
  } catch (e) {
72
75
  console.error("[zag-js > ariaHidden] cannot operate on ", node, e);
@@ -85,7 +88,7 @@ var walkTreeOutside = (originalTarget, props) => {
85
88
  markerCounter.set(node, markerValue);
86
89
  if (!counterValue) {
87
90
  if (!uncontrolledNodes.has(node)) {
88
- node.removeAttribute(controlAttribute);
91
+ node.removeAttribute(attribute);
89
92
  }
90
93
  uncontrolledNodes.delete(node);
91
94
  }
@@ -95,13 +98,77 @@ var walkTreeOutside = (originalTarget, props) => {
95
98
  });
96
99
  lockCount--;
97
100
  if (!lockCount) {
98
- counterMap = /* @__PURE__ */ new WeakMap();
99
101
  counterMap = /* @__PURE__ */ new WeakMap();
100
102
  uncontrolledNodes = /* @__PURE__ */ new WeakMap();
101
103
  markerMap = {};
102
104
  }
103
105
  };
104
106
  };
107
+ function createLockStack() {
108
+ const locks = [];
109
+ return {
110
+ add(lock) {
111
+ locks[locks.length - 1]?.pause();
112
+ locks.push(lock);
113
+ lock.resume();
114
+ },
115
+ remove(lock) {
116
+ const index = locks.indexOf(lock);
117
+ if (index === -1) return;
118
+ const isTop = index === locks.length - 1;
119
+ locks.splice(index, 1);
120
+ if (!isTop) return;
121
+ lock.pause();
122
+ locks[locks.length - 1]?.resume();
123
+ }
124
+ };
125
+ }
126
+ var lockStacks = /* @__PURE__ */ new WeakMap();
127
+ var getLockStack = (doc) => {
128
+ let stack = lockStacks.get(doc);
129
+ if (!stack) {
130
+ stack = createLockStack();
131
+ lockStacks.set(doc, stack);
132
+ }
133
+ return stack;
134
+ };
135
+ var walkTreeOutside = (originalTarget, props) => {
136
+ const { parentNode, attribute, followControlledElements = true } = props;
137
+ const targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
138
+ if (!targets.length) return () => {
139
+ };
140
+ const hiddenSelector = attribute === "aria-hidden" ? '[aria-hidden="true"]' : "[inert]";
141
+ let undo;
142
+ let observer;
143
+ const apply = () => {
144
+ const prevUndo = undo;
145
+ undo = applyAttributeToOthers(targets, props);
146
+ prevUndo?.();
147
+ };
148
+ const release = () => {
149
+ undo?.();
150
+ undo = void 0;
151
+ };
152
+ const lock = {
153
+ pause() {
154
+ observer?.disconnect();
155
+ observer = void 0;
156
+ release();
157
+ },
158
+ resume() {
159
+ apply();
160
+ if (!followControlledElements) return;
161
+ const win = getWindow(parentNode);
162
+ observer = new win.MutationObserver((records) => {
163
+ if (records.some(({ target }) => isElement(target) && !target.closest(hiddenSelector))) apply();
164
+ });
165
+ observer.observe(parentNode, { attributes: true, attributeFilter: ["aria-expanded"], subtree: true });
166
+ }
167
+ };
168
+ const lockStack = getLockStack(parentNode.ownerDocument);
169
+ lockStack.add(lock);
170
+ return () => lockStack.remove(lock);
171
+ };
105
172
  export {
106
173
  walkTreeOutside
107
174
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/aria-hidden",
3
- "version": "1.45.0",
3
+ "version": "1.46.0",
4
4
  "description": "Hide targets from screen readers",
5
5
  "keywords": [
6
6
  "js",
@@ -27,7 +27,7 @@
27
27
  "clean-package": "../../../clean-package.config.json",
28
28
  "main": "dist/index.js",
29
29
  "dependencies": {
30
- "@zag-js/dom-query": "1.45.0"
30
+ "@zag-js/dom-query": "1.46.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "clean-package": "2.2.0"