@zag-js/dismissable 1.39.1 → 1.41.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.
@@ -1,6 +1,6 @@
1
1
  import { InteractOutsideHandlers } from '@zag-js/interact-outside';
2
2
  import { MaybeFunction } from '@zag-js/utils';
3
- import { LayerDismissEvent, LayerType } from './layer-stack.mjs';
3
+ import { LayerDismissEvent, LayerStyleTarget, LayerType } from './layer-stack.mjs';
4
4
 
5
5
  type MaybeElement = HTMLElement | null;
6
6
  type Container = MaybeElement | Array<MaybeElement>;
@@ -24,6 +24,12 @@ interface PersistentElementOptions {
24
24
  persistentElements?: Array<() => Element | null> | undefined;
25
25
  }
26
26
  interface DismissableElementOptions extends DismissableElementHandlers, PersistentElementOptions {
27
+ /**
28
+ * Extra elements that receive the same layer stack CSS vars, `data-*`, and `--z-index`
29
+ * (from the primary node's computed `z-index`) as the dismissable node
30
+ * (e.g. dialog backdrop + positioner when the node is content).
31
+ */
32
+ layerStyleTargets?: LayerStyleTarget[] | undefined;
27
33
  /**
28
34
  * Whether to log debug information
29
35
  */
@@ -1,6 +1,6 @@
1
1
  import { InteractOutsideHandlers } from '@zag-js/interact-outside';
2
2
  import { MaybeFunction } from '@zag-js/utils';
3
- import { LayerDismissEvent, LayerType } from './layer-stack.js';
3
+ import { LayerDismissEvent, LayerStyleTarget, LayerType } from './layer-stack.js';
4
4
 
5
5
  type MaybeElement = HTMLElement | null;
6
6
  type Container = MaybeElement | Array<MaybeElement>;
@@ -24,6 +24,12 @@ interface PersistentElementOptions {
24
24
  persistentElements?: Array<() => Element | null> | undefined;
25
25
  }
26
26
  interface DismissableElementOptions extends DismissableElementHandlers, PersistentElementOptions {
27
+ /**
28
+ * Extra elements that receive the same layer stack CSS vars, `data-*`, and `--z-index`
29
+ * (from the primary node's computed `z-index`) as the dismissable node
30
+ * (e.g. dialog backdrop + positioner when the node is content).
31
+ */
32
+ layerStyleTargets?: LayerStyleTarget[] | undefined;
27
33
  /**
28
34
  * Whether to log debug information
29
35
  */
@@ -39,8 +39,23 @@ function trackDismissableElementImpl(node, options) {
39
39
  if (!node) {
40
40
  return;
41
41
  }
42
- const { onDismiss, onRequestDismiss, pointerBlocking, exclude: excludeContainers, debug, type = "dialog" } = options;
43
- const layer = { dismiss: onDismiss, node, type, pointerBlocking, requestDismiss: onRequestDismiss };
42
+ const {
43
+ onDismiss,
44
+ onRequestDismiss,
45
+ pointerBlocking,
46
+ exclude: excludeContainers,
47
+ debug,
48
+ type = "dialog",
49
+ layerStyleTargets
50
+ } = options;
51
+ const layer = {
52
+ dismiss: onDismiss,
53
+ node,
54
+ type,
55
+ pointerBlocking,
56
+ requestDismiss: onRequestDismiss,
57
+ styleTargets: layerStyleTargets
58
+ };
44
59
  import_layer_stack.layerStack.add(layer);
45
60
  (0, import_pointer_event_outside.assignPointerEventToLayers)();
46
61
  function onPointerDownOutside(event) {
@@ -16,8 +16,23 @@ function trackDismissableElementImpl(node, options) {
16
16
  if (!node) {
17
17
  return;
18
18
  }
19
- const { onDismiss, onRequestDismiss, pointerBlocking, exclude: excludeContainers, debug, type = "dialog" } = options;
20
- const layer = { dismiss: onDismiss, node, type, pointerBlocking, requestDismiss: onRequestDismiss };
19
+ const {
20
+ onDismiss,
21
+ onRequestDismiss,
22
+ pointerBlocking,
23
+ exclude: excludeContainers,
24
+ debug,
25
+ type = "dialog",
26
+ layerStyleTargets
27
+ } = options;
28
+ const layer = {
29
+ dismiss: onDismiss,
30
+ node,
31
+ type,
32
+ pointerBlocking,
33
+ requestDismiss: onRequestDismiss,
34
+ styleTargets: layerStyleTargets
35
+ };
21
36
  layerStack.add(layer);
22
37
  assignPointerEventToLayers();
23
38
  function onPointerDownOutside(event) {
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { FocusOutsideEvent, InteractOutsideEvent, InteractOutsideHandlers, PointerDownOutsideEvent } from '@zag-js/interact-outside';
2
2
  export { DismissableElementHandlers, DismissableElementOptions, PersistentElementOptions, trackDismissableBranch, trackDismissableElement } from './dismissable-layer.mjs';
3
- export { LayerType } from './layer-stack.mjs';
3
+ export { LayerStyleTarget, LayerType } from './layer-stack.mjs';
4
4
  import '@zag-js/utils';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { FocusOutsideEvent, InteractOutsideEvent, InteractOutsideHandlers, PointerDownOutsideEvent } from '@zag-js/interact-outside';
2
2
  export { DismissableElementHandlers, DismissableElementOptions, PersistentElementOptions, trackDismissableBranch, trackDismissableElement } from './dismissable-layer.js';
3
- export { LayerType } from './layer-stack.js';
3
+ export { LayerStyleTarget, LayerType } from './layer-stack.js';
4
4
  import '@zag-js/utils';
@@ -6,12 +6,14 @@ type LayerDismissEventDetail = {
6
6
  targetIndex: number;
7
7
  };
8
8
  type LayerDismissEvent = CustomEvent<LayerDismissEventDetail>;
9
+ type LayerStyleTarget = () => HTMLElement | null;
9
10
  interface Layer {
10
11
  dismiss: VoidFunction;
11
12
  node: HTMLElement;
12
13
  type: LayerType;
13
14
  pointerBlocking?: boolean | undefined;
14
15
  requestDismiss?: ((event: LayerDismissEvent) => void) | undefined;
16
+ styleTargets?: LayerStyleTarget[] | undefined;
15
17
  }
16
18
  declare const layerStack: {
17
19
  layers: Layer[];
@@ -40,4 +42,4 @@ declare const layerStack: {
40
42
  clear(): void;
41
43
  };
42
44
 
43
- export { type Layer, type LayerDismissEvent, type LayerDismissEventDetail, type LayerType, layerStack };
45
+ export { type Layer, type LayerDismissEvent, type LayerDismissEventDetail, type LayerStyleTarget, type LayerType, layerStack };
@@ -6,12 +6,14 @@ type LayerDismissEventDetail = {
6
6
  targetIndex: number;
7
7
  };
8
8
  type LayerDismissEvent = CustomEvent<LayerDismissEventDetail>;
9
+ type LayerStyleTarget = () => HTMLElement | null;
9
10
  interface Layer {
10
11
  dismiss: VoidFunction;
11
12
  node: HTMLElement;
12
13
  type: LayerType;
13
14
  pointerBlocking?: boolean | undefined;
14
15
  requestDismiss?: ((event: LayerDismissEvent) => void) | undefined;
16
+ styleTargets?: LayerStyleTarget[] | undefined;
15
17
  }
16
18
  declare const layerStack: {
17
19
  layers: Layer[];
@@ -40,4 +42,4 @@ declare const layerStack: {
40
42
  clear(): void;
41
43
  };
42
44
 
43
- export { type Layer, type LayerDismissEvent, type LayerDismissEventDetail, type LayerType, layerStack };
45
+ export { type Layer, type LayerDismissEvent, type LayerDismissEventDetail, type LayerStyleTarget, type LayerType, layerStack };
@@ -79,6 +79,10 @@ var layerStack = {
79
79
  return Array.from(this.branches).some((branch) => (0, import_dom_query.contains)(branch, target));
80
80
  },
81
81
  add(layer) {
82
+ const existingIndex = this.indexOf(layer.node);
83
+ if (existingIndex !== -1) {
84
+ this.layers.splice(existingIndex, 1);
85
+ }
82
86
  this.layers.push(layer);
83
87
  this.syncLayers();
84
88
  },
@@ -88,11 +92,18 @@ var layerStack = {
88
92
  remove(node) {
89
93
  const index = this.indexOf(node);
90
94
  if (index < 0) return;
95
+ const layer = this.layers[index];
96
+ layer.styleTargets?.forEach((getTarget) => {
97
+ const target = getTarget();
98
+ if (target) {
99
+ clearLayerStyleMirror(target);
100
+ }
101
+ });
91
102
  this.recentlyRemoved.add(node);
92
103
  (0, import_dom_query.nextTick)(() => this.recentlyRemoved.delete(node));
93
104
  if (index < this.count() - 1) {
94
105
  const _layers = this.getNestedLayers(node);
95
- _layers.forEach((layer) => layerStack.dismiss(layer.node, node));
106
+ _layers.forEach((layer2) => layerStack.dismiss(layer2.node, node));
96
107
  }
97
108
  this.layers.splice(index, 1);
98
109
  this.syncLayers();
@@ -103,18 +114,14 @@ var layerStack = {
103
114
  },
104
115
  syncLayers() {
105
116
  this.layers.forEach((layer, index) => {
106
- layer.node.style.setProperty("--layer-index", `${index}`);
107
- layer.node.removeAttribute("data-nested");
108
- layer.node.removeAttribute("data-has-nested");
109
- const parentOfSameType = this.getParentLayerOfType(layer.node, layer.type);
110
- if (parentOfSameType) {
111
- layer.node.setAttribute("data-nested", layer.type);
112
- }
113
- const nestedCount = this.countNestedLayersOfType(layer.node, layer.type);
114
- if (nestedCount > 0) {
115
- layer.node.setAttribute("data-has-nested", layer.type);
116
- }
117
- layer.node.style.setProperty("--nested-layer-count", `${nestedCount}`);
117
+ applyLayerStackMetadata(layer, index, layer.node);
118
+ layer.styleTargets?.forEach((getTarget) => {
119
+ const target = getTarget();
120
+ if (!target || target === layer.node) return;
121
+ applyLayerStackMetadata(layer, index, target);
122
+ const { zIndex } = (0, import_dom_query.getComputedStyle)(layer.node);
123
+ target.style.setProperty("--z-index", zIndex);
124
+ });
118
125
  });
119
126
  },
120
127
  indexOf(node) {
@@ -142,6 +149,27 @@ var layerStack = {
142
149
  this.remove(this.layers[0].node);
143
150
  }
144
151
  };
152
+ function applyLayerStackMetadata(layer, index, el) {
153
+ el.style.setProperty("--layer-index", `${index}`);
154
+ el.removeAttribute("data-nested");
155
+ el.removeAttribute("data-has-nested");
156
+ const parentOfSameType = layerStack.getParentLayerOfType(layer.node, layer.type);
157
+ if (parentOfSameType) {
158
+ el.setAttribute("data-nested", layer.type);
159
+ }
160
+ const nestedCount = layerStack.countNestedLayersOfType(layer.node, layer.type);
161
+ if (nestedCount > 0) {
162
+ el.setAttribute("data-has-nested", layer.type);
163
+ }
164
+ el.style.setProperty("--nested-layer-count", `${nestedCount}`);
165
+ }
166
+ function clearLayerStyleMirror(el) {
167
+ el.style.removeProperty("--layer-index");
168
+ el.style.removeProperty("--nested-layer-count");
169
+ el.style.removeProperty("--z-index");
170
+ el.removeAttribute("data-nested");
171
+ el.removeAttribute("data-has-nested");
172
+ }
145
173
  function fireCustomEvent(el, type, detail) {
146
174
  const win = el.ownerDocument.defaultView || window;
147
175
  const event = new win.CustomEvent(type, { cancelable: true, bubbles: true, detail });
@@ -1,5 +1,5 @@
1
1
  // src/layer-stack.ts
2
- import { contains, nextTick } from "@zag-js/dom-query";
2
+ import { contains, nextTick, getComputedStyle } from "@zag-js/dom-query";
3
3
  var LAYER_REQUEST_DISMISS_EVENT = "layer:request-dismiss";
4
4
  var layerStack = {
5
5
  layers: [],
@@ -55,6 +55,10 @@ var layerStack = {
55
55
  return Array.from(this.branches).some((branch) => contains(branch, target));
56
56
  },
57
57
  add(layer) {
58
+ const existingIndex = this.indexOf(layer.node);
59
+ if (existingIndex !== -1) {
60
+ this.layers.splice(existingIndex, 1);
61
+ }
58
62
  this.layers.push(layer);
59
63
  this.syncLayers();
60
64
  },
@@ -64,11 +68,18 @@ var layerStack = {
64
68
  remove(node) {
65
69
  const index = this.indexOf(node);
66
70
  if (index < 0) return;
71
+ const layer = this.layers[index];
72
+ layer.styleTargets?.forEach((getTarget) => {
73
+ const target = getTarget();
74
+ if (target) {
75
+ clearLayerStyleMirror(target);
76
+ }
77
+ });
67
78
  this.recentlyRemoved.add(node);
68
79
  nextTick(() => this.recentlyRemoved.delete(node));
69
80
  if (index < this.count() - 1) {
70
81
  const _layers = this.getNestedLayers(node);
71
- _layers.forEach((layer) => layerStack.dismiss(layer.node, node));
82
+ _layers.forEach((layer2) => layerStack.dismiss(layer2.node, node));
72
83
  }
73
84
  this.layers.splice(index, 1);
74
85
  this.syncLayers();
@@ -79,18 +90,14 @@ var layerStack = {
79
90
  },
80
91
  syncLayers() {
81
92
  this.layers.forEach((layer, index) => {
82
- layer.node.style.setProperty("--layer-index", `${index}`);
83
- layer.node.removeAttribute("data-nested");
84
- layer.node.removeAttribute("data-has-nested");
85
- const parentOfSameType = this.getParentLayerOfType(layer.node, layer.type);
86
- if (parentOfSameType) {
87
- layer.node.setAttribute("data-nested", layer.type);
88
- }
89
- const nestedCount = this.countNestedLayersOfType(layer.node, layer.type);
90
- if (nestedCount > 0) {
91
- layer.node.setAttribute("data-has-nested", layer.type);
92
- }
93
- layer.node.style.setProperty("--nested-layer-count", `${nestedCount}`);
93
+ applyLayerStackMetadata(layer, index, layer.node);
94
+ layer.styleTargets?.forEach((getTarget) => {
95
+ const target = getTarget();
96
+ if (!target || target === layer.node) return;
97
+ applyLayerStackMetadata(layer, index, target);
98
+ const { zIndex } = getComputedStyle(layer.node);
99
+ target.style.setProperty("--z-index", zIndex);
100
+ });
94
101
  });
95
102
  },
96
103
  indexOf(node) {
@@ -118,6 +125,27 @@ var layerStack = {
118
125
  this.remove(this.layers[0].node);
119
126
  }
120
127
  };
128
+ function applyLayerStackMetadata(layer, index, el) {
129
+ el.style.setProperty("--layer-index", `${index}`);
130
+ el.removeAttribute("data-nested");
131
+ el.removeAttribute("data-has-nested");
132
+ const parentOfSameType = layerStack.getParentLayerOfType(layer.node, layer.type);
133
+ if (parentOfSameType) {
134
+ el.setAttribute("data-nested", layer.type);
135
+ }
136
+ const nestedCount = layerStack.countNestedLayersOfType(layer.node, layer.type);
137
+ if (nestedCount > 0) {
138
+ el.setAttribute("data-has-nested", layer.type);
139
+ }
140
+ el.style.setProperty("--nested-layer-count", `${nestedCount}`);
141
+ }
142
+ function clearLayerStyleMirror(el) {
143
+ el.style.removeProperty("--layer-index");
144
+ el.style.removeProperty("--nested-layer-count");
145
+ el.style.removeProperty("--z-index");
146
+ el.removeAttribute("data-nested");
147
+ el.removeAttribute("data-has-nested");
148
+ }
121
149
  function fireCustomEvent(el, type, detail) {
122
150
  const win = el.ownerDocument.defaultView || window;
123
151
  const event = new win.CustomEvent(type, { cancelable: true, bubbles: true, detail });
@@ -40,10 +40,12 @@ function disablePointerEventsOutside(node, persistentElements) {
40
40
  const doc = (0, import_dom_query.getDocument)(node);
41
41
  const cleanups = [];
42
42
  if (import_layer_stack.layerStack.hasPointerBlockingLayer() && !doc.body.hasAttribute("data-inert")) {
43
- originalBodyPointerEvents = document.body.style.pointerEvents;
43
+ originalBodyPointerEvents = doc.body.style.pointerEvents;
44
44
  queueMicrotask(() => {
45
- doc.body.style.pointerEvents = "none";
46
- doc.body.setAttribute("data-inert", "");
45
+ const body = doc.body;
46
+ if (!body) return;
47
+ body.style.pointerEvents = "none";
48
+ body.setAttribute("data-inert", "");
47
49
  });
48
50
  }
49
51
  persistentElements?.forEach((el) => {
@@ -60,9 +62,11 @@ function disablePointerEventsOutside(node, persistentElements) {
60
62
  return () => {
61
63
  if (import_layer_stack.layerStack.hasPointerBlockingLayer()) return;
62
64
  queueMicrotask(() => {
63
- doc.body.style.pointerEvents = originalBodyPointerEvents;
64
- doc.body.removeAttribute("data-inert");
65
- if (doc.body.style.length === 0) doc.body.removeAttribute("style");
65
+ const body = doc.body;
66
+ if (!body) return;
67
+ body.style.pointerEvents = originalBodyPointerEvents;
68
+ body.removeAttribute("data-inert");
69
+ if (body.style.length === 0) body.removeAttribute("style");
66
70
  });
67
71
  cleanups.forEach((fn) => fn());
68
72
  };
@@ -14,10 +14,12 @@ function disablePointerEventsOutside(node, persistentElements) {
14
14
  const doc = getDocument(node);
15
15
  const cleanups = [];
16
16
  if (layerStack.hasPointerBlockingLayer() && !doc.body.hasAttribute("data-inert")) {
17
- originalBodyPointerEvents = document.body.style.pointerEvents;
17
+ originalBodyPointerEvents = doc.body.style.pointerEvents;
18
18
  queueMicrotask(() => {
19
- doc.body.style.pointerEvents = "none";
20
- doc.body.setAttribute("data-inert", "");
19
+ const body = doc.body;
20
+ if (!body) return;
21
+ body.style.pointerEvents = "none";
22
+ body.setAttribute("data-inert", "");
21
23
  });
22
24
  }
23
25
  persistentElements?.forEach((el) => {
@@ -34,9 +36,11 @@ function disablePointerEventsOutside(node, persistentElements) {
34
36
  return () => {
35
37
  if (layerStack.hasPointerBlockingLayer()) return;
36
38
  queueMicrotask(() => {
37
- doc.body.style.pointerEvents = originalBodyPointerEvents;
38
- doc.body.removeAttribute("data-inert");
39
- if (doc.body.style.length === 0) doc.body.removeAttribute("style");
39
+ const body = doc.body;
40
+ if (!body) return;
41
+ body.style.pointerEvents = originalBodyPointerEvents;
42
+ body.removeAttribute("data-inert");
43
+ if (body.style.length === 0) body.removeAttribute("style");
40
44
  });
41
45
  cleanups.forEach((fn) => fn());
42
46
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/dismissable",
3
- "version": "1.39.1",
3
+ "version": "1.41.0",
4
4
  "description": "Dismissable layer utilities for the DOM",
5
5
  "keywords": [
6
6
  "js",
@@ -23,9 +23,9 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@zag-js/interact-outside": "1.39.1",
27
- "@zag-js/dom-query": "1.39.1",
28
- "@zag-js/utils": "1.39.1"
26
+ "@zag-js/interact-outside": "1.41.0",
27
+ "@zag-js/dom-query": "1.41.0",
28
+ "@zag-js/utils": "1.41.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "clean-package": "2.2.0"