@zag-js/popover 0.1.7 → 0.1.10

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.mjs CHANGED
@@ -19,181 +19,62 @@ var __spreadValues = (a, b) => {
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
 
21
21
  // ../../utilities/dom/dist/index.mjs
22
+ var __defProp2 = Object.defineProperty;
23
+ var __getOwnPropSymbols2 = Object.getOwnPropertySymbols;
24
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
25
+ var __propIsEnum2 = Object.prototype.propertyIsEnumerable;
26
+ var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
27
+ var __spreadValues2 = (a, b) => {
28
+ for (var prop in b || (b = {}))
29
+ if (__hasOwnProp2.call(b, prop))
30
+ __defNormalProp2(a, prop, b[prop]);
31
+ if (__getOwnPropSymbols2)
32
+ for (var prop of __getOwnPropSymbols2(b)) {
33
+ if (__propIsEnum2.call(b, prop))
34
+ __defNormalProp2(a, prop, b[prop]);
35
+ }
36
+ return a;
37
+ };
22
38
  var dataAttr = (guard) => {
23
39
  return guard ? "" : void 0;
24
40
  };
25
- function getStyleCache() {
26
- ;
27
- globalThis.__styleCache__ = globalThis.__styleCache__ || /* @__PURE__ */ new WeakMap();
28
- return globalThis.__styleCache__;
29
- }
30
- function getComputedStyle2(el) {
31
- var _a;
32
- if (!el)
33
- return {};
34
- const cache = getStyleCache();
35
- let style = cache.get(el);
36
- if (!style) {
37
- const win = (_a = el == null ? void 0 : el.ownerDocument.defaultView) != null ? _a : window;
38
- style = win.getComputedStyle(el);
39
- cache.set(el, style);
40
- }
41
- return style;
42
- }
43
- function nextTick(fn) {
44
- const set = /* @__PURE__ */ new Set();
45
- function raf2(fn2) {
46
- const id = globalThis.requestAnimationFrame(fn2);
47
- set.add(() => globalThis.cancelAnimationFrame(id));
48
- }
49
- raf2(() => raf2(fn));
50
- return function cleanup() {
51
- set.forEach(function(fn2) {
52
- fn2();
53
- });
54
- };
55
- }
56
- function raf(fn) {
57
- const id = globalThis.requestAnimationFrame(fn);
58
- return function cleanup() {
59
- globalThis.cancelAnimationFrame(id);
60
- };
61
- }
62
- var isDom = () => typeof window !== "undefined";
63
- var hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
64
- var isTouchDevice = isDom() && !!navigator.maxTouchPoints;
65
- var isLeftClick = (v) => v.button === 0;
66
41
  var runIfFn = (v, ...a) => {
67
42
  const res = typeof v === "function" ? v(...a) : v;
68
43
  return res != null ? res : void 0;
69
44
  };
70
- var noop = () => {
71
- };
72
- var pipe = (...fns) => (v) => fns.reduce((a, b) => b(a), v);
73
- function getListenerElements() {
74
- ;
75
- globalThis.__listenerElements__ = globalThis.__listenerElements__ || /* @__PURE__ */ new Map();
76
- return globalThis.__listenerElements__;
45
+ var hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
46
+ function isDocument(el) {
47
+ return el.nodeType === Node.DOCUMENT_NODE;
77
48
  }
78
- function getListenerCache() {
79
- ;
80
- globalThis.__listenerCache__ = globalThis.__listenerCache__ || /* @__PURE__ */ new Map();
81
- return globalThis.__listenerCache__;
49
+ function isWindow(value) {
50
+ return (value == null ? void 0 : value.toString()) === "[object Window]";
82
51
  }
83
- function addGlobalEventListener(node, type, handler, options) {
84
- var _a;
85
- if (!node)
86
- return noop;
87
- const hash = JSON.stringify({ type, options });
88
- const listenerElements = getListenerElements();
89
- const listenerCache = getListenerCache();
90
- const group = listenerElements.get(node);
91
- if (!listenerElements.has(node)) {
92
- const group2 = /* @__PURE__ */ new Map([[hash, /* @__PURE__ */ new Set([handler])]]);
93
- listenerElements.set(node, group2);
94
- } else if (group == null ? void 0 : group.has(hash)) {
95
- (_a = group == null ? void 0 : group.get(hash)) == null ? void 0 : _a.add(handler);
96
- } else {
97
- group == null ? void 0 : group.set(hash, /* @__PURE__ */ new Set([handler]));
98
- }
99
- function attach(node2) {
100
- var _a2, _b;
101
- function listener(event) {
102
- var _a3;
103
- const group2 = listenerElements.get(node2);
104
- (_a3 = group2 == null ? void 0 : group2.get(hash)) == null ? void 0 : _a3.forEach((fn) => fn(event));
105
- }
106
- if (!(listenerCache == null ? void 0 : listenerCache.has(node2))) {
107
- listenerCache.set(node2, /* @__PURE__ */ new Map([[hash, listener]]));
108
- node2.addEventListener(type, listener, options);
109
- return;
110
- }
111
- if (!((_a2 = listenerCache == null ? void 0 : listenerCache.get(node2)) == null ? void 0 : _a2.has(hash))) {
112
- (_b = listenerCache.get(node2)) == null ? void 0 : _b.set(hash, listener);
113
- node2.addEventListener(type, listener, options);
114
- }
115
- }
116
- attach(node);
117
- return function remove() {
118
- var _a2, _b, _c, _d;
119
- if (!listenerElements.has(node))
120
- return;
121
- const group2 = listenerElements.get(node);
122
- (_a2 = group2 == null ? void 0 : group2.get(hash)) == null ? void 0 : _a2.delete(handler);
123
- if (((_b = group2 == null ? void 0 : group2.get(hash)) == null ? void 0 : _b.size) === 0) {
124
- const listener = (_c = listenerCache.get(node)) == null ? void 0 : _c.get(hash);
125
- node.removeEventListener(type, listener, options);
126
- group2 == null ? void 0 : group2.delete(hash);
127
- (_d = listenerCache.get(node)) == null ? void 0 : _d.delete(hash);
128
- if ((group2 == null ? void 0 : group2.size) === 0) {
129
- listenerElements.delete(node);
130
- listenerCache.delete(node);
131
- }
132
- }
133
- };
52
+ function isFrame(element) {
53
+ return element.localName === "iframe";
134
54
  }
135
- var isRef = (v) => hasProp(v, "current");
136
- function addDomEvent(target, event, listener, options) {
137
- const node = isRef(target) ? target.current : runIfFn(target);
138
- return addGlobalEventListener(node, event, listener, options);
55
+ function getDocument(el) {
56
+ var _a;
57
+ if (isWindow(el))
58
+ return el.document;
59
+ if (isDocument(el))
60
+ return el;
61
+ return (_a = el == null ? void 0 : el.ownerDocument) != null ? _a : document;
139
62
  }
140
- var changeCount = 0;
141
- var originalBodyPointerEvents;
142
- function preventBodyPointerEvents(el, opts = {}) {
143
- const { disabled = false, document: docProp } = opts;
144
- const doc = docProp || document;
145
- let isTouchOrPenPressed = false;
146
- let isLeftClickPressed = false;
147
- function listen() {
148
- const onPointerDown = (event) => {
149
- const isMouse = event.pointerType === "mouse";
150
- isTouchOrPenPressed = !isMouse;
151
- isLeftClickPressed = isMouse && isLeftClick(event);
152
- };
153
- const onPointerUp = () => {
154
- isTouchOrPenPressed = false;
155
- isLeftClickPressed = false;
156
- };
157
- return pipe(addDomEvent(doc, "pointerdown", onPointerDown), addDomEvent(doc, "pointerup", onPointerUp));
158
- }
159
- function reset() {
160
- changeCount--;
161
- if (changeCount === 0) {
162
- doc.body.style.pointerEvents = originalBodyPointerEvents;
163
- }
164
- if (el) {
165
- el.style.pointerEvents = "";
166
- }
167
- }
168
- function apply() {
169
- if (disabled)
170
- return;
171
- if (changeCount === 0) {
172
- originalBodyPointerEvents = doc.body.style.pointerEvents;
173
- }
174
- doc.body.style.pointerEvents = "none";
175
- if (el) {
176
- el.style.pointerEvents = "auto";
177
- }
178
- changeCount++;
179
- return function() {
180
- if (isTouchOrPenPressed) {
181
- addDomEvent(doc, "click", reset, { once: true });
182
- } else if (isLeftClickPressed) {
183
- addDomEvent(doc, "pointerup", reset, { once: true });
184
- } else {
185
- reset();
186
- }
187
- };
188
- }
189
- const cleanups = [];
190
- cleanups.push(apply());
191
- nextTick(() => {
192
- cleanups.push(listen());
193
- });
194
- return function() {
195
- cleanups.forEach((cleanup) => cleanup == null ? void 0 : cleanup());
63
+ function defineDomHelpers(helpers) {
64
+ const dom2 = {
65
+ getRootNode: (ctx) => {
66
+ var _a, _b;
67
+ return (_b = (_a = ctx.getRootNode) == null ? void 0 : _a.call(ctx)) != null ? _b : document;
68
+ },
69
+ getDoc: (ctx) => getDocument(dom2.getRootNode(ctx)),
70
+ getWin: (ctx) => {
71
+ var _a;
72
+ return (_a = dom2.getDoc(ctx).defaultView) != null ? _a : window;
73
+ },
74
+ getActiveElement: (ctx) => dom2.getDoc(ctx).activeElement,
75
+ getById: (ctx, id) => dom2.getRootNode(ctx).getElementById(id)
196
76
  };
77
+ return __spreadValues2(__spreadValues2({}, dom2), helpers);
197
78
  }
198
79
  function contains(parent, child) {
199
80
  if (!parent)
@@ -203,147 +84,102 @@ function contains(parent, child) {
203
84
  function isHTMLElement(v) {
204
85
  return typeof v === "object" && (v == null ? void 0 : v.nodeType) === Node.ELEMENT_NODE && typeof (v == null ? void 0 : v.nodeName) === "string";
205
86
  }
206
- var isDisabled = (el) => {
207
- return (el == null ? void 0 : el.getAttribute("disabled")) != null || !!(el == null ? void 0 : el.getAttribute("aria-disabled")) === true;
208
- };
209
- function validateBlur(event, opts) {
210
- var _a;
211
- const exclude = Array.isArray(opts.exclude) ? opts.exclude : [opts.exclude];
212
- const relatedTarget = (_a = event.relatedTarget) != null ? _a : opts.fallback;
213
- return exclude.every((el) => !(el == null ? void 0 : el.contains(relatedTarget)));
87
+ function isVisible(el) {
88
+ if (!isHTMLElement(el))
89
+ return false;
90
+ return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0;
214
91
  }
215
- var focusableSelector = /* @__PURE__ */ [
216
- "input:not([disabled]):not([type=hidden])",
217
- "select:not([disabled])",
218
- "textarea:not([disabled])",
219
- "button:not([disabled])",
220
- "embed",
221
- "iframe",
222
- "object",
223
- "a[href]",
224
- "area[href]",
225
- "[tabindex]",
226
- "audio[controls]",
227
- "video[controls]",
228
- "*[tabindex]:not([aria-disabled])",
229
- "[contenteditable]:not([contenteditable=false])",
230
- "details > summary:first-of-type"
231
- ].join(",");
232
- function isHidden(el, until) {
233
- const style = getComputedStyle2(el);
234
- if (!el || style.getPropertyValue("visibility") === "hidden")
235
- return true;
236
- while (el) {
237
- if (until != null && el === until)
238
- return false;
239
- if (style.getPropertyValue("display") === "none")
240
- return true;
241
- el = el.parentElement;
242
- }
243
- return false;
92
+ var isModifiedEvent = (v) => v.ctrlKey || v.altKey || v.metaKey;
93
+ function hasNegativeTabIndex(element) {
94
+ const tabIndex = parseInt(element.getAttribute("tabindex") || "0", 10);
95
+ return tabIndex < 0;
244
96
  }
245
- var getFocusables = (el, includeContainer = false) => {
246
- if (!el)
97
+ 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";
98
+ var getFocusables = (container, includeContainer = false) => {
99
+ if (!container)
247
100
  return [];
248
- let els = Array.from(el.querySelectorAll(focusableSelector));
249
- const shouldAddContainer = includeContainer == true || includeContainer == "if-empty" && els.length === 0;
250
- if (shouldAddContainer && isHTMLElement(el)) {
251
- els.unshift(el);
101
+ const elements = Array.from(container.querySelectorAll(focusableSelector));
102
+ const include = includeContainer == true || includeContainer == "if-empty" && elements.length === 0;
103
+ if (include && isHTMLElement(container) && isFocusable(container)) {
104
+ elements.unshift(container);
252
105
  }
253
- return els.filter((el2) => isFocusable(el2) && !isHidden(el2));
106
+ const focusableElements = elements.filter(isFocusable);
107
+ focusableElements.forEach((element, i) => {
108
+ if (isFrame(element) && element.contentDocument) {
109
+ const frameBody = element.contentDocument.body;
110
+ focusableElements.splice(i, 1, ...getFocusables(frameBody));
111
+ }
112
+ });
113
+ return focusableElements;
254
114
  };
255
- var isFocusable = (el) => {
256
- if (!isHTMLElement(el) || isHidden(el) || isDisabled(el))
115
+ function isFocusable(element) {
116
+ if (!element)
257
117
  return false;
258
- return el == null ? void 0 : el.matches(focusableSelector);
259
- };
260
- var getTabbables = (el, includeContainer = false) => {
261
- if (!el)
118
+ return element.matches(focusableSelector) && isVisible(element);
119
+ }
120
+ function getTabbables(container, includeContainer) {
121
+ if (!container)
262
122
  return [];
263
- return getFocusables(el, includeContainer).filter(isTabbable);
264
- };
265
- var isTabbable = (el) => {
266
- return isFocusable(el) && !isDisabled(el) && !isHidden(el);
267
- };
268
- function itemById(v, id) {
269
- return v.find((node) => node.id === id);
123
+ const elements = Array.from(container.querySelectorAll(focusableSelector));
124
+ const tabbableElements = elements.filter(isTabbable);
125
+ if (includeContainer && isTabbable(container)) {
126
+ tabbableElements.unshift(container);
127
+ }
128
+ tabbableElements.forEach((element, i) => {
129
+ if (isFrame(element) && element.contentDocument) {
130
+ const frameBody = element.contentDocument.body;
131
+ const allFrameTabbable = getTabbables(frameBody);
132
+ tabbableElements.splice(i, 1, ...allFrameTabbable);
133
+ }
134
+ });
135
+ if (!tabbableElements.length && includeContainer) {
136
+ return elements;
137
+ }
138
+ return tabbableElements;
270
139
  }
271
- function indexOfId(v, id) {
272
- const item = itemById(v, id);
273
- return item ? v.indexOf(item) : -1;
140
+ function isTabbable(el) {
141
+ return isFocusable(el) && !hasNegativeTabIndex(el);
274
142
  }
275
- var getValueText = (item) => {
276
- var _a, _b;
277
- return (_b = (_a = item.dataset.valuetext) != null ? _a : item.textContent) != null ? _b : "";
278
- };
279
- var match = (valueText, query2) => valueText.toLowerCase().startsWith(query2.toLowerCase());
280
- var wrap = (v, idx) => {
281
- return v.map((_, index) => v[(Math.max(idx, 0) + index) % v.length]);
282
- };
283
- function findByText(v, text, currentId) {
284
- const index = currentId ? indexOfId(v, currentId) : -1;
285
- let items = currentId ? wrap(v, index) : v;
286
- const isSingleKey = text.length === 1;
287
- if (isSingleKey) {
288
- items = items.filter((item) => item.id !== currentId);
289
- }
290
- return items.find((item) => match(getValueText(item), text));
143
+ function getFirstTabbable(container, includeContainer) {
144
+ const [first] = getTabbables(container, includeContainer);
145
+ return first || null;
291
146
  }
292
- function trackPointerDown(doc, onPointerDown) {
293
- var _a;
294
- const win = (_a = doc.defaultView) != null ? _a : window;
295
- const fn = (event) => {
296
- if (event.target instanceof win.HTMLElement) {
297
- onPointerDown(event.target);
298
- }
147
+ function getLastTabbable(container, includeContainer) {
148
+ const elements = getTabbables(container, includeContainer);
149
+ return elements[elements.length - 1] || null;
150
+ }
151
+ var isRef = (v) => hasProp(v, "current");
152
+ function addDomEvent(target, eventName, handler, options) {
153
+ const node = isRef(target) ? target.current : runIfFn(target);
154
+ node == null ? void 0 : node.addEventListener(eventName, handler, options);
155
+ return () => {
156
+ node == null ? void 0 : node.removeEventListener(eventName, handler, options);
299
157
  };
300
- return addDomEvent(doc, "pointerdown", fn);
301
158
  }
302
- function findByTypeahead(_items, options) {
303
- const { state: state2, activeId, key, timeout = 350 } = options;
304
- const search = state2.keysSoFar + key;
305
- const isRepeated = search.length > 1 && Array.from(search).every((char) => char === search[0]);
306
- const query2 = isRepeated ? search[0] : search;
307
- let items = _items.slice();
308
- const next2 = findByText(items, query2, activeId);
309
- function cleanup() {
310
- clearTimeout(state2.timer);
311
- state2.timer = -1;
312
- }
313
- function update(value) {
314
- state2.keysSoFar = value;
315
- cleanup();
316
- if (value !== "") {
317
- state2.timer = +setTimeout(() => {
318
- update("");
319
- cleanup();
320
- }, timeout);
321
- }
159
+ function nextTick(fn) {
160
+ const set = /* @__PURE__ */ new Set();
161
+ function raf2(fn2) {
162
+ const id = globalThis.requestAnimationFrame(fn2);
163
+ set.add(() => globalThis.cancelAnimationFrame(id));
322
164
  }
323
- update(search);
324
- return next2;
165
+ raf2(() => raf2(fn));
166
+ return function cleanup() {
167
+ set.forEach(function(fn2) {
168
+ fn2();
169
+ });
170
+ };
171
+ }
172
+ function raf(fn) {
173
+ const id = globalThis.requestAnimationFrame(fn);
174
+ return function cleanup() {
175
+ globalThis.cancelAnimationFrame(id);
176
+ };
325
177
  }
326
- findByTypeahead.defaultOptions = {
327
- keysSoFar: "",
328
- timer: -1
329
- };
330
178
 
331
179
  // src/popover.connect.ts
332
180
  import { getPlacementStyles } from "@zag-js/popper";
333
181
 
334
- // ../../types/dist/index.mjs
335
- function createNormalizer(fn) {
336
- return new Proxy({}, {
337
- get() {
338
- return fn;
339
- }
340
- });
341
- }
342
- var normalizeProp = createNormalizer((v) => v);
343
-
344
182
  // ../../utilities/core/dist/index.mjs
345
- var first = (v) => v[0];
346
- var last = (v) => v[v.length - 1];
347
183
  function nextIndex(v, idx, opts = {}) {
348
184
  const { step = 1, loop = true } = opts;
349
185
  const next2 = idx + step;
@@ -360,63 +196,52 @@ function nextIndex(v, idx, opts = {}) {
360
196
  function next(v, idx, opts = {}) {
361
197
  return v[nextIndex(v, idx, opts)];
362
198
  }
363
- var isDom2 = () => typeof window !== "undefined";
364
- var isTouchDevice2 = isDom2() && !!navigator.maxTouchPoints;
365
199
  var runIfFn2 = (v, ...a) => {
366
200
  const res = typeof v === "function" ? v(...a) : v;
367
201
  return res != null ? res : void 0;
368
202
  };
369
- var cast = (v) => v;
370
203
 
371
204
  // src/popover.dom.ts
372
- var dom = {
373
- getDoc: (ctx) => {
374
- var _a;
375
- return (_a = ctx.doc) != null ? _a : document;
376
- },
205
+ var dom = defineDomHelpers({
377
206
  getActiveEl: (ctx) => dom.getDoc(ctx).activeElement,
378
- getRootNode: (ctx) => {
379
- var _a;
380
- return (_a = ctx.rootNode) != null ? _a : dom.getDoc(ctx);
381
- },
382
207
  getAnchorId: (ctx) => {
383
208
  var _a, _b;
384
- return (_b = (_a = ctx.ids) == null ? void 0 : _a.anchor) != null ? _b : `popover:${ctx.uid}:anchor`;
209
+ return (_b = (_a = ctx.ids) == null ? void 0 : _a.anchor) != null ? _b : `popover:${ctx.id}:anchor`;
385
210
  },
386
211
  getTriggerId: (ctx) => {
387
212
  var _a, _b;
388
- return (_b = (_a = ctx.ids) == null ? void 0 : _a.trigger) != null ? _b : `popover:${ctx.uid}:trigger`;
213
+ return (_b = (_a = ctx.ids) == null ? void 0 : _a.trigger) != null ? _b : `popover:${ctx.id}:trigger`;
389
214
  },
390
215
  getContentId: (ctx) => {
391
216
  var _a, _b;
392
- return (_b = (_a = ctx.ids) == null ? void 0 : _a.content) != null ? _b : `popover:${ctx.uid}:content`;
217
+ return (_b = (_a = ctx.ids) == null ? void 0 : _a.content) != null ? _b : `popover:${ctx.id}:content`;
393
218
  },
394
- getPositionerId: (ctx) => `popover:${ctx.uid}:popper`,
395
- getArrowId: (ctx) => `popover:${ctx.uid}:arrow`,
219
+ getPositionerId: (ctx) => `popover:${ctx.id}:popper`,
220
+ getArrowId: (ctx) => `popover:${ctx.id}:arrow`,
396
221
  getTitleId: (ctx) => {
397
222
  var _a, _b;
398
- return (_b = (_a = ctx.ids) == null ? void 0 : _a.title) != null ? _b : `popover:${ctx.uid}:title`;
223
+ return (_b = (_a = ctx.ids) == null ? void 0 : _a.title) != null ? _b : `popover:${ctx.id}:title`;
399
224
  },
400
225
  getDescriptionId: (ctx) => {
401
226
  var _a, _b;
402
- return (_b = (_a = ctx.ids) == null ? void 0 : _a.description) != null ? _b : `popover:${ctx.uid}:desc`;
227
+ return (_b = (_a = ctx.ids) == null ? void 0 : _a.description) != null ? _b : `popover:${ctx.id}:desc`;
403
228
  },
404
229
  getCloseButtonId: (ctx) => {
405
230
  var _a, _b;
406
- return (_b = (_a = ctx.ids) == null ? void 0 : _a.closeBtn) != null ? _b : `popover:${ctx.uid}:close-button`;
231
+ return (_b = (_a = ctx.ids) == null ? void 0 : _a.closeBtn) != null ? _b : `popover:${ctx.id}:close-button`;
407
232
  },
408
- getAnchorEl: (ctx) => dom.getRootNode(ctx).getElementById(dom.getAnchorId(ctx)),
409
- getTriggerEl: (ctx) => dom.getRootNode(ctx).getElementById(dom.getTriggerId(ctx)),
410
- getContentEl: (ctx) => dom.getRootNode(ctx).getElementById(dom.getContentId(ctx)),
411
- getPositionerEl: (ctx) => dom.getRootNode(ctx).getElementById(dom.getPositionerId(ctx)),
412
- getTitleEl: (ctx) => dom.getRootNode(ctx).getElementById(dom.getTitleId(ctx)),
413
- getDescriptionEl: (ctx) => dom.getRootNode(ctx).getElementById(dom.getDescriptionId(ctx)),
233
+ getAnchorEl: (ctx) => dom.getById(ctx, dom.getAnchorId(ctx)),
234
+ getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
235
+ getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
236
+ getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
237
+ getTitleEl: (ctx) => dom.getById(ctx, dom.getTitleId(ctx)),
238
+ getDescriptionEl: (ctx) => dom.getById(ctx, dom.getDescriptionId(ctx)),
414
239
  getFocusableEls: (ctx) => getFocusables(dom.getContentEl(ctx)),
415
240
  getFirstFocusableEl: (ctx) => dom.getFocusableEls(ctx)[0],
416
- getDocTabbableEls: (ctx) => getTabbables(cast(dom.getDoc(ctx))),
241
+ getDocTabbableEls: (ctx) => getTabbables(dom.getDoc(ctx).body),
417
242
  getTabbableEls: (ctx) => getTabbables(dom.getContentEl(ctx), "if-empty"),
418
- getFirstTabbableEl: (ctx) => first(dom.getTabbableEls(ctx)),
419
- getLastTabbableEl: (ctx) => last(dom.getTabbableEls(ctx)),
243
+ getFirstTabbableEl: (ctx) => getFirstTabbable(dom.getContentEl(ctx), "if-empty"),
244
+ getLastTabbableEl: (ctx) => getLastTabbable(dom.getContentEl(ctx), "if-empty"),
420
245
  getInitialFocusEl: (ctx) => {
421
246
  let el = runIfFn2(ctx.initialFocusEl);
422
247
  if (!el && ctx.autoFocus)
@@ -425,19 +250,20 @@ var dom = {
425
250
  el = dom.getContentEl(ctx);
426
251
  return el;
427
252
  }
428
- };
253
+ });
429
254
 
430
255
  // src/popover.connect.ts
431
- function connect(state, send, normalize = normalizeProp) {
256
+ function connect(state, send, normalize) {
432
257
  const isOpen = state.matches("open");
433
- const pointerdownNode = state.context.pointerdownNode;
434
258
  const currentPlacement = state.context.currentPlacement;
259
+ const portalled = state.context.currentPortalled;
260
+ const rendered = state.context.renderedElements;
435
261
  const popperStyles = getPlacementStyles({
436
262
  measured: !!state.context.isPlacementComplete,
437
263
  placement: currentPlacement
438
264
  });
439
265
  return {
440
- portalled: state.context.currentPortalled,
266
+ portalled,
441
267
  isOpen,
442
268
  open() {
443
269
  send("OPEN");
@@ -468,12 +294,10 @@ function connect(state, send, normalize = normalizeProp) {
468
294
  "data-expanded": dataAttr(isOpen),
469
295
  "aria-controls": dom.getContentId(state.context),
470
296
  onClick() {
471
- send("TRIGGER_CLICK");
297
+ send("TOGGLE");
472
298
  },
473
- onKeyDown(event) {
474
- if (event.key === "Escape") {
475
- send("ESCAPE");
476
- }
299
+ onBlur(event) {
300
+ send({ type: "TRIGGER_BLUR", target: event.relatedTarget });
477
301
  }
478
302
  }),
479
303
  positionerProps: normalize.element({
@@ -488,34 +312,9 @@ function connect(state, send, normalize = normalizeProp) {
488
312
  role: "dialog",
489
313
  hidden: !isOpen,
490
314
  "data-expanded": dataAttr(isOpen),
491
- "aria-labelledby": state.context.renderedElements.title ? dom.getTitleId(state.context) : void 0,
492
- "aria-describedby": state.context.renderedElements.description ? dom.getDescriptionId(state.context) : void 0,
493
- "data-placement": currentPlacement,
494
- onKeyDown(event) {
495
- const keyMap = {
496
- Escape(event2) {
497
- send("ESCAPE");
498
- event2.stopPropagation();
499
- },
500
- Tab(event2) {
501
- const type = event2.shiftKey ? "SHIFT_TAB" : "TAB";
502
- send({ type, preventDefault: () => event2.preventDefault() });
503
- }
504
- };
505
- const exec = keyMap[event.key];
506
- exec == null ? void 0 : exec(event);
507
- },
508
- onBlur(event) {
509
- var _a;
510
- const isValidBlur = validateBlur(event, {
511
- exclude: [dom.getTriggerEl(state.context), dom.getContentEl(state.context)],
512
- fallback: pointerdownNode
513
- });
514
- if (isValidBlur) {
515
- const el = (_a = event.relatedTarget) != null ? _a : pointerdownNode;
516
- send({ type: "INTERACT_OUTSIDE", focusable: isFocusable(el) });
517
- }
518
- }
315
+ "aria-labelledby": rendered.title ? dom.getTitleId(state.context) : void 0,
316
+ "aria-describedby": rendered.description ? dom.getDescriptionId(state.context) : void 0,
317
+ "data-placement": currentPlacement
519
318
  }),
520
319
  titleProps: normalize.element({
521
320
  "data-part": "title",
@@ -531,7 +330,7 @@ function connect(state, send, normalize = normalizeProp) {
531
330
  type: "button",
532
331
  "aria-label": "close",
533
332
  onClick() {
534
- send("CLOSE");
333
+ send("REQUEST_CLOSE");
535
334
  }
536
335
  })
537
336
  };
@@ -539,18 +338,18 @@ function connect(state, send, normalize = normalizeProp) {
539
338
 
540
339
  // src/popover.machine.ts
541
340
  import { ariaHidden } from "@zag-js/aria-hidden";
542
- import { createMachine, guards, ref } from "@zag-js/core";
341
+ import { createMachine, guards } from "@zag-js/core";
342
+ import { trackDismissableElement } from "@zag-js/dismissable";
543
343
  import { getPlacement } from "@zag-js/popper";
544
344
  import { preventBodyScroll } from "@zag-js/remove-scroll";
545
345
  import { createFocusTrap } from "focus-trap";
546
- var { and, or } = guards;
547
- function machine(ctx = {}) {
346
+ var { and, or, not } = guards;
347
+ function machine(ctx) {
548
348
  return createMachine({
549
349
  id: "popover",
550
350
  initial: "unknown",
551
351
  context: __spreadProps(__spreadValues({
552
- uid: "",
553
- closeOnBlur: true,
352
+ closeOnInteractOutside: true,
554
353
  closeOnEsc: true,
555
354
  autoFocus: true,
556
355
  modal: false,
@@ -559,6 +358,7 @@ function machine(ctx = {}) {
559
358
  }, ctx.positioning),
560
359
  currentPlacement: void 0
561
360
  }, ctx), {
361
+ focusTriggerOnClose: true,
562
362
  renderedElements: {
563
363
  title: true,
564
364
  description: true,
@@ -572,63 +372,54 @@ function machine(ctx = {}) {
572
372
  unknown: {
573
373
  on: {
574
374
  SETUP: {
575
- target: ctx.open ? "open" : "closed",
576
- actions: ["setupDocument", "checkRenderedElements"]
375
+ target: ctx.defaultOpen ? "open" : "closed",
376
+ actions: "checkRenderedElements"
577
377
  }
578
378
  }
579
379
  },
580
380
  closed: {
581
- entry: ["clearPointerDown", "invokeOnClose"],
381
+ entry: "invokeOnClose",
582
382
  on: {
583
- TRIGGER_CLICK: "open",
383
+ TOGGLE: "open",
584
384
  OPEN: "open"
585
385
  }
586
386
  },
587
387
  open: {
588
388
  activities: [
589
- "trackPointerDown",
590
389
  "trapFocus",
591
390
  "preventScroll",
592
391
  "hideContentBelow",
593
- "disableOutsidePointerEvents",
594
- "computePlacement"
392
+ "computePlacement",
393
+ "trackInteractionOutside",
394
+ "trackTabKeyDown"
595
395
  ],
596
396
  entry: ["setInitialFocus", "invokeOnOpen"],
597
397
  on: {
598
- CLOSE: {
599
- target: "closed",
600
- actions: "focusTrigger"
601
- },
602
- TRIGGER_CLICK: {
603
- target: "closed",
604
- actions: "focusTrigger"
605
- },
606
- ESCAPE: {
607
- guard: "closeOnEsc",
608
- target: "closed",
609
- actions: "focusTrigger"
610
- },
611
- TAB: {
612
- guard: and("isLastTabbableElement", "closeOnBlur", "portalled"),
398
+ CLOSE: "closed",
399
+ REQUEST_CLOSE: {
613
400
  target: "closed",
614
- actions: "focusNextTabbableElementAfterTrigger"
401
+ actions: "focusTriggerIfNeeded"
615
402
  },
616
- SHIFT_TAB: {
617
- guard: and(or("isFirstTabbableElement", "isContentFocused"), "closeOnBlur", "portalled"),
618
- target: "closed",
619
- actions: "focusTrigger"
403
+ TOGGLE: "closed",
404
+ TRIGGER_BLUR: {
405
+ guard: not("isRelatedTargetWithinContent"),
406
+ target: "closed"
620
407
  },
621
- INTERACT_OUTSIDE: [
408
+ TAB: [
622
409
  {
623
- guard: and("closeOnBlur", "isRelatedTargetFocusable"),
624
- target: "closed"
410
+ guard: and("isTriggerFocused", "portalled"),
411
+ actions: "focusFirstTabbableElement"
625
412
  },
626
413
  {
627
- guard: "closeOnBlur",
414
+ guard: and("isLastTabbableElement", "closeOnInteractOutside", "portalled"),
628
415
  target: "closed",
629
- actions: "focusTrigger"
416
+ actions: "focusNextTabbableElementAfterTrigger"
630
417
  }
631
- ]
418
+ ],
419
+ SHIFT_TAB: {
420
+ guard: and(or("isFirstTabbableElement", "isContentFocused"), "portalled"),
421
+ actions: "focusTriggerIfNeeded"
422
+ }
632
423
  }
633
424
  }
634
425
  }
@@ -648,32 +439,70 @@ function machine(ctx = {}) {
648
439
  }
649
440
  }));
650
441
  },
651
- trackPointerDown(ctx2) {
652
- return trackPointerDown(dom.getDoc(ctx2), (el) => {
653
- ctx2.pointerdownNode = ref(el);
442
+ trackInteractionOutside(ctx2, _evt, { send }) {
443
+ return trackDismissableElement(dom.getContentEl(ctx2), {
444
+ pointerBlocking: ctx2.modal,
445
+ exclude: dom.getTriggerEl(ctx2),
446
+ onEscapeKeyDown(event) {
447
+ var _a;
448
+ (_a = ctx2.onEscapeKeyDown) == null ? void 0 : _a.call(ctx2, event);
449
+ if (ctx2.closeOnEsc)
450
+ return;
451
+ ctx2.focusTriggerOnClose = true;
452
+ event.preventDefault();
453
+ },
454
+ onInteractOutside(event) {
455
+ var _a;
456
+ (_a = ctx2.onInteractOutside) == null ? void 0 : _a.call(ctx2, event);
457
+ if (event.defaultPrevented)
458
+ return;
459
+ ctx2.focusTriggerOnClose = !(event.detail.focusable || event.detail.contextmenu);
460
+ if (!ctx2.closeOnInteractOutside) {
461
+ event.preventDefault();
462
+ }
463
+ },
464
+ onPointerDownOutside(event) {
465
+ var _a;
466
+ (_a = ctx2.onPointerDownOutside) == null ? void 0 : _a.call(ctx2, event);
467
+ },
468
+ onFocusOutside(event) {
469
+ var _a;
470
+ (_a = ctx2.onFocusOutside) == null ? void 0 : _a.call(ctx2, event);
471
+ if (ctx2.currentPortalled) {
472
+ event.preventDefault();
473
+ }
474
+ },
475
+ onDismiss() {
476
+ send({ type: "REQUEST_CLOSE", src: "#interact-outside" });
477
+ }
654
478
  });
655
479
  },
656
- disableOutsidePointerEvents(ctx2) {
657
- const el = dom.getContentEl(ctx2);
658
- return preventBodyPointerEvents(el, {
659
- document: dom.getDoc(ctx2),
660
- disabled: !ctx2.modal
661
- });
480
+ trackTabKeyDown(ctx2, _evt, { send }) {
481
+ if (ctx2.modal)
482
+ return;
483
+ return addDomEvent(dom.getWin(ctx2), "keydown", (event) => {
484
+ const isTabKey = event.key === "Tab" && !isModifiedEvent(event);
485
+ if (!isTabKey)
486
+ return;
487
+ send({
488
+ type: event.shiftKey ? "SHIFT_TAB" : "TAB",
489
+ preventDefault: () => event.preventDefault()
490
+ });
491
+ }, true);
662
492
  },
663
493
  hideContentBelow(ctx2) {
664
494
  if (!ctx2.modal)
665
495
  return;
666
- let unhide;
496
+ let cleanup;
667
497
  nextTick(() => {
668
- unhide = ariaHidden([dom.getContentEl(ctx2), dom.getTriggerEl(ctx2)]);
498
+ cleanup = ariaHidden([dom.getContentEl(ctx2), dom.getTriggerEl(ctx2)]);
669
499
  });
670
- return () => unhide == null ? void 0 : unhide();
500
+ return () => cleanup == null ? void 0 : cleanup();
671
501
  },
672
502
  preventScroll(ctx2) {
673
- return preventBodyScroll({
674
- disabled: !ctx2.modal,
675
- document: dom.getDoc(ctx2)
676
- });
503
+ if (!ctx2.modal)
504
+ return;
505
+ return preventBodyScroll(dom.getDoc(ctx2));
677
506
  },
678
507
  trapFocus(ctx2) {
679
508
  if (!ctx2.modal)
@@ -700,13 +529,11 @@ function machine(ctx = {}) {
700
529
  }
701
530
  },
702
531
  guards: {
703
- closeOnEsc: (ctx2) => !!ctx2.closeOnEsc,
704
- autoFocus: (ctx2) => !!ctx2.autoFocus,
705
- modal: (ctx2) => !!ctx2.modal,
706
- portalled: (ctx2) => !!ctx2.portalled,
707
- isRelatedTargetFocusable: (_ctx, evt) => evt.focusable,
708
- closeOnBlur: (ctx2) => !!ctx2.closeOnBlur,
532
+ portalled: (ctx2) => ctx2.currentPortalled,
533
+ isRelatedTargetWithinContent: (ctx2, evt) => contains(dom.getContentEl(ctx2), evt.target),
534
+ closeOnInteractOutside: (ctx2) => !!ctx2.closeOnInteractOutside,
709
535
  isContentFocused: (ctx2) => dom.getContentEl(ctx2) === dom.getActiveEl(ctx2),
536
+ isTriggerFocused: (ctx2) => dom.getTriggerEl(ctx2) === dom.getActiveEl(ctx2),
710
537
  isFirstTabbableElement: (ctx2) => dom.getFirstTabbableEl(ctx2) === dom.getActiveEl(ctx2),
711
538
  isLastTabbableElement: (ctx2) => dom.getLastTabbableEl(ctx2) === dom.getActiveEl(ctx2)
712
539
  },
@@ -720,48 +547,44 @@ function machine(ctx = {}) {
720
547
  });
721
548
  });
722
549
  },
723
- setupDocument(ctx2, evt) {
724
- if (evt.doc)
725
- ctx2.doc = ref(evt.doc);
726
- if (evt.root)
727
- ctx2.rootNode = ref(evt.root);
728
- ctx2.uid = evt.id;
729
- },
730
- clearPointerDown(ctx2) {
731
- ctx2.pointerdownNode = null;
732
- },
733
550
  setInitialFocus(ctx2) {
734
551
  raf(() => {
735
552
  var _a;
736
553
  (_a = dom.getInitialFocusEl(ctx2)) == null ? void 0 : _a.focus();
737
554
  });
738
555
  },
739
- focusTrigger(ctx2) {
556
+ focusTriggerIfNeeded(ctx2) {
557
+ if (!ctx2.focusTriggerOnClose)
558
+ return;
740
559
  raf(() => {
741
560
  var _a;
742
- (_a = dom.getTriggerEl(ctx2)) == null ? void 0 : _a.focus();
561
+ return (_a = dom.getTriggerEl(ctx2)) == null ? void 0 : _a.focus();
743
562
  });
744
563
  },
564
+ focusFirstTabbableElement(ctx2, evt) {
565
+ var _a;
566
+ evt.preventDefault();
567
+ (_a = dom.getFirstTabbableEl(ctx2)) == null ? void 0 : _a.focus();
568
+ },
745
569
  invokeOnOpen(ctx2, evt) {
746
570
  var _a;
747
571
  if (evt.type !== "SETUP") {
748
- (_a = ctx2.onOpen) == null ? void 0 : _a.call(ctx2);
572
+ (_a = ctx2.onOpenChange) == null ? void 0 : _a.call(ctx2, true);
749
573
  }
750
574
  },
751
575
  invokeOnClose(ctx2, evt) {
752
576
  var _a;
753
577
  if (evt.type !== "SETUP") {
754
- (_a = ctx2.onClose) == null ? void 0 : _a.call(ctx2);
578
+ (_a = ctx2.onOpenChange) == null ? void 0 : _a.call(ctx2, false);
755
579
  }
756
580
  },
757
581
  focusNextTabbableElementAfterTrigger(ctx2, evt) {
758
582
  const content = dom.getContentEl(ctx2);
759
- const doc = dom.getDoc(ctx2);
760
583
  const button = dom.getTriggerEl(ctx2);
761
584
  if (!content || !button)
762
585
  return;
763
586
  const lastTabbable = dom.getLastTabbableEl(ctx2);
764
- if (lastTabbable !== doc.activeElement)
587
+ if (lastTabbable !== dom.getActiveEl(ctx2))
765
588
  return;
766
589
  let tabbables = dom.getDocTabbableEls(ctx2);
767
590
  let elementAfterTrigger = next(tabbables, tabbables.indexOf(button), { loop: false });
@@ -781,4 +604,3 @@ export {
781
604
  connect,
782
605
  machine
783
606
  };
784
- //# sourceMappingURL=index.mjs.map