@zag-js/dismissable 0.70.0 → 0.72.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.
- package/dist/index.js +25 -61
- package/dist/index.mjs +9 -22
- package/package.json +7 -8
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/src/dismissable-layer.ts +0 -164
- package/src/escape-keydown.ts +0 -12
- package/src/index.ts +0 -7
- package/src/layer-stack.ts +0 -77
- package/src/pointer-event-outside.ts +0 -45
package/dist/index.js
CHANGED
|
@@ -1,49 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
'use strict';
|
|
19
2
|
|
|
20
|
-
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
trackDismissableElement: () => trackDismissableElement
|
|
25
|
-
});
|
|
26
|
-
module.exports = __toCommonJS(src_exports);
|
|
3
|
+
var domQuery = require('@zag-js/dom-query');
|
|
4
|
+
var interactOutside = require('@zag-js/interact-outside');
|
|
5
|
+
var utils = require('@zag-js/utils');
|
|
6
|
+
var domEvent = require('@zag-js/dom-event');
|
|
27
7
|
|
|
28
8
|
// src/dismissable-layer.ts
|
|
29
|
-
var import_dom_query4 = require("@zag-js/dom-query");
|
|
30
|
-
var import_interact_outside = require("@zag-js/interact-outside");
|
|
31
|
-
var import_utils = require("@zag-js/utils");
|
|
32
|
-
|
|
33
|
-
// src/escape-keydown.ts
|
|
34
|
-
var import_dom_event = require("@zag-js/dom-event");
|
|
35
|
-
var import_dom_query = require("@zag-js/dom-query");
|
|
36
9
|
function trackEscapeKeydown(node, fn) {
|
|
37
10
|
const handleKeyDown = (event) => {
|
|
38
11
|
if (event.key !== "Escape") return;
|
|
39
12
|
if (event.isComposing) return;
|
|
40
13
|
fn?.(event);
|
|
41
14
|
};
|
|
42
|
-
return
|
|
15
|
+
return domEvent.addDomEvent(domQuery.getDocument(node), "keydown", handleKeyDown, { capture: true });
|
|
43
16
|
}
|
|
44
|
-
|
|
45
|
-
// src/layer-stack.ts
|
|
46
|
-
var import_dom_query2 = require("@zag-js/dom-query");
|
|
47
17
|
var layerStack = {
|
|
48
18
|
layers: [],
|
|
49
19
|
branches: [],
|
|
@@ -72,10 +42,10 @@ var layerStack = {
|
|
|
72
42
|
return Array.from(this.layers).slice(this.indexOf(node) + 1);
|
|
73
43
|
},
|
|
74
44
|
isInNestedLayer(node, target) {
|
|
75
|
-
return this.getNestedLayers(node).some((layer) =>
|
|
45
|
+
return this.getNestedLayers(node).some((layer) => domQuery.contains(layer.node, target));
|
|
76
46
|
},
|
|
77
47
|
isInBranch(target) {
|
|
78
|
-
return Array.from(this.branches).some((branch) =>
|
|
48
|
+
return Array.from(this.branches).some((branch) => domQuery.contains(branch, target));
|
|
79
49
|
},
|
|
80
50
|
add(layer) {
|
|
81
51
|
const num = this.layers.push(layer);
|
|
@@ -108,9 +78,6 @@ var layerStack = {
|
|
|
108
78
|
this.remove(this.layers[0].node);
|
|
109
79
|
}
|
|
110
80
|
};
|
|
111
|
-
|
|
112
|
-
// src/pointer-event-outside.ts
|
|
113
|
-
var import_dom_query3 = require("@zag-js/dom-query");
|
|
114
81
|
var originalBodyPointerEvents;
|
|
115
82
|
function assignPointerEventToLayers() {
|
|
116
83
|
layerStack.layers.forEach(({ node }) => {
|
|
@@ -121,7 +88,7 @@ function clearPointerEvent(node) {
|
|
|
121
88
|
node.style.pointerEvents = "";
|
|
122
89
|
}
|
|
123
90
|
function disablePointerEventsOutside(node, peristentElements) {
|
|
124
|
-
const doc =
|
|
91
|
+
const doc = domQuery.getDocument(node);
|
|
125
92
|
const cleanups = [];
|
|
126
93
|
if (layerStack.hasPointerBlockingLayer() && !doc.body.hasAttribute("data-inert")) {
|
|
127
94
|
originalBodyPointerEvents = document.body.style.pointerEvents;
|
|
@@ -131,8 +98,8 @@ function disablePointerEventsOutside(node, peristentElements) {
|
|
|
131
98
|
});
|
|
132
99
|
}
|
|
133
100
|
if (peristentElements) {
|
|
134
|
-
const persistedCleanup =
|
|
135
|
-
cleanups.push(
|
|
101
|
+
const persistedCleanup = domQuery.waitForElements(peristentElements, (el) => {
|
|
102
|
+
cleanups.push(domQuery.setStyle(el, { pointerEvents: "auto" }));
|
|
136
103
|
});
|
|
137
104
|
cleanups.push(persistedCleanup);
|
|
138
105
|
}
|
|
@@ -150,7 +117,7 @@ function disablePointerEventsOutside(node, peristentElements) {
|
|
|
150
117
|
// src/dismissable-layer.ts
|
|
151
118
|
function trackDismissableElementImpl(node, options) {
|
|
152
119
|
if (!node) {
|
|
153
|
-
|
|
120
|
+
utils.warn("[@zag-js/dismissable] node is `null` or `undefined`");
|
|
154
121
|
return;
|
|
155
122
|
}
|
|
156
123
|
const { onDismiss, pointerBlocking, exclude: excludeContainers, debug } = options;
|
|
@@ -158,7 +125,7 @@ function trackDismissableElementImpl(node, options) {
|
|
|
158
125
|
layerStack.add(layer);
|
|
159
126
|
assignPointerEventToLayers();
|
|
160
127
|
function onPointerDownOutside(event) {
|
|
161
|
-
const target =
|
|
128
|
+
const target = domQuery.getEventTarget(event.detail.originalEvent);
|
|
162
129
|
if (layerStack.isBelowPointerBlockingLayer(node) || layerStack.isInBranch(target)) return;
|
|
163
130
|
options.onPointerDownOutside?.(event);
|
|
164
131
|
options.onInteractOutside?.(event);
|
|
@@ -169,7 +136,7 @@ function trackDismissableElementImpl(node, options) {
|
|
|
169
136
|
onDismiss?.();
|
|
170
137
|
}
|
|
171
138
|
function onFocusOutside(event) {
|
|
172
|
-
const target =
|
|
139
|
+
const target = domQuery.getEventTarget(event.detail.originalEvent);
|
|
173
140
|
if (layerStack.isInBranch(target)) return;
|
|
174
141
|
options.onFocusOutside?.(event);
|
|
175
142
|
options.onInteractOutside?.(event);
|
|
@@ -191,14 +158,14 @@ function trackDismissableElementImpl(node, options) {
|
|
|
191
158
|
if (!node) return false;
|
|
192
159
|
const containers = typeof excludeContainers === "function" ? excludeContainers() : excludeContainers;
|
|
193
160
|
const _containers = Array.isArray(containers) ? containers : [containers];
|
|
194
|
-
const persistentElements = options.persistentElements?.map((fn) => fn()).filter(
|
|
161
|
+
const persistentElements = options.persistentElements?.map((fn) => fn()).filter(domQuery.isHTMLElement);
|
|
195
162
|
if (persistentElements) _containers.push(...persistentElements);
|
|
196
|
-
return _containers.some((node2) =>
|
|
163
|
+
return _containers.some((node2) => domQuery.contains(node2, target)) || layerStack.isInNestedLayer(node, target);
|
|
197
164
|
}
|
|
198
165
|
const cleanups = [
|
|
199
166
|
pointerBlocking ? disablePointerEventsOutside(node, options.persistentElements) : void 0,
|
|
200
167
|
trackEscapeKeydown(node, onEscapeKeyDown),
|
|
201
|
-
|
|
168
|
+
interactOutside.trackInteractOutside(node, { exclude, onFocusOutside, onPointerDownOutside, defer: options.defer })
|
|
202
169
|
];
|
|
203
170
|
return () => {
|
|
204
171
|
layerStack.remove(node);
|
|
@@ -209,11 +176,11 @@ function trackDismissableElementImpl(node, options) {
|
|
|
209
176
|
}
|
|
210
177
|
function trackDismissableElement(nodeOrFn, options) {
|
|
211
178
|
const { defer } = options;
|
|
212
|
-
const func = defer ?
|
|
179
|
+
const func = defer ? domQuery.raf : (v) => v();
|
|
213
180
|
const cleanups = [];
|
|
214
181
|
cleanups.push(
|
|
215
182
|
func(() => {
|
|
216
|
-
const node =
|
|
183
|
+
const node = utils.isFunction(nodeOrFn) ? nodeOrFn() : nodeOrFn;
|
|
217
184
|
cleanups.push(trackDismissableElementImpl(node, options));
|
|
218
185
|
})
|
|
219
186
|
);
|
|
@@ -223,13 +190,13 @@ function trackDismissableElement(nodeOrFn, options) {
|
|
|
223
190
|
}
|
|
224
191
|
function trackDismissableBranch(nodeOrFn, options = {}) {
|
|
225
192
|
const { defer } = options;
|
|
226
|
-
const func = defer ?
|
|
193
|
+
const func = defer ? domQuery.raf : (v) => v();
|
|
227
194
|
const cleanups = [];
|
|
228
195
|
cleanups.push(
|
|
229
196
|
func(() => {
|
|
230
|
-
const node =
|
|
197
|
+
const node = utils.isFunction(nodeOrFn) ? nodeOrFn() : nodeOrFn;
|
|
231
198
|
if (!node) {
|
|
232
|
-
|
|
199
|
+
utils.warn("[@zag-js/dismissable] branch node is `null` or `undefined`");
|
|
233
200
|
return;
|
|
234
201
|
}
|
|
235
202
|
layerStack.addBranch(node);
|
|
@@ -242,9 +209,6 @@ function trackDismissableBranch(nodeOrFn, options = {}) {
|
|
|
242
209
|
cleanups.forEach((fn) => fn?.());
|
|
243
210
|
};
|
|
244
211
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
trackDismissableElement
|
|
249
|
-
});
|
|
250
|
-
//# sourceMappingURL=index.js.map
|
|
212
|
+
|
|
213
|
+
exports.trackDismissableBranch = trackDismissableBranch;
|
|
214
|
+
exports.trackDismissableElement = trackDismissableElement;
|
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
} from "@zag-js/interact-outside";
|
|
6
|
-
import { isFunction, warn } from "@zag-js/utils";
|
|
1
|
+
import { contains, raf, getDocument, waitForElements, setStyle, getEventTarget, isHTMLElement } from '@zag-js/dom-query';
|
|
2
|
+
import { trackInteractOutside } from '@zag-js/interact-outside';
|
|
3
|
+
import { isFunction, warn } from '@zag-js/utils';
|
|
4
|
+
import { addDomEvent } from '@zag-js/dom-event';
|
|
7
5
|
|
|
8
|
-
// src/
|
|
9
|
-
import { addDomEvent } from "@zag-js/dom-event";
|
|
10
|
-
import { getDocument } from "@zag-js/dom-query";
|
|
6
|
+
// src/dismissable-layer.ts
|
|
11
7
|
function trackEscapeKeydown(node, fn) {
|
|
12
8
|
const handleKeyDown = (event) => {
|
|
13
9
|
if (event.key !== "Escape") return;
|
|
@@ -16,9 +12,6 @@ function trackEscapeKeydown(node, fn) {
|
|
|
16
12
|
};
|
|
17
13
|
return addDomEvent(getDocument(node), "keydown", handleKeyDown, { capture: true });
|
|
18
14
|
}
|
|
19
|
-
|
|
20
|
-
// src/layer-stack.ts
|
|
21
|
-
import { contains } from "@zag-js/dom-query";
|
|
22
15
|
var layerStack = {
|
|
23
16
|
layers: [],
|
|
24
17
|
branches: [],
|
|
@@ -83,9 +76,6 @@ var layerStack = {
|
|
|
83
76
|
this.remove(this.layers[0].node);
|
|
84
77
|
}
|
|
85
78
|
};
|
|
86
|
-
|
|
87
|
-
// src/pointer-event-outside.ts
|
|
88
|
-
import { getDocument as getDocument2, setStyle, waitForElements } from "@zag-js/dom-query";
|
|
89
79
|
var originalBodyPointerEvents;
|
|
90
80
|
function assignPointerEventToLayers() {
|
|
91
81
|
layerStack.layers.forEach(({ node }) => {
|
|
@@ -96,7 +86,7 @@ function clearPointerEvent(node) {
|
|
|
96
86
|
node.style.pointerEvents = "";
|
|
97
87
|
}
|
|
98
88
|
function disablePointerEventsOutside(node, peristentElements) {
|
|
99
|
-
const doc =
|
|
89
|
+
const doc = getDocument(node);
|
|
100
90
|
const cleanups = [];
|
|
101
91
|
if (layerStack.hasPointerBlockingLayer() && !doc.body.hasAttribute("data-inert")) {
|
|
102
92
|
originalBodyPointerEvents = document.body.style.pointerEvents;
|
|
@@ -168,7 +158,7 @@ function trackDismissableElementImpl(node, options) {
|
|
|
168
158
|
const _containers = Array.isArray(containers) ? containers : [containers];
|
|
169
159
|
const persistentElements = options.persistentElements?.map((fn) => fn()).filter(isHTMLElement);
|
|
170
160
|
if (persistentElements) _containers.push(...persistentElements);
|
|
171
|
-
return _containers.some((node2) =>
|
|
161
|
+
return _containers.some((node2) => contains(node2, target)) || layerStack.isInNestedLayer(node, target);
|
|
172
162
|
}
|
|
173
163
|
const cleanups = [
|
|
174
164
|
pointerBlocking ? disablePointerEventsOutside(node, options.persistentElements) : void 0,
|
|
@@ -217,8 +207,5 @@ function trackDismissableBranch(nodeOrFn, options = {}) {
|
|
|
217
207
|
cleanups.forEach((fn) => fn?.());
|
|
218
208
|
};
|
|
219
209
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
trackDismissableElement
|
|
223
|
-
};
|
|
224
|
-
//# sourceMappingURL=index.mjs.map
|
|
210
|
+
|
|
211
|
+
export { trackDismissableBranch, trackDismissableElement };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zag-js/dismissable",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.0",
|
|
4
4
|
"description": "Dismissable layer utilities for the DOM",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"js",
|
|
@@ -17,17 +17,16 @@
|
|
|
17
17
|
"repository": "https://github.com/chakra-ui/zag/tree/main/packages/utilities/interact-outside",
|
|
18
18
|
"sideEffects": false,
|
|
19
19
|
"files": [
|
|
20
|
-
"dist"
|
|
21
|
-
"src"
|
|
20
|
+
"dist"
|
|
22
21
|
],
|
|
23
22
|
"publishConfig": {
|
|
24
23
|
"access": "public"
|
|
25
24
|
},
|
|
26
25
|
"dependencies": {
|
|
27
|
-
"@zag-js/interact-outside": "0.
|
|
28
|
-
"@zag-js/dom-query": "0.
|
|
29
|
-
"@zag-js/dom-event": "0.
|
|
30
|
-
"@zag-js/utils": "0.
|
|
26
|
+
"@zag-js/interact-outside": "0.72.0",
|
|
27
|
+
"@zag-js/dom-query": "0.72.0",
|
|
28
|
+
"@zag-js/dom-event": "0.72.0",
|
|
29
|
+
"@zag-js/utils": "0.72.0"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
32
|
"clean-package": "2.2.0"
|
|
@@ -49,7 +48,7 @@
|
|
|
49
48
|
},
|
|
50
49
|
"scripts": {
|
|
51
50
|
"build": "tsup",
|
|
52
|
-
"test": "
|
|
51
|
+
"test": "vitest",
|
|
53
52
|
"lint": "eslint src",
|
|
54
53
|
"test-ci": "pnpm test --ci --runInBand -u",
|
|
55
54
|
"test-watch": "pnpm test --watchAll"
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/dismissable-layer.ts","../src/escape-keydown.ts","../src/layer-stack.ts","../src/pointer-event-outside.ts"],"sourcesContent":["export type {\n FocusOutsideEvent,\n InteractOutsideEvent,\n InteractOutsideHandlers,\n PointerDownOutsideEvent,\n} from \"@zag-js/interact-outside\"\nexport * from \"./dismissable-layer\"\n","import { contains, getEventTarget, isHTMLElement, raf } from \"@zag-js/dom-query\"\nimport {\n trackInteractOutside,\n type FocusOutsideEvent,\n type InteractOutsideHandlers,\n type PointerDownOutsideEvent,\n} from \"@zag-js/interact-outside\"\nimport { isFunction, warn, type MaybeFunction } from \"@zag-js/utils\"\nimport { trackEscapeKeydown } from \"./escape-keydown\"\nimport { layerStack, type Layer } from \"./layer-stack\"\nimport { assignPointerEventToLayers, clearPointerEvent, disablePointerEventsOutside } from \"./pointer-event-outside\"\n\ntype MaybeElement = HTMLElement | null\ntype Container = MaybeElement | Array<MaybeElement>\ntype NodeOrFn = MaybeFunction<MaybeElement>\n\nexport interface DismissableElementHandlers extends InteractOutsideHandlers {\n /**\n * Function called when the escape key is pressed\n */\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n}\n\nexport interface PersistentElementOptions {\n /**\n * Returns the persistent elements that:\n * - should not have pointer-events disabled\n * - should not trigger the dismiss event\n */\n persistentElements?: Array<() => Element | null>\n}\n\nexport interface DismissableElementOptions extends DismissableElementHandlers, PersistentElementOptions {\n /**\n * Whether to log debug information\n */\n debug?: boolean\n /**\n * Whether to block pointer events outside the dismissable element\n */\n pointerBlocking?: boolean\n /**\n * Function called when the dismissable element is dismissed\n */\n onDismiss: VoidFunction\n /**\n * Exclude containers from the interact outside event\n */\n exclude?: MaybeFunction<Container>\n /**\n * Defer the interact outside event to the next frame\n */\n defer?: boolean\n}\n\nfunction trackDismissableElementImpl(node: MaybeElement, options: DismissableElementOptions) {\n if (!node) {\n warn(\"[@zag-js/dismissable] node is `null` or `undefined`\")\n return\n }\n\n const { onDismiss, pointerBlocking, exclude: excludeContainers, debug } = options\n\n const layer: Layer = { dismiss: onDismiss, node, pointerBlocking }\n\n layerStack.add(layer)\n assignPointerEventToLayers()\n\n function onPointerDownOutside(event: PointerDownOutsideEvent) {\n const target = getEventTarget(event.detail.originalEvent)\n if (layerStack.isBelowPointerBlockingLayer(node!) || layerStack.isInBranch(target)) return\n options.onPointerDownOutside?.(event)\n options.onInteractOutside?.(event)\n if (event.defaultPrevented) return\n if (debug) {\n console.log(\"onPointerDownOutside:\", event.detail.originalEvent)\n }\n onDismiss?.()\n }\n\n function onFocusOutside(event: FocusOutsideEvent) {\n const target = getEventTarget(event.detail.originalEvent)\n if (layerStack.isInBranch(target)) return\n options.onFocusOutside?.(event)\n options.onInteractOutside?.(event)\n if (event.defaultPrevented) return\n if (debug) {\n console.log(\"onFocusOutside:\", event.detail.originalEvent)\n }\n onDismiss?.()\n }\n\n function onEscapeKeyDown(event: KeyboardEvent) {\n if (!layerStack.isTopMost(node!)) return\n options.onEscapeKeyDown?.(event)\n if (!event.defaultPrevented && onDismiss) {\n event.preventDefault()\n onDismiss()\n }\n }\n\n function exclude(target: Element) {\n if (!node) return false\n const containers = typeof excludeContainers === \"function\" ? excludeContainers() : excludeContainers\n const _containers = Array.isArray(containers) ? containers : [containers]\n const persistentElements = options.persistentElements?.map((fn) => fn()).filter(isHTMLElement)\n if (persistentElements) _containers.push(...persistentElements)\n return _containers.some((node) => contains(node, target)) || layerStack.isInNestedLayer(node, target)\n }\n\n const cleanups = [\n pointerBlocking ? disablePointerEventsOutside(node, options.persistentElements) : undefined,\n trackEscapeKeydown(node, onEscapeKeyDown),\n trackInteractOutside(node, { exclude, onFocusOutside, onPointerDownOutside, defer: options.defer }),\n ]\n\n return () => {\n layerStack.remove(node!)\n // re-assign pointer event to remaining layers\n assignPointerEventToLayers()\n // remove pointer event from removed layer\n clearPointerEvent(node!)\n cleanups.forEach((fn) => fn?.())\n }\n}\n\nexport function trackDismissableElement(nodeOrFn: NodeOrFn, options: DismissableElementOptions) {\n const { defer } = options\n const func = defer ? raf : (v: any) => v()\n const cleanups: (VoidFunction | undefined)[] = []\n cleanups.push(\n func(() => {\n const node = isFunction(nodeOrFn) ? nodeOrFn() : nodeOrFn\n cleanups.push(trackDismissableElementImpl(node, options))\n }),\n )\n return () => {\n cleanups.forEach((fn) => fn?.())\n }\n}\n\nexport function trackDismissableBranch(nodeOrFn: NodeOrFn, options: { defer?: boolean } = {}) {\n const { defer } = options\n const func = defer ? raf : (v: any) => v()\n const cleanups: (VoidFunction | undefined)[] = []\n\n cleanups.push(\n func(() => {\n const node = isFunction(nodeOrFn) ? nodeOrFn() : nodeOrFn\n if (!node) {\n warn(\"[@zag-js/dismissable] branch node is `null` or `undefined`\")\n return\n }\n layerStack.addBranch(node)\n cleanups.push(() => {\n layerStack.removeBranch(node)\n })\n }),\n )\n\n return () => {\n cleanups.forEach((fn) => fn?.())\n }\n}\n","import { addDomEvent } from \"@zag-js/dom-event\"\nimport { getDocument } from \"@zag-js/dom-query\"\n\nexport function trackEscapeKeydown(node: HTMLElement, fn?: (event: KeyboardEvent) => void) {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return\n if (event.isComposing) return\n fn?.(event)\n }\n\n return addDomEvent(getDocument(node), \"keydown\", handleKeyDown, { capture: true })\n}\n","import { contains } from \"@zag-js/dom-query\"\n\nexport interface Layer {\n dismiss: VoidFunction\n node: HTMLElement\n pointerBlocking?: boolean\n}\n\nexport const layerStack = {\n layers: [] as Layer[],\n branches: [] as HTMLElement[],\n count(): number {\n return this.layers.length\n },\n pointerBlockingLayers(): Layer[] {\n return this.layers.filter((layer) => layer.pointerBlocking)\n },\n topMostPointerBlockingLayer(): Layer | undefined {\n return [...this.pointerBlockingLayers()].slice(-1)[0]\n },\n hasPointerBlockingLayer(): boolean {\n return this.pointerBlockingLayers().length > 0\n },\n isBelowPointerBlockingLayer(node: HTMLElement) {\n const index = this.indexOf(node)\n const highestBlockingIndex = this.topMostPointerBlockingLayer()\n ? this.indexOf(this.topMostPointerBlockingLayer()?.node)\n : -1\n return index < highestBlockingIndex\n },\n isTopMost(node: HTMLElement | null) {\n const layer = this.layers[this.count() - 1]\n return layer?.node === node\n },\n getNestedLayers(node: HTMLElement) {\n return Array.from(this.layers).slice(this.indexOf(node) + 1)\n },\n isInNestedLayer(node: HTMLElement, target: HTMLElement | EventTarget | null) {\n return this.getNestedLayers(node).some((layer) => contains(layer.node, target))\n },\n isInBranch(target: HTMLElement | EventTarget | null) {\n return Array.from(this.branches).some((branch) => contains(branch, target))\n },\n add(layer: Layer) {\n const num = this.layers.push(layer)\n layer.node.style.setProperty(\"--layer-index\", `${num}`)\n },\n addBranch(node: HTMLElement) {\n this.branches.push(node)\n },\n remove(node: HTMLElement) {\n const index = this.indexOf(node)\n if (index < 0) return\n\n // dismiss nested layers\n if (index < this.count() - 1) {\n const _layers = this.getNestedLayers(node)\n _layers.forEach((layer) => layer.dismiss())\n }\n // remove this layer\n this.layers.splice(index, 1)\n node.style.removeProperty(\"--layer-index\")\n },\n removeBranch(node: HTMLElement) {\n const index = this.branches.indexOf(node)\n if (index >= 0) this.branches.splice(index, 1)\n },\n indexOf(node: HTMLElement | undefined) {\n return this.layers.findIndex((layer) => layer.node === node)\n },\n dismiss(node: HTMLElement) {\n this.layers[this.indexOf(node)]?.dismiss()\n },\n clear() {\n this.remove(this.layers[0].node)\n },\n}\n","import { getDocument, setStyle, waitForElements } from \"@zag-js/dom-query\"\nimport { layerStack } from \"./layer-stack\"\n\nlet originalBodyPointerEvents: string\n\nexport function assignPointerEventToLayers() {\n layerStack.layers.forEach(({ node }) => {\n node.style.pointerEvents = layerStack.isBelowPointerBlockingLayer(node) ? \"none\" : \"auto\"\n })\n}\n\nexport function clearPointerEvent(node: HTMLElement) {\n node.style.pointerEvents = \"\"\n}\n\nexport function disablePointerEventsOutside(node: HTMLElement, peristentElements?: Array<() => Element | null>) {\n const doc = getDocument(node)\n\n const cleanups: VoidFunction[] = []\n\n if (layerStack.hasPointerBlockingLayer() && !doc.body.hasAttribute(\"data-inert\")) {\n originalBodyPointerEvents = document.body.style.pointerEvents\n queueMicrotask(() => {\n doc.body.style.pointerEvents = \"none\"\n doc.body.setAttribute(\"data-inert\", \"\")\n })\n }\n\n if (peristentElements) {\n const persistedCleanup = waitForElements(peristentElements, (el) => {\n cleanups.push(setStyle(el, { pointerEvents: \"auto\" }))\n })\n cleanups.push(persistedCleanup)\n }\n\n return () => {\n if (layerStack.hasPointerBlockingLayer()) return\n queueMicrotask(() => {\n doc.body.style.pointerEvents = originalBodyPointerEvents\n doc.body.removeAttribute(\"data-inert\")\n if (doc.body.style.length === 0) doc.body.removeAttribute(\"style\")\n })\n cleanups.forEach((fn) => fn())\n }\n}\n"],"mappings":"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","names":["import_dom_query","import_dom_query","import_dom_query","node"]}
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dismissable-layer.ts","../src/escape-keydown.ts","../src/layer-stack.ts","../src/pointer-event-outside.ts"],"sourcesContent":["import { contains, getEventTarget, isHTMLElement, raf } from \"@zag-js/dom-query\"\nimport {\n trackInteractOutside,\n type FocusOutsideEvent,\n type InteractOutsideHandlers,\n type PointerDownOutsideEvent,\n} from \"@zag-js/interact-outside\"\nimport { isFunction, warn, type MaybeFunction } from \"@zag-js/utils\"\nimport { trackEscapeKeydown } from \"./escape-keydown\"\nimport { layerStack, type Layer } from \"./layer-stack\"\nimport { assignPointerEventToLayers, clearPointerEvent, disablePointerEventsOutside } from \"./pointer-event-outside\"\n\ntype MaybeElement = HTMLElement | null\ntype Container = MaybeElement | Array<MaybeElement>\ntype NodeOrFn = MaybeFunction<MaybeElement>\n\nexport interface DismissableElementHandlers extends InteractOutsideHandlers {\n /**\n * Function called when the escape key is pressed\n */\n onEscapeKeyDown?: (event: KeyboardEvent) => void\n}\n\nexport interface PersistentElementOptions {\n /**\n * Returns the persistent elements that:\n * - should not have pointer-events disabled\n * - should not trigger the dismiss event\n */\n persistentElements?: Array<() => Element | null>\n}\n\nexport interface DismissableElementOptions extends DismissableElementHandlers, PersistentElementOptions {\n /**\n * Whether to log debug information\n */\n debug?: boolean\n /**\n * Whether to block pointer events outside the dismissable element\n */\n pointerBlocking?: boolean\n /**\n * Function called when the dismissable element is dismissed\n */\n onDismiss: VoidFunction\n /**\n * Exclude containers from the interact outside event\n */\n exclude?: MaybeFunction<Container>\n /**\n * Defer the interact outside event to the next frame\n */\n defer?: boolean\n}\n\nfunction trackDismissableElementImpl(node: MaybeElement, options: DismissableElementOptions) {\n if (!node) {\n warn(\"[@zag-js/dismissable] node is `null` or `undefined`\")\n return\n }\n\n const { onDismiss, pointerBlocking, exclude: excludeContainers, debug } = options\n\n const layer: Layer = { dismiss: onDismiss, node, pointerBlocking }\n\n layerStack.add(layer)\n assignPointerEventToLayers()\n\n function onPointerDownOutside(event: PointerDownOutsideEvent) {\n const target = getEventTarget(event.detail.originalEvent)\n if (layerStack.isBelowPointerBlockingLayer(node!) || layerStack.isInBranch(target)) return\n options.onPointerDownOutside?.(event)\n options.onInteractOutside?.(event)\n if (event.defaultPrevented) return\n if (debug) {\n console.log(\"onPointerDownOutside:\", event.detail.originalEvent)\n }\n onDismiss?.()\n }\n\n function onFocusOutside(event: FocusOutsideEvent) {\n const target = getEventTarget(event.detail.originalEvent)\n if (layerStack.isInBranch(target)) return\n options.onFocusOutside?.(event)\n options.onInteractOutside?.(event)\n if (event.defaultPrevented) return\n if (debug) {\n console.log(\"onFocusOutside:\", event.detail.originalEvent)\n }\n onDismiss?.()\n }\n\n function onEscapeKeyDown(event: KeyboardEvent) {\n if (!layerStack.isTopMost(node!)) return\n options.onEscapeKeyDown?.(event)\n if (!event.defaultPrevented && onDismiss) {\n event.preventDefault()\n onDismiss()\n }\n }\n\n function exclude(target: Element) {\n if (!node) return false\n const containers = typeof excludeContainers === \"function\" ? excludeContainers() : excludeContainers\n const _containers = Array.isArray(containers) ? containers : [containers]\n const persistentElements = options.persistentElements?.map((fn) => fn()).filter(isHTMLElement)\n if (persistentElements) _containers.push(...persistentElements)\n return _containers.some((node) => contains(node, target)) || layerStack.isInNestedLayer(node, target)\n }\n\n const cleanups = [\n pointerBlocking ? disablePointerEventsOutside(node, options.persistentElements) : undefined,\n trackEscapeKeydown(node, onEscapeKeyDown),\n trackInteractOutside(node, { exclude, onFocusOutside, onPointerDownOutside, defer: options.defer }),\n ]\n\n return () => {\n layerStack.remove(node!)\n // re-assign pointer event to remaining layers\n assignPointerEventToLayers()\n // remove pointer event from removed layer\n clearPointerEvent(node!)\n cleanups.forEach((fn) => fn?.())\n }\n}\n\nexport function trackDismissableElement(nodeOrFn: NodeOrFn, options: DismissableElementOptions) {\n const { defer } = options\n const func = defer ? raf : (v: any) => v()\n const cleanups: (VoidFunction | undefined)[] = []\n cleanups.push(\n func(() => {\n const node = isFunction(nodeOrFn) ? nodeOrFn() : nodeOrFn\n cleanups.push(trackDismissableElementImpl(node, options))\n }),\n )\n return () => {\n cleanups.forEach((fn) => fn?.())\n }\n}\n\nexport function trackDismissableBranch(nodeOrFn: NodeOrFn, options: { defer?: boolean } = {}) {\n const { defer } = options\n const func = defer ? raf : (v: any) => v()\n const cleanups: (VoidFunction | undefined)[] = []\n\n cleanups.push(\n func(() => {\n const node = isFunction(nodeOrFn) ? nodeOrFn() : nodeOrFn\n if (!node) {\n warn(\"[@zag-js/dismissable] branch node is `null` or `undefined`\")\n return\n }\n layerStack.addBranch(node)\n cleanups.push(() => {\n layerStack.removeBranch(node)\n })\n }),\n )\n\n return () => {\n cleanups.forEach((fn) => fn?.())\n }\n}\n","import { addDomEvent } from \"@zag-js/dom-event\"\nimport { getDocument } from \"@zag-js/dom-query\"\n\nexport function trackEscapeKeydown(node: HTMLElement, fn?: (event: KeyboardEvent) => void) {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return\n if (event.isComposing) return\n fn?.(event)\n }\n\n return addDomEvent(getDocument(node), \"keydown\", handleKeyDown, { capture: true })\n}\n","import { contains } from \"@zag-js/dom-query\"\n\nexport interface Layer {\n dismiss: VoidFunction\n node: HTMLElement\n pointerBlocking?: boolean\n}\n\nexport const layerStack = {\n layers: [] as Layer[],\n branches: [] as HTMLElement[],\n count(): number {\n return this.layers.length\n },\n pointerBlockingLayers(): Layer[] {\n return this.layers.filter((layer) => layer.pointerBlocking)\n },\n topMostPointerBlockingLayer(): Layer | undefined {\n return [...this.pointerBlockingLayers()].slice(-1)[0]\n },\n hasPointerBlockingLayer(): boolean {\n return this.pointerBlockingLayers().length > 0\n },\n isBelowPointerBlockingLayer(node: HTMLElement) {\n const index = this.indexOf(node)\n const highestBlockingIndex = this.topMostPointerBlockingLayer()\n ? this.indexOf(this.topMostPointerBlockingLayer()?.node)\n : -1\n return index < highestBlockingIndex\n },\n isTopMost(node: HTMLElement | null) {\n const layer = this.layers[this.count() - 1]\n return layer?.node === node\n },\n getNestedLayers(node: HTMLElement) {\n return Array.from(this.layers).slice(this.indexOf(node) + 1)\n },\n isInNestedLayer(node: HTMLElement, target: HTMLElement | EventTarget | null) {\n return this.getNestedLayers(node).some((layer) => contains(layer.node, target))\n },\n isInBranch(target: HTMLElement | EventTarget | null) {\n return Array.from(this.branches).some((branch) => contains(branch, target))\n },\n add(layer: Layer) {\n const num = this.layers.push(layer)\n layer.node.style.setProperty(\"--layer-index\", `${num}`)\n },\n addBranch(node: HTMLElement) {\n this.branches.push(node)\n },\n remove(node: HTMLElement) {\n const index = this.indexOf(node)\n if (index < 0) return\n\n // dismiss nested layers\n if (index < this.count() - 1) {\n const _layers = this.getNestedLayers(node)\n _layers.forEach((layer) => layer.dismiss())\n }\n // remove this layer\n this.layers.splice(index, 1)\n node.style.removeProperty(\"--layer-index\")\n },\n removeBranch(node: HTMLElement) {\n const index = this.branches.indexOf(node)\n if (index >= 0) this.branches.splice(index, 1)\n },\n indexOf(node: HTMLElement | undefined) {\n return this.layers.findIndex((layer) => layer.node === node)\n },\n dismiss(node: HTMLElement) {\n this.layers[this.indexOf(node)]?.dismiss()\n },\n clear() {\n this.remove(this.layers[0].node)\n },\n}\n","import { getDocument, setStyle, waitForElements } from \"@zag-js/dom-query\"\nimport { layerStack } from \"./layer-stack\"\n\nlet originalBodyPointerEvents: string\n\nexport function assignPointerEventToLayers() {\n layerStack.layers.forEach(({ node }) => {\n node.style.pointerEvents = layerStack.isBelowPointerBlockingLayer(node) ? \"none\" : \"auto\"\n })\n}\n\nexport function clearPointerEvent(node: HTMLElement) {\n node.style.pointerEvents = \"\"\n}\n\nexport function disablePointerEventsOutside(node: HTMLElement, peristentElements?: Array<() => Element | null>) {\n const doc = getDocument(node)\n\n const cleanups: VoidFunction[] = []\n\n if (layerStack.hasPointerBlockingLayer() && !doc.body.hasAttribute(\"data-inert\")) {\n originalBodyPointerEvents = document.body.style.pointerEvents\n queueMicrotask(() => {\n doc.body.style.pointerEvents = \"none\"\n doc.body.setAttribute(\"data-inert\", \"\")\n })\n }\n\n if (peristentElements) {\n const persistedCleanup = waitForElements(peristentElements, (el) => {\n cleanups.push(setStyle(el, { pointerEvents: \"auto\" }))\n })\n cleanups.push(persistedCleanup)\n }\n\n return () => {\n if (layerStack.hasPointerBlockingLayer()) return\n queueMicrotask(() => {\n doc.body.style.pointerEvents = originalBodyPointerEvents\n doc.body.removeAttribute(\"data-inert\")\n if (doc.body.style.length === 0) doc.body.removeAttribute(\"style\")\n })\n cleanups.forEach((fn) => fn())\n }\n}\n"],"mappings":"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","names":["contains","getDocument","getDocument","node","contains"]}
|
package/src/dismissable-layer.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { contains, getEventTarget, isHTMLElement, raf } from "@zag-js/dom-query"
|
|
2
|
-
import {
|
|
3
|
-
trackInteractOutside,
|
|
4
|
-
type FocusOutsideEvent,
|
|
5
|
-
type InteractOutsideHandlers,
|
|
6
|
-
type PointerDownOutsideEvent,
|
|
7
|
-
} from "@zag-js/interact-outside"
|
|
8
|
-
import { isFunction, warn, type MaybeFunction } from "@zag-js/utils"
|
|
9
|
-
import { trackEscapeKeydown } from "./escape-keydown"
|
|
10
|
-
import { layerStack, type Layer } from "./layer-stack"
|
|
11
|
-
import { assignPointerEventToLayers, clearPointerEvent, disablePointerEventsOutside } from "./pointer-event-outside"
|
|
12
|
-
|
|
13
|
-
type MaybeElement = HTMLElement | null
|
|
14
|
-
type Container = MaybeElement | Array<MaybeElement>
|
|
15
|
-
type NodeOrFn = MaybeFunction<MaybeElement>
|
|
16
|
-
|
|
17
|
-
export interface DismissableElementHandlers extends InteractOutsideHandlers {
|
|
18
|
-
/**
|
|
19
|
-
* Function called when the escape key is pressed
|
|
20
|
-
*/
|
|
21
|
-
onEscapeKeyDown?: (event: KeyboardEvent) => void
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface PersistentElementOptions {
|
|
25
|
-
/**
|
|
26
|
-
* Returns the persistent elements that:
|
|
27
|
-
* - should not have pointer-events disabled
|
|
28
|
-
* - should not trigger the dismiss event
|
|
29
|
-
*/
|
|
30
|
-
persistentElements?: Array<() => Element | null>
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface DismissableElementOptions extends DismissableElementHandlers, PersistentElementOptions {
|
|
34
|
-
/**
|
|
35
|
-
* Whether to log debug information
|
|
36
|
-
*/
|
|
37
|
-
debug?: boolean
|
|
38
|
-
/**
|
|
39
|
-
* Whether to block pointer events outside the dismissable element
|
|
40
|
-
*/
|
|
41
|
-
pointerBlocking?: boolean
|
|
42
|
-
/**
|
|
43
|
-
* Function called when the dismissable element is dismissed
|
|
44
|
-
*/
|
|
45
|
-
onDismiss: VoidFunction
|
|
46
|
-
/**
|
|
47
|
-
* Exclude containers from the interact outside event
|
|
48
|
-
*/
|
|
49
|
-
exclude?: MaybeFunction<Container>
|
|
50
|
-
/**
|
|
51
|
-
* Defer the interact outside event to the next frame
|
|
52
|
-
*/
|
|
53
|
-
defer?: boolean
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function trackDismissableElementImpl(node: MaybeElement, options: DismissableElementOptions) {
|
|
57
|
-
if (!node) {
|
|
58
|
-
warn("[@zag-js/dismissable] node is `null` or `undefined`")
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const { onDismiss, pointerBlocking, exclude: excludeContainers, debug } = options
|
|
63
|
-
|
|
64
|
-
const layer: Layer = { dismiss: onDismiss, node, pointerBlocking }
|
|
65
|
-
|
|
66
|
-
layerStack.add(layer)
|
|
67
|
-
assignPointerEventToLayers()
|
|
68
|
-
|
|
69
|
-
function onPointerDownOutside(event: PointerDownOutsideEvent) {
|
|
70
|
-
const target = getEventTarget(event.detail.originalEvent)
|
|
71
|
-
if (layerStack.isBelowPointerBlockingLayer(node!) || layerStack.isInBranch(target)) return
|
|
72
|
-
options.onPointerDownOutside?.(event)
|
|
73
|
-
options.onInteractOutside?.(event)
|
|
74
|
-
if (event.defaultPrevented) return
|
|
75
|
-
if (debug) {
|
|
76
|
-
console.log("onPointerDownOutside:", event.detail.originalEvent)
|
|
77
|
-
}
|
|
78
|
-
onDismiss?.()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function onFocusOutside(event: FocusOutsideEvent) {
|
|
82
|
-
const target = getEventTarget(event.detail.originalEvent)
|
|
83
|
-
if (layerStack.isInBranch(target)) return
|
|
84
|
-
options.onFocusOutside?.(event)
|
|
85
|
-
options.onInteractOutside?.(event)
|
|
86
|
-
if (event.defaultPrevented) return
|
|
87
|
-
if (debug) {
|
|
88
|
-
console.log("onFocusOutside:", event.detail.originalEvent)
|
|
89
|
-
}
|
|
90
|
-
onDismiss?.()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function onEscapeKeyDown(event: KeyboardEvent) {
|
|
94
|
-
if (!layerStack.isTopMost(node!)) return
|
|
95
|
-
options.onEscapeKeyDown?.(event)
|
|
96
|
-
if (!event.defaultPrevented && onDismiss) {
|
|
97
|
-
event.preventDefault()
|
|
98
|
-
onDismiss()
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function exclude(target: Element) {
|
|
103
|
-
if (!node) return false
|
|
104
|
-
const containers = typeof excludeContainers === "function" ? excludeContainers() : excludeContainers
|
|
105
|
-
const _containers = Array.isArray(containers) ? containers : [containers]
|
|
106
|
-
const persistentElements = options.persistentElements?.map((fn) => fn()).filter(isHTMLElement)
|
|
107
|
-
if (persistentElements) _containers.push(...persistentElements)
|
|
108
|
-
return _containers.some((node) => contains(node, target)) || layerStack.isInNestedLayer(node, target)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const cleanups = [
|
|
112
|
-
pointerBlocking ? disablePointerEventsOutside(node, options.persistentElements) : undefined,
|
|
113
|
-
trackEscapeKeydown(node, onEscapeKeyDown),
|
|
114
|
-
trackInteractOutside(node, { exclude, onFocusOutside, onPointerDownOutside, defer: options.defer }),
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
return () => {
|
|
118
|
-
layerStack.remove(node!)
|
|
119
|
-
// re-assign pointer event to remaining layers
|
|
120
|
-
assignPointerEventToLayers()
|
|
121
|
-
// remove pointer event from removed layer
|
|
122
|
-
clearPointerEvent(node!)
|
|
123
|
-
cleanups.forEach((fn) => fn?.())
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export function trackDismissableElement(nodeOrFn: NodeOrFn, options: DismissableElementOptions) {
|
|
128
|
-
const { defer } = options
|
|
129
|
-
const func = defer ? raf : (v: any) => v()
|
|
130
|
-
const cleanups: (VoidFunction | undefined)[] = []
|
|
131
|
-
cleanups.push(
|
|
132
|
-
func(() => {
|
|
133
|
-
const node = isFunction(nodeOrFn) ? nodeOrFn() : nodeOrFn
|
|
134
|
-
cleanups.push(trackDismissableElementImpl(node, options))
|
|
135
|
-
}),
|
|
136
|
-
)
|
|
137
|
-
return () => {
|
|
138
|
-
cleanups.forEach((fn) => fn?.())
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export function trackDismissableBranch(nodeOrFn: NodeOrFn, options: { defer?: boolean } = {}) {
|
|
143
|
-
const { defer } = options
|
|
144
|
-
const func = defer ? raf : (v: any) => v()
|
|
145
|
-
const cleanups: (VoidFunction | undefined)[] = []
|
|
146
|
-
|
|
147
|
-
cleanups.push(
|
|
148
|
-
func(() => {
|
|
149
|
-
const node = isFunction(nodeOrFn) ? nodeOrFn() : nodeOrFn
|
|
150
|
-
if (!node) {
|
|
151
|
-
warn("[@zag-js/dismissable] branch node is `null` or `undefined`")
|
|
152
|
-
return
|
|
153
|
-
}
|
|
154
|
-
layerStack.addBranch(node)
|
|
155
|
-
cleanups.push(() => {
|
|
156
|
-
layerStack.removeBranch(node)
|
|
157
|
-
})
|
|
158
|
-
}),
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
return () => {
|
|
162
|
-
cleanups.forEach((fn) => fn?.())
|
|
163
|
-
}
|
|
164
|
-
}
|
package/src/escape-keydown.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { addDomEvent } from "@zag-js/dom-event"
|
|
2
|
-
import { getDocument } from "@zag-js/dom-query"
|
|
3
|
-
|
|
4
|
-
export function trackEscapeKeydown(node: HTMLElement, fn?: (event: KeyboardEvent) => void) {
|
|
5
|
-
const handleKeyDown = (event: KeyboardEvent) => {
|
|
6
|
-
if (event.key !== "Escape") return
|
|
7
|
-
if (event.isComposing) return
|
|
8
|
-
fn?.(event)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return addDomEvent(getDocument(node), "keydown", handleKeyDown, { capture: true })
|
|
12
|
-
}
|
package/src/index.ts
DELETED
package/src/layer-stack.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { contains } from "@zag-js/dom-query"
|
|
2
|
-
|
|
3
|
-
export interface Layer {
|
|
4
|
-
dismiss: VoidFunction
|
|
5
|
-
node: HTMLElement
|
|
6
|
-
pointerBlocking?: boolean
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const layerStack = {
|
|
10
|
-
layers: [] as Layer[],
|
|
11
|
-
branches: [] as HTMLElement[],
|
|
12
|
-
count(): number {
|
|
13
|
-
return this.layers.length
|
|
14
|
-
},
|
|
15
|
-
pointerBlockingLayers(): Layer[] {
|
|
16
|
-
return this.layers.filter((layer) => layer.pointerBlocking)
|
|
17
|
-
},
|
|
18
|
-
topMostPointerBlockingLayer(): Layer | undefined {
|
|
19
|
-
return [...this.pointerBlockingLayers()].slice(-1)[0]
|
|
20
|
-
},
|
|
21
|
-
hasPointerBlockingLayer(): boolean {
|
|
22
|
-
return this.pointerBlockingLayers().length > 0
|
|
23
|
-
},
|
|
24
|
-
isBelowPointerBlockingLayer(node: HTMLElement) {
|
|
25
|
-
const index = this.indexOf(node)
|
|
26
|
-
const highestBlockingIndex = this.topMostPointerBlockingLayer()
|
|
27
|
-
? this.indexOf(this.topMostPointerBlockingLayer()?.node)
|
|
28
|
-
: -1
|
|
29
|
-
return index < highestBlockingIndex
|
|
30
|
-
},
|
|
31
|
-
isTopMost(node: HTMLElement | null) {
|
|
32
|
-
const layer = this.layers[this.count() - 1]
|
|
33
|
-
return layer?.node === node
|
|
34
|
-
},
|
|
35
|
-
getNestedLayers(node: HTMLElement) {
|
|
36
|
-
return Array.from(this.layers).slice(this.indexOf(node) + 1)
|
|
37
|
-
},
|
|
38
|
-
isInNestedLayer(node: HTMLElement, target: HTMLElement | EventTarget | null) {
|
|
39
|
-
return this.getNestedLayers(node).some((layer) => contains(layer.node, target))
|
|
40
|
-
},
|
|
41
|
-
isInBranch(target: HTMLElement | EventTarget | null) {
|
|
42
|
-
return Array.from(this.branches).some((branch) => contains(branch, target))
|
|
43
|
-
},
|
|
44
|
-
add(layer: Layer) {
|
|
45
|
-
const num = this.layers.push(layer)
|
|
46
|
-
layer.node.style.setProperty("--layer-index", `${num}`)
|
|
47
|
-
},
|
|
48
|
-
addBranch(node: HTMLElement) {
|
|
49
|
-
this.branches.push(node)
|
|
50
|
-
},
|
|
51
|
-
remove(node: HTMLElement) {
|
|
52
|
-
const index = this.indexOf(node)
|
|
53
|
-
if (index < 0) return
|
|
54
|
-
|
|
55
|
-
// dismiss nested layers
|
|
56
|
-
if (index < this.count() - 1) {
|
|
57
|
-
const _layers = this.getNestedLayers(node)
|
|
58
|
-
_layers.forEach((layer) => layer.dismiss())
|
|
59
|
-
}
|
|
60
|
-
// remove this layer
|
|
61
|
-
this.layers.splice(index, 1)
|
|
62
|
-
node.style.removeProperty("--layer-index")
|
|
63
|
-
},
|
|
64
|
-
removeBranch(node: HTMLElement) {
|
|
65
|
-
const index = this.branches.indexOf(node)
|
|
66
|
-
if (index >= 0) this.branches.splice(index, 1)
|
|
67
|
-
},
|
|
68
|
-
indexOf(node: HTMLElement | undefined) {
|
|
69
|
-
return this.layers.findIndex((layer) => layer.node === node)
|
|
70
|
-
},
|
|
71
|
-
dismiss(node: HTMLElement) {
|
|
72
|
-
this.layers[this.indexOf(node)]?.dismiss()
|
|
73
|
-
},
|
|
74
|
-
clear() {
|
|
75
|
-
this.remove(this.layers[0].node)
|
|
76
|
-
},
|
|
77
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { getDocument, setStyle, waitForElements } from "@zag-js/dom-query"
|
|
2
|
-
import { layerStack } from "./layer-stack"
|
|
3
|
-
|
|
4
|
-
let originalBodyPointerEvents: string
|
|
5
|
-
|
|
6
|
-
export function assignPointerEventToLayers() {
|
|
7
|
-
layerStack.layers.forEach(({ node }) => {
|
|
8
|
-
node.style.pointerEvents = layerStack.isBelowPointerBlockingLayer(node) ? "none" : "auto"
|
|
9
|
-
})
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function clearPointerEvent(node: HTMLElement) {
|
|
13
|
-
node.style.pointerEvents = ""
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function disablePointerEventsOutside(node: HTMLElement, peristentElements?: Array<() => Element | null>) {
|
|
17
|
-
const doc = getDocument(node)
|
|
18
|
-
|
|
19
|
-
const cleanups: VoidFunction[] = []
|
|
20
|
-
|
|
21
|
-
if (layerStack.hasPointerBlockingLayer() && !doc.body.hasAttribute("data-inert")) {
|
|
22
|
-
originalBodyPointerEvents = document.body.style.pointerEvents
|
|
23
|
-
queueMicrotask(() => {
|
|
24
|
-
doc.body.style.pointerEvents = "none"
|
|
25
|
-
doc.body.setAttribute("data-inert", "")
|
|
26
|
-
})
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (peristentElements) {
|
|
30
|
-
const persistedCleanup = waitForElements(peristentElements, (el) => {
|
|
31
|
-
cleanups.push(setStyle(el, { pointerEvents: "auto" }))
|
|
32
|
-
})
|
|
33
|
-
cleanups.push(persistedCleanup)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return () => {
|
|
37
|
-
if (layerStack.hasPointerBlockingLayer()) return
|
|
38
|
-
queueMicrotask(() => {
|
|
39
|
-
doc.body.style.pointerEvents = originalBodyPointerEvents
|
|
40
|
-
doc.body.removeAttribute("data-inert")
|
|
41
|
-
if (doc.body.style.length === 0) doc.body.removeAttribute("style")
|
|
42
|
-
})
|
|
43
|
-
cleanups.forEach((fn) => fn())
|
|
44
|
-
}
|
|
45
|
-
}
|