@zag-js/popover 0.1.15 → 0.1.16
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 +47 -19
- package/dist/index.mjs +579 -0
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
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);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
connect: () => connect,
|
|
24
|
+
machine: () => machine
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(src_exports);
|
|
27
|
+
|
|
28
|
+
// ../../utilities/dom/dist/index.mjs
|
|
2
29
|
var dataAttr = (guard) => {
|
|
3
30
|
return guard ? "" : void 0;
|
|
4
31
|
};
|
|
@@ -140,9 +167,9 @@ function raf(fn) {
|
|
|
140
167
|
}
|
|
141
168
|
|
|
142
169
|
// src/popover.connect.ts
|
|
143
|
-
|
|
170
|
+
var import_popper = require("@zag-js/popper");
|
|
144
171
|
|
|
145
|
-
// ../../utilities/core/dist/index.
|
|
172
|
+
// ../../utilities/core/dist/index.mjs
|
|
146
173
|
function nextIndex(v, idx, opts = {}) {
|
|
147
174
|
const { step = 1, loop = true } = opts;
|
|
148
175
|
const next2 = idx + step;
|
|
@@ -221,7 +248,7 @@ function connect(state, send, normalize) {
|
|
|
221
248
|
const currentPlacement = state.context.currentPlacement;
|
|
222
249
|
const portalled = state.context.currentPortalled;
|
|
223
250
|
const rendered = state.context.renderedElements;
|
|
224
|
-
const popperStyles = getPlacementStyles({
|
|
251
|
+
const popperStyles = (0, import_popper.getPlacementStyles)({
|
|
225
252
|
measured: !!state.context.isPlacementComplete,
|
|
226
253
|
placement: currentPlacement
|
|
227
254
|
});
|
|
@@ -300,15 +327,15 @@ function connect(state, send, normalize) {
|
|
|
300
327
|
}
|
|
301
328
|
|
|
302
329
|
// src/popover.machine.ts
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
var { and, or, not } = guards;
|
|
330
|
+
var import_aria_hidden = require("@zag-js/aria-hidden");
|
|
331
|
+
var import_core = require("@zag-js/core");
|
|
332
|
+
var import_dismissable = require("@zag-js/dismissable");
|
|
333
|
+
var import_popper2 = require("@zag-js/popper");
|
|
334
|
+
var import_remove_scroll = require("@zag-js/remove-scroll");
|
|
335
|
+
var import_focus_trap = require("focus-trap");
|
|
336
|
+
var { and, or, not } = import_core.guards;
|
|
310
337
|
function machine(ctx) {
|
|
311
|
-
return createMachine(
|
|
338
|
+
return (0, import_core.createMachine)(
|
|
312
339
|
{
|
|
313
340
|
id: "popover",
|
|
314
341
|
initial: "unknown",
|
|
@@ -394,7 +421,7 @@ function machine(ctx) {
|
|
|
394
421
|
computePlacement(ctx2) {
|
|
395
422
|
ctx2.currentPlacement = ctx2.positioning.placement;
|
|
396
423
|
const anchorEl = ctx2.renderedElements.anchor ? dom.getAnchorEl(ctx2) : dom.getTriggerEl(ctx2);
|
|
397
|
-
return getPlacement(anchorEl, dom.getPositionerEl(ctx2), {
|
|
424
|
+
return (0, import_popper2.getPlacement)(anchorEl, dom.getPositionerEl(ctx2), {
|
|
398
425
|
...ctx2.positioning,
|
|
399
426
|
onComplete(data) {
|
|
400
427
|
ctx2.currentPlacement = data.placement;
|
|
@@ -407,7 +434,7 @@ function machine(ctx) {
|
|
|
407
434
|
});
|
|
408
435
|
},
|
|
409
436
|
trackInteractionOutside(ctx2, _evt, { send }) {
|
|
410
|
-
return trackDismissableElement(dom.getContentEl(ctx2), {
|
|
437
|
+
return (0, import_dismissable.trackDismissableElement)(dom.getContentEl(ctx2), {
|
|
411
438
|
pointerBlocking: ctx2.modal,
|
|
412
439
|
exclude: dom.getTriggerEl(ctx2),
|
|
413
440
|
onEscapeKeyDown(event) {
|
|
@@ -467,14 +494,14 @@ function machine(ctx) {
|
|
|
467
494
|
return;
|
|
468
495
|
let cleanup;
|
|
469
496
|
nextTick(() => {
|
|
470
|
-
cleanup = ariaHidden([dom.getContentEl(ctx2), dom.getTriggerEl(ctx2)]);
|
|
497
|
+
cleanup = (0, import_aria_hidden.ariaHidden)([dom.getContentEl(ctx2), dom.getTriggerEl(ctx2)]);
|
|
471
498
|
});
|
|
472
499
|
return () => cleanup == null ? void 0 : cleanup();
|
|
473
500
|
},
|
|
474
501
|
preventScroll(ctx2) {
|
|
475
502
|
if (!ctx2.modal)
|
|
476
503
|
return;
|
|
477
|
-
return preventBodyScroll(dom.getDoc(ctx2));
|
|
504
|
+
return (0, import_remove_scroll.preventBodyScroll)(dom.getDoc(ctx2));
|
|
478
505
|
},
|
|
479
506
|
trapFocus(ctx2) {
|
|
480
507
|
if (!ctx2.modal)
|
|
@@ -484,7 +511,7 @@ function machine(ctx) {
|
|
|
484
511
|
const el = dom.getContentEl(ctx2);
|
|
485
512
|
if (!el)
|
|
486
513
|
return;
|
|
487
|
-
trap = createFocusTrap(el, {
|
|
514
|
+
trap = (0, import_focus_trap.createFocusTrap)(el, {
|
|
488
515
|
escapeDeactivates: false,
|
|
489
516
|
allowOutsideClick: true,
|
|
490
517
|
returnFocusOnDeactivate: true,
|
|
@@ -573,7 +600,8 @@ function machine(ctx) {
|
|
|
573
600
|
}
|
|
574
601
|
);
|
|
575
602
|
}
|
|
576
|
-
export
|
|
603
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
604
|
+
0 && (module.exports = {
|
|
577
605
|
connect,
|
|
578
606
|
machine
|
|
579
|
-
};
|
|
607
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
// ../../utilities/dom/dist/index.mjs
|
|
2
|
+
var dataAttr = (guard) => {
|
|
3
|
+
return guard ? "" : void 0;
|
|
4
|
+
};
|
|
5
|
+
var runIfFn = (v, ...a) => {
|
|
6
|
+
const res = typeof v === "function" ? v(...a) : v;
|
|
7
|
+
return res ?? void 0;
|
|
8
|
+
};
|
|
9
|
+
var hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
|
|
10
|
+
function isDocument(el) {
|
|
11
|
+
return el.nodeType === Node.DOCUMENT_NODE;
|
|
12
|
+
}
|
|
13
|
+
function isWindow(value) {
|
|
14
|
+
return (value == null ? void 0 : value.toString()) === "[object Window]";
|
|
15
|
+
}
|
|
16
|
+
function isFrame(element) {
|
|
17
|
+
return element.localName === "iframe";
|
|
18
|
+
}
|
|
19
|
+
function getDocument(el) {
|
|
20
|
+
if (isWindow(el))
|
|
21
|
+
return el.document;
|
|
22
|
+
if (isDocument(el))
|
|
23
|
+
return el;
|
|
24
|
+
return (el == null ? void 0 : el.ownerDocument) ?? document;
|
|
25
|
+
}
|
|
26
|
+
function defineDomHelpers(helpers) {
|
|
27
|
+
const dom2 = {
|
|
28
|
+
getRootNode: (ctx) => {
|
|
29
|
+
var _a;
|
|
30
|
+
return ((_a = ctx.getRootNode) == null ? void 0 : _a.call(ctx)) ?? document;
|
|
31
|
+
},
|
|
32
|
+
getDoc: (ctx) => getDocument(dom2.getRootNode(ctx)),
|
|
33
|
+
getWin: (ctx) => dom2.getDoc(ctx).defaultView ?? window,
|
|
34
|
+
getActiveElement: (ctx) => dom2.getDoc(ctx).activeElement,
|
|
35
|
+
getById: (ctx, id) => dom2.getRootNode(ctx).getElementById(id)
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
...dom2,
|
|
39
|
+
...helpers
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function contains(parent, child) {
|
|
43
|
+
if (!parent)
|
|
44
|
+
return false;
|
|
45
|
+
return parent === child || isHTMLElement(parent) && isHTMLElement(child) && parent.contains(child);
|
|
46
|
+
}
|
|
47
|
+
function isHTMLElement(v) {
|
|
48
|
+
return typeof v === "object" && (v == null ? void 0 : v.nodeType) === Node.ELEMENT_NODE && typeof (v == null ? void 0 : v.nodeName) === "string";
|
|
49
|
+
}
|
|
50
|
+
function isVisible(el) {
|
|
51
|
+
if (!isHTMLElement(el))
|
|
52
|
+
return false;
|
|
53
|
+
return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0;
|
|
54
|
+
}
|
|
55
|
+
var isModifiedEvent = (v) => v.ctrlKey || v.altKey || v.metaKey;
|
|
56
|
+
function hasNegativeTabIndex(element) {
|
|
57
|
+
const tabIndex = parseInt(element.getAttribute("tabindex") || "0", 10);
|
|
58
|
+
return tabIndex < 0;
|
|
59
|
+
}
|
|
60
|
+
var focusableSelector = "input:not([type='hidden']):not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], iframe, object, embed, area[href], audio[controls], video[controls], [contenteditable]:not([contenteditable='false']), details > summary:first-of-type";
|
|
61
|
+
var getFocusables = (container, includeContainer = false) => {
|
|
62
|
+
if (!container)
|
|
63
|
+
return [];
|
|
64
|
+
const elements = Array.from(container.querySelectorAll(focusableSelector));
|
|
65
|
+
const include = includeContainer == true || includeContainer == "if-empty" && elements.length === 0;
|
|
66
|
+
if (include && isHTMLElement(container) && isFocusable(container)) {
|
|
67
|
+
elements.unshift(container);
|
|
68
|
+
}
|
|
69
|
+
const focusableElements = elements.filter(isFocusable);
|
|
70
|
+
focusableElements.forEach((element, i) => {
|
|
71
|
+
if (isFrame(element) && element.contentDocument) {
|
|
72
|
+
const frameBody = element.contentDocument.body;
|
|
73
|
+
focusableElements.splice(i, 1, ...getFocusables(frameBody));
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return focusableElements;
|
|
77
|
+
};
|
|
78
|
+
function isFocusable(element) {
|
|
79
|
+
if (!element)
|
|
80
|
+
return false;
|
|
81
|
+
return element.matches(focusableSelector) && isVisible(element);
|
|
82
|
+
}
|
|
83
|
+
function getTabbables(container, includeContainer) {
|
|
84
|
+
if (!container)
|
|
85
|
+
return [];
|
|
86
|
+
const elements = Array.from(container.querySelectorAll(focusableSelector));
|
|
87
|
+
const tabbableElements = elements.filter(isTabbable);
|
|
88
|
+
if (includeContainer && isTabbable(container)) {
|
|
89
|
+
tabbableElements.unshift(container);
|
|
90
|
+
}
|
|
91
|
+
tabbableElements.forEach((element, i) => {
|
|
92
|
+
if (isFrame(element) && element.contentDocument) {
|
|
93
|
+
const frameBody = element.contentDocument.body;
|
|
94
|
+
const allFrameTabbable = getTabbables(frameBody);
|
|
95
|
+
tabbableElements.splice(i, 1, ...allFrameTabbable);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
if (!tabbableElements.length && includeContainer) {
|
|
99
|
+
return elements;
|
|
100
|
+
}
|
|
101
|
+
return tabbableElements;
|
|
102
|
+
}
|
|
103
|
+
function isTabbable(el) {
|
|
104
|
+
return isFocusable(el) && !hasNegativeTabIndex(el);
|
|
105
|
+
}
|
|
106
|
+
function getFirstTabbable(container, includeContainer) {
|
|
107
|
+
const [first] = getTabbables(container, includeContainer);
|
|
108
|
+
return first || null;
|
|
109
|
+
}
|
|
110
|
+
function getLastTabbable(container, includeContainer) {
|
|
111
|
+
const elements = getTabbables(container, includeContainer);
|
|
112
|
+
return elements[elements.length - 1] || null;
|
|
113
|
+
}
|
|
114
|
+
var isRef = (v) => hasProp(v, "current");
|
|
115
|
+
function addDomEvent(target, eventName, handler, options) {
|
|
116
|
+
const node = isRef(target) ? target.current : runIfFn(target);
|
|
117
|
+
node == null ? void 0 : node.addEventListener(eventName, handler, options);
|
|
118
|
+
return () => {
|
|
119
|
+
node == null ? void 0 : node.removeEventListener(eventName, handler, options);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function nextTick(fn) {
|
|
123
|
+
const set = /* @__PURE__ */ new Set();
|
|
124
|
+
function raf2(fn2) {
|
|
125
|
+
const id = globalThis.requestAnimationFrame(fn2);
|
|
126
|
+
set.add(() => globalThis.cancelAnimationFrame(id));
|
|
127
|
+
}
|
|
128
|
+
raf2(() => raf2(fn));
|
|
129
|
+
return function cleanup() {
|
|
130
|
+
set.forEach(function(fn2) {
|
|
131
|
+
fn2();
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function raf(fn) {
|
|
136
|
+
const id = globalThis.requestAnimationFrame(fn);
|
|
137
|
+
return function cleanup() {
|
|
138
|
+
globalThis.cancelAnimationFrame(id);
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/popover.connect.ts
|
|
143
|
+
import { getPlacementStyles } from "@zag-js/popper";
|
|
144
|
+
|
|
145
|
+
// ../../utilities/core/dist/index.mjs
|
|
146
|
+
function nextIndex(v, idx, opts = {}) {
|
|
147
|
+
const { step = 1, loop = true } = opts;
|
|
148
|
+
const next2 = idx + step;
|
|
149
|
+
const len = v.length;
|
|
150
|
+
const last2 = len - 1;
|
|
151
|
+
if (idx === -1)
|
|
152
|
+
return step > 0 ? 0 : last2;
|
|
153
|
+
if (next2 < 0)
|
|
154
|
+
return loop ? last2 : 0;
|
|
155
|
+
if (next2 >= len)
|
|
156
|
+
return loop ? 0 : idx > len ? len : idx;
|
|
157
|
+
return next2;
|
|
158
|
+
}
|
|
159
|
+
function next(v, idx, opts = {}) {
|
|
160
|
+
return v[nextIndex(v, idx, opts)];
|
|
161
|
+
}
|
|
162
|
+
var runIfFn2 = (v, ...a) => {
|
|
163
|
+
const res = typeof v === "function" ? v(...a) : v;
|
|
164
|
+
return res ?? void 0;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// src/popover.dom.ts
|
|
168
|
+
var dom = defineDomHelpers({
|
|
169
|
+
getActiveEl: (ctx) => dom.getDoc(ctx).activeElement,
|
|
170
|
+
getAnchorId: (ctx) => {
|
|
171
|
+
var _a;
|
|
172
|
+
return ((_a = ctx.ids) == null ? void 0 : _a.anchor) ?? `popover:${ctx.id}:anchor`;
|
|
173
|
+
},
|
|
174
|
+
getTriggerId: (ctx) => {
|
|
175
|
+
var _a;
|
|
176
|
+
return ((_a = ctx.ids) == null ? void 0 : _a.trigger) ?? `popover:${ctx.id}:trigger`;
|
|
177
|
+
},
|
|
178
|
+
getContentId: (ctx) => {
|
|
179
|
+
var _a;
|
|
180
|
+
return ((_a = ctx.ids) == null ? void 0 : _a.content) ?? `popover:${ctx.id}:content`;
|
|
181
|
+
},
|
|
182
|
+
getPositionerId: (ctx) => `popover:${ctx.id}:popper`,
|
|
183
|
+
getArrowId: (ctx) => `popover:${ctx.id}:arrow`,
|
|
184
|
+
getTitleId: (ctx) => {
|
|
185
|
+
var _a;
|
|
186
|
+
return ((_a = ctx.ids) == null ? void 0 : _a.title) ?? `popover:${ctx.id}:title`;
|
|
187
|
+
},
|
|
188
|
+
getDescriptionId: (ctx) => {
|
|
189
|
+
var _a;
|
|
190
|
+
return ((_a = ctx.ids) == null ? void 0 : _a.description) ?? `popover:${ctx.id}:desc`;
|
|
191
|
+
},
|
|
192
|
+
getCloseButtonId: (ctx) => {
|
|
193
|
+
var _a;
|
|
194
|
+
return ((_a = ctx.ids) == null ? void 0 : _a.closeBtn) ?? `popover:${ctx.id}:close-button`;
|
|
195
|
+
},
|
|
196
|
+
getAnchorEl: (ctx) => dom.getById(ctx, dom.getAnchorId(ctx)),
|
|
197
|
+
getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
|
|
198
|
+
getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
|
|
199
|
+
getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
|
|
200
|
+
getTitleEl: (ctx) => dom.getById(ctx, dom.getTitleId(ctx)),
|
|
201
|
+
getDescriptionEl: (ctx) => dom.getById(ctx, dom.getDescriptionId(ctx)),
|
|
202
|
+
getFocusableEls: (ctx) => getFocusables(dom.getContentEl(ctx)),
|
|
203
|
+
getFirstFocusableEl: (ctx) => dom.getFocusableEls(ctx)[0],
|
|
204
|
+
getDocTabbableEls: (ctx) => getTabbables(dom.getDoc(ctx).body),
|
|
205
|
+
getTabbableEls: (ctx) => getTabbables(dom.getContentEl(ctx), "if-empty"),
|
|
206
|
+
getFirstTabbableEl: (ctx) => getFirstTabbable(dom.getContentEl(ctx), "if-empty"),
|
|
207
|
+
getLastTabbableEl: (ctx) => getLastTabbable(dom.getContentEl(ctx), "if-empty"),
|
|
208
|
+
getInitialFocusEl: (ctx) => {
|
|
209
|
+
let el = runIfFn2(ctx.initialFocusEl);
|
|
210
|
+
if (!el && ctx.autoFocus)
|
|
211
|
+
el = dom.getFirstFocusableEl(ctx);
|
|
212
|
+
if (!el)
|
|
213
|
+
el = dom.getContentEl(ctx);
|
|
214
|
+
return el;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// src/popover.connect.ts
|
|
219
|
+
function connect(state, send, normalize) {
|
|
220
|
+
const isOpen = state.matches("open");
|
|
221
|
+
const currentPlacement = state.context.currentPlacement;
|
|
222
|
+
const portalled = state.context.currentPortalled;
|
|
223
|
+
const rendered = state.context.renderedElements;
|
|
224
|
+
const popperStyles = getPlacementStyles({
|
|
225
|
+
measured: !!state.context.isPlacementComplete,
|
|
226
|
+
placement: currentPlacement
|
|
227
|
+
});
|
|
228
|
+
return {
|
|
229
|
+
portalled,
|
|
230
|
+
isOpen,
|
|
231
|
+
open() {
|
|
232
|
+
send("OPEN");
|
|
233
|
+
},
|
|
234
|
+
close() {
|
|
235
|
+
send("CLOSE");
|
|
236
|
+
},
|
|
237
|
+
arrowProps: normalize.element({
|
|
238
|
+
id: dom.getArrowId(state.context),
|
|
239
|
+
"data-part": "arrow",
|
|
240
|
+
style: popperStyles.arrow
|
|
241
|
+
}),
|
|
242
|
+
innerArrowProps: normalize.element({
|
|
243
|
+
"data-part": "arrow-inner",
|
|
244
|
+
style: popperStyles.innerArrow
|
|
245
|
+
}),
|
|
246
|
+
anchorProps: normalize.element({
|
|
247
|
+
"data-part": "anchor",
|
|
248
|
+
id: dom.getAnchorId(state.context)
|
|
249
|
+
}),
|
|
250
|
+
triggerProps: normalize.button({
|
|
251
|
+
"data-part": "trigger",
|
|
252
|
+
type: "button",
|
|
253
|
+
"data-placement": currentPlacement,
|
|
254
|
+
id: dom.getTriggerId(state.context),
|
|
255
|
+
"aria-haspopup": "dialog",
|
|
256
|
+
"aria-expanded": isOpen,
|
|
257
|
+
"data-expanded": dataAttr(isOpen),
|
|
258
|
+
"aria-controls": dom.getContentId(state.context),
|
|
259
|
+
onClick() {
|
|
260
|
+
send("TOGGLE");
|
|
261
|
+
},
|
|
262
|
+
onBlur(event) {
|
|
263
|
+
send({ type: "TRIGGER_BLUR", target: event.relatedTarget });
|
|
264
|
+
}
|
|
265
|
+
}),
|
|
266
|
+
positionerProps: normalize.element({
|
|
267
|
+
id: dom.getPositionerId(state.context),
|
|
268
|
+
"data-part": "positioner",
|
|
269
|
+
style: popperStyles.floating
|
|
270
|
+
}),
|
|
271
|
+
contentProps: normalize.element({
|
|
272
|
+
"data-part": "content",
|
|
273
|
+
id: dom.getContentId(state.context),
|
|
274
|
+
tabIndex: -1,
|
|
275
|
+
role: "dialog",
|
|
276
|
+
hidden: !isOpen,
|
|
277
|
+
"data-expanded": dataAttr(isOpen),
|
|
278
|
+
"aria-labelledby": rendered.title ? dom.getTitleId(state.context) : void 0,
|
|
279
|
+
"aria-describedby": rendered.description ? dom.getDescriptionId(state.context) : void 0,
|
|
280
|
+
"data-placement": currentPlacement
|
|
281
|
+
}),
|
|
282
|
+
titleProps: normalize.element({
|
|
283
|
+
"data-part": "title",
|
|
284
|
+
id: dom.getTitleId(state.context)
|
|
285
|
+
}),
|
|
286
|
+
descriptionProps: normalize.element({
|
|
287
|
+
"data-part": "description",
|
|
288
|
+
id: dom.getDescriptionId(state.context)
|
|
289
|
+
}),
|
|
290
|
+
closeButtonProps: normalize.button({
|
|
291
|
+
"data-part": "close-button",
|
|
292
|
+
id: dom.getCloseButtonId(state.context),
|
|
293
|
+
type: "button",
|
|
294
|
+
"aria-label": "close",
|
|
295
|
+
onClick() {
|
|
296
|
+
send("REQUEST_CLOSE");
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// src/popover.machine.ts
|
|
303
|
+
import { ariaHidden } from "@zag-js/aria-hidden";
|
|
304
|
+
import { createMachine, guards } from "@zag-js/core";
|
|
305
|
+
import { trackDismissableElement } from "@zag-js/dismissable";
|
|
306
|
+
import { getPlacement } from "@zag-js/popper";
|
|
307
|
+
import { preventBodyScroll } from "@zag-js/remove-scroll";
|
|
308
|
+
import { createFocusTrap } from "focus-trap";
|
|
309
|
+
var { and, or, not } = guards;
|
|
310
|
+
function machine(ctx) {
|
|
311
|
+
return createMachine(
|
|
312
|
+
{
|
|
313
|
+
id: "popover",
|
|
314
|
+
initial: "unknown",
|
|
315
|
+
context: {
|
|
316
|
+
closeOnInteractOutside: true,
|
|
317
|
+
closeOnEsc: true,
|
|
318
|
+
autoFocus: true,
|
|
319
|
+
modal: false,
|
|
320
|
+
positioning: {
|
|
321
|
+
placement: "bottom",
|
|
322
|
+
...ctx.positioning
|
|
323
|
+
},
|
|
324
|
+
currentPlacement: void 0,
|
|
325
|
+
...ctx,
|
|
326
|
+
focusTriggerOnClose: true,
|
|
327
|
+
renderedElements: {
|
|
328
|
+
title: true,
|
|
329
|
+
description: true,
|
|
330
|
+
anchor: false
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
computed: {
|
|
334
|
+
currentPortalled: (ctx2) => !!ctx2.modal || !!ctx2.portalled
|
|
335
|
+
},
|
|
336
|
+
states: {
|
|
337
|
+
unknown: {
|
|
338
|
+
on: {
|
|
339
|
+
SETUP: {
|
|
340
|
+
target: ctx.defaultOpen ? "open" : "closed",
|
|
341
|
+
actions: "checkRenderedElements"
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
closed: {
|
|
346
|
+
entry: "invokeOnClose",
|
|
347
|
+
on: {
|
|
348
|
+
TOGGLE: "open",
|
|
349
|
+
OPEN: "open"
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
open: {
|
|
353
|
+
activities: [
|
|
354
|
+
"trapFocus",
|
|
355
|
+
"preventScroll",
|
|
356
|
+
"hideContentBelow",
|
|
357
|
+
"computePlacement",
|
|
358
|
+
"trackInteractionOutside",
|
|
359
|
+
"trackTabKeyDown"
|
|
360
|
+
],
|
|
361
|
+
entry: ["setInitialFocus", "invokeOnOpen"],
|
|
362
|
+
on: {
|
|
363
|
+
CLOSE: "closed",
|
|
364
|
+
REQUEST_CLOSE: {
|
|
365
|
+
target: "closed",
|
|
366
|
+
actions: "focusTriggerIfNeeded"
|
|
367
|
+
},
|
|
368
|
+
TOGGLE: "closed",
|
|
369
|
+
TRIGGER_BLUR: {
|
|
370
|
+
guard: not("isRelatedTargetWithinContent"),
|
|
371
|
+
target: "closed"
|
|
372
|
+
},
|
|
373
|
+
TAB: [
|
|
374
|
+
{
|
|
375
|
+
guard: and("isTriggerFocused", "portalled"),
|
|
376
|
+
actions: "focusFirstTabbableElement"
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
guard: and("isLastTabbableElement", "closeOnInteractOutside", "portalled"),
|
|
380
|
+
target: "closed",
|
|
381
|
+
actions: "focusNextTabbableElementAfterTrigger"
|
|
382
|
+
}
|
|
383
|
+
],
|
|
384
|
+
SHIFT_TAB: {
|
|
385
|
+
guard: and(or("isFirstTabbableElement", "isContentFocused"), "portalled"),
|
|
386
|
+
actions: "focusTriggerIfNeeded"
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
activities: {
|
|
394
|
+
computePlacement(ctx2) {
|
|
395
|
+
ctx2.currentPlacement = ctx2.positioning.placement;
|
|
396
|
+
const anchorEl = ctx2.renderedElements.anchor ? dom.getAnchorEl(ctx2) : dom.getTriggerEl(ctx2);
|
|
397
|
+
return getPlacement(anchorEl, dom.getPositionerEl(ctx2), {
|
|
398
|
+
...ctx2.positioning,
|
|
399
|
+
onComplete(data) {
|
|
400
|
+
ctx2.currentPlacement = data.placement;
|
|
401
|
+
ctx2.isPlacementComplete = true;
|
|
402
|
+
},
|
|
403
|
+
onCleanup() {
|
|
404
|
+
ctx2.currentPlacement = void 0;
|
|
405
|
+
ctx2.isPlacementComplete = false;
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
},
|
|
409
|
+
trackInteractionOutside(ctx2, _evt, { send }) {
|
|
410
|
+
return trackDismissableElement(dom.getContentEl(ctx2), {
|
|
411
|
+
pointerBlocking: ctx2.modal,
|
|
412
|
+
exclude: dom.getTriggerEl(ctx2),
|
|
413
|
+
onEscapeKeyDown(event) {
|
|
414
|
+
var _a;
|
|
415
|
+
(_a = ctx2.onEscapeKeyDown) == null ? void 0 : _a.call(ctx2, event);
|
|
416
|
+
if (ctx2.closeOnEsc)
|
|
417
|
+
return;
|
|
418
|
+
ctx2.focusTriggerOnClose = true;
|
|
419
|
+
event.preventDefault();
|
|
420
|
+
},
|
|
421
|
+
onInteractOutside(event) {
|
|
422
|
+
var _a;
|
|
423
|
+
(_a = ctx2.onInteractOutside) == null ? void 0 : _a.call(ctx2, event);
|
|
424
|
+
if (event.defaultPrevented)
|
|
425
|
+
return;
|
|
426
|
+
ctx2.focusTriggerOnClose = !(event.detail.focusable || event.detail.contextmenu);
|
|
427
|
+
if (!ctx2.closeOnInteractOutside) {
|
|
428
|
+
event.preventDefault();
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
onPointerDownOutside(event) {
|
|
432
|
+
var _a;
|
|
433
|
+
(_a = ctx2.onPointerDownOutside) == null ? void 0 : _a.call(ctx2, event);
|
|
434
|
+
},
|
|
435
|
+
onFocusOutside(event) {
|
|
436
|
+
var _a;
|
|
437
|
+
(_a = ctx2.onFocusOutside) == null ? void 0 : _a.call(ctx2, event);
|
|
438
|
+
if (ctx2.currentPortalled) {
|
|
439
|
+
event.preventDefault();
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
onDismiss() {
|
|
443
|
+
send({ type: "REQUEST_CLOSE", src: "#interact-outside" });
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
},
|
|
447
|
+
trackTabKeyDown(ctx2, _evt, { send }) {
|
|
448
|
+
if (ctx2.modal)
|
|
449
|
+
return;
|
|
450
|
+
return addDomEvent(
|
|
451
|
+
dom.getWin(ctx2),
|
|
452
|
+
"keydown",
|
|
453
|
+
(event) => {
|
|
454
|
+
const isTabKey = event.key === "Tab" && !isModifiedEvent(event);
|
|
455
|
+
if (!isTabKey)
|
|
456
|
+
return;
|
|
457
|
+
send({
|
|
458
|
+
type: event.shiftKey ? "SHIFT_TAB" : "TAB",
|
|
459
|
+
preventDefault: () => event.preventDefault()
|
|
460
|
+
});
|
|
461
|
+
},
|
|
462
|
+
true
|
|
463
|
+
);
|
|
464
|
+
},
|
|
465
|
+
hideContentBelow(ctx2) {
|
|
466
|
+
if (!ctx2.modal)
|
|
467
|
+
return;
|
|
468
|
+
let cleanup;
|
|
469
|
+
nextTick(() => {
|
|
470
|
+
cleanup = ariaHidden([dom.getContentEl(ctx2), dom.getTriggerEl(ctx2)]);
|
|
471
|
+
});
|
|
472
|
+
return () => cleanup == null ? void 0 : cleanup();
|
|
473
|
+
},
|
|
474
|
+
preventScroll(ctx2) {
|
|
475
|
+
if (!ctx2.modal)
|
|
476
|
+
return;
|
|
477
|
+
return preventBodyScroll(dom.getDoc(ctx2));
|
|
478
|
+
},
|
|
479
|
+
trapFocus(ctx2) {
|
|
480
|
+
if (!ctx2.modal)
|
|
481
|
+
return;
|
|
482
|
+
let trap;
|
|
483
|
+
nextTick(() => {
|
|
484
|
+
const el = dom.getContentEl(ctx2);
|
|
485
|
+
if (!el)
|
|
486
|
+
return;
|
|
487
|
+
trap = createFocusTrap(el, {
|
|
488
|
+
escapeDeactivates: false,
|
|
489
|
+
allowOutsideClick: true,
|
|
490
|
+
returnFocusOnDeactivate: true,
|
|
491
|
+
document: dom.getDoc(ctx2),
|
|
492
|
+
fallbackFocus: el,
|
|
493
|
+
initialFocus: runIfFn2(ctx2.initialFocusEl)
|
|
494
|
+
});
|
|
495
|
+
try {
|
|
496
|
+
trap.activate();
|
|
497
|
+
} catch {
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
return () => trap == null ? void 0 : trap.deactivate();
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
guards: {
|
|
504
|
+
portalled: (ctx2) => ctx2.currentPortalled,
|
|
505
|
+
isRelatedTargetWithinContent: (ctx2, evt) => contains(dom.getContentEl(ctx2), evt.target),
|
|
506
|
+
closeOnInteractOutside: (ctx2) => !!ctx2.closeOnInteractOutside,
|
|
507
|
+
isContentFocused: (ctx2) => dom.getContentEl(ctx2) === dom.getActiveEl(ctx2),
|
|
508
|
+
isTriggerFocused: (ctx2) => dom.getTriggerEl(ctx2) === dom.getActiveEl(ctx2),
|
|
509
|
+
isFirstTabbableElement: (ctx2) => dom.getFirstTabbableEl(ctx2) === dom.getActiveEl(ctx2),
|
|
510
|
+
isLastTabbableElement: (ctx2) => dom.getLastTabbableEl(ctx2) === dom.getActiveEl(ctx2)
|
|
511
|
+
},
|
|
512
|
+
actions: {
|
|
513
|
+
checkRenderedElements(ctx2) {
|
|
514
|
+
raf(() => {
|
|
515
|
+
Object.assign(ctx2.renderedElements, {
|
|
516
|
+
title: !!dom.getTitleEl(ctx2),
|
|
517
|
+
description: !!dom.getDescriptionEl(ctx2),
|
|
518
|
+
anchor: !!dom.getAnchorEl(ctx2)
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
},
|
|
522
|
+
setInitialFocus(ctx2) {
|
|
523
|
+
raf(() => {
|
|
524
|
+
var _a;
|
|
525
|
+
(_a = dom.getInitialFocusEl(ctx2)) == null ? void 0 : _a.focus();
|
|
526
|
+
});
|
|
527
|
+
},
|
|
528
|
+
focusTriggerIfNeeded(ctx2) {
|
|
529
|
+
if (!ctx2.focusTriggerOnClose)
|
|
530
|
+
return;
|
|
531
|
+
raf(() => {
|
|
532
|
+
var _a;
|
|
533
|
+
return (_a = dom.getTriggerEl(ctx2)) == null ? void 0 : _a.focus();
|
|
534
|
+
});
|
|
535
|
+
},
|
|
536
|
+
focusFirstTabbableElement(ctx2, evt) {
|
|
537
|
+
var _a;
|
|
538
|
+
evt.preventDefault();
|
|
539
|
+
(_a = dom.getFirstTabbableEl(ctx2)) == null ? void 0 : _a.focus();
|
|
540
|
+
},
|
|
541
|
+
invokeOnOpen(ctx2, evt) {
|
|
542
|
+
var _a;
|
|
543
|
+
if (evt.type !== "SETUP") {
|
|
544
|
+
(_a = ctx2.onOpenChange) == null ? void 0 : _a.call(ctx2, true);
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
invokeOnClose(ctx2, evt) {
|
|
548
|
+
var _a;
|
|
549
|
+
if (evt.type !== "SETUP") {
|
|
550
|
+
(_a = ctx2.onOpenChange) == null ? void 0 : _a.call(ctx2, false);
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
focusNextTabbableElementAfterTrigger(ctx2, evt) {
|
|
554
|
+
const content = dom.getContentEl(ctx2);
|
|
555
|
+
const button = dom.getTriggerEl(ctx2);
|
|
556
|
+
if (!content || !button)
|
|
557
|
+
return;
|
|
558
|
+
const lastTabbable = dom.getLastTabbableEl(ctx2);
|
|
559
|
+
if (lastTabbable !== dom.getActiveEl(ctx2))
|
|
560
|
+
return;
|
|
561
|
+
let tabbables = dom.getDocTabbableEls(ctx2);
|
|
562
|
+
let elementAfterTrigger = next(tabbables, tabbables.indexOf(button), { loop: false });
|
|
563
|
+
if (elementAfterTrigger === content) {
|
|
564
|
+
tabbables = tabbables.filter((el) => !contains(content, el));
|
|
565
|
+
elementAfterTrigger = next(tabbables, tabbables.indexOf(button), { loop: false });
|
|
566
|
+
}
|
|
567
|
+
if (!elementAfterTrigger || elementAfterTrigger === button)
|
|
568
|
+
return;
|
|
569
|
+
evt.preventDefault();
|
|
570
|
+
raf(() => elementAfterTrigger == null ? void 0 : elementAfterTrigger.focus());
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
export {
|
|
577
|
+
connect,
|
|
578
|
+
machine
|
|
579
|
+
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"type": "module",
|
|
3
2
|
"name": "@zag-js/popover",
|
|
4
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
5
4
|
"description": "Core logic for the popover widget implemented as a state machine",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
6
8
|
"keywords": [
|
|
7
9
|
"js",
|
|
8
10
|
"machine",
|
|
@@ -15,8 +17,6 @@
|
|
|
15
17
|
"author": "Segun Adebayo <sage@adebayosegun.com>",
|
|
16
18
|
"homepage": "https://github.com/chakra-ui/zag#readme",
|
|
17
19
|
"license": "MIT",
|
|
18
|
-
"main": "dist/index.js",
|
|
19
|
-
"types": "dist/index.d.ts",
|
|
20
20
|
"repository": "https://github.com/chakra-ui/zag/tree/main/packages/popover",
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"files": [
|
|
@@ -29,22 +29,22 @@
|
|
|
29
29
|
"url": "https://github.com/chakra-ui/zag/issues"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@zag-js/aria-hidden": "0.1.
|
|
33
|
-
"@zag-js/core": "0.1.
|
|
34
|
-
"@zag-js/dismissable": "0.1.
|
|
35
|
-
"@zag-js/popper": "0.1.
|
|
36
|
-
"@zag-js/remove-scroll": "0.1.
|
|
37
|
-
"@zag-js/types": "0.2.
|
|
32
|
+
"@zag-js/aria-hidden": "0.1.4",
|
|
33
|
+
"@zag-js/core": "0.1.12",
|
|
34
|
+
"@zag-js/dismissable": "0.1.6",
|
|
35
|
+
"@zag-js/popper": "0.1.13",
|
|
36
|
+
"@zag-js/remove-scroll": "0.1.6",
|
|
37
|
+
"@zag-js/types": "0.2.7",
|
|
38
38
|
"focus-trap": "7.0.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@zag-js/dom-utils": "0.1.
|
|
42
|
-
"@zag-js/utils": "0.1.
|
|
41
|
+
"@zag-js/dom-utils": "0.1.13",
|
|
42
|
+
"@zag-js/utils": "0.1.6"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
-
"build-fast": "tsup src/index.ts --format=esm",
|
|
45
|
+
"build-fast": "tsup src/index.ts --format=esm,cjs",
|
|
46
46
|
"start": "pnpm build --watch",
|
|
47
|
-
"build": "tsup src/index.ts --format=esm --dts",
|
|
47
|
+
"build": "tsup src/index.ts --format=esm,cjs --dts",
|
|
48
48
|
"test": "jest --config ../../../jest.config.js --rootDir . --passWithNoTests",
|
|
49
49
|
"lint": "eslint src --ext .ts,.tsx",
|
|
50
50
|
"test-ci": "pnpm test --ci --runInBand",
|