@zag-js/popover 0.0.0-dev-20220627213111 → 0.0.0-dev-20220703123907

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 CHANGED
@@ -47,12 +47,10 @@ var dataAttr = (guard) => {
47
47
  return guard ? "" : void 0;
48
48
  };
49
49
  var hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
50
- var isLeftClick = (v) => v.button === 0;
51
50
  var runIfFn = (v, ...a) => {
52
51
  const res = typeof v === "function" ? v(...a) : v;
53
52
  return res != null ? res : void 0;
54
53
  };
55
- var pipe = (...fns) => (v) => fns.reduce((a, b) => b(a), v);
56
54
  var isRef = (v) => hasProp(v, "current");
57
55
  function addDomEvent(target, eventName, handler, options) {
58
56
  const node = isRef(target) ? target.current : runIfFn(target);
@@ -80,81 +78,21 @@ function raf(fn) {
80
78
  globalThis.cancelAnimationFrame(id);
81
79
  };
82
80
  }
83
- var changeCount = 0;
84
- var originalBodyPointerEvents;
85
- function preventBodyPointerEvents(el, opts = {}) {
86
- const { disabled = false, document: docProp } = opts;
87
- const doc = docProp || document;
88
- let isTouchOrPenPressed = false;
89
- let isLeftClickPressed = false;
90
- function listen() {
91
- const onPointerDown = (event) => {
92
- const isMouse = event.pointerType === "mouse";
93
- isTouchOrPenPressed = !isMouse;
94
- isLeftClickPressed = isMouse && isLeftClick(event);
95
- };
96
- const onPointerUp = () => {
97
- isTouchOrPenPressed = false;
98
- isLeftClickPressed = false;
99
- };
100
- return pipe(addDomEvent(doc, "pointerdown", onPointerDown), addDomEvent(doc, "pointerup", onPointerUp));
101
- }
102
- function reset() {
103
- changeCount--;
104
- if (changeCount === 0) {
105
- doc.body.style.pointerEvents = originalBodyPointerEvents;
106
- }
107
- if (el) {
108
- el.style.pointerEvents = "";
109
- }
110
- }
111
- function apply() {
112
- if (disabled)
113
- return;
114
- if (changeCount === 0) {
115
- originalBodyPointerEvents = doc.body.style.pointerEvents;
116
- }
117
- doc.body.style.pointerEvents = "none";
118
- if (el) {
119
- el.style.pointerEvents = "auto";
120
- }
121
- changeCount++;
122
- return function() {
123
- if (isTouchOrPenPressed) {
124
- addDomEvent(doc, "click", reset, { once: true });
125
- } else if (isLeftClickPressed) {
126
- addDomEvent(doc, "pointerup", reset, { once: true });
127
- } else {
128
- reset();
129
- }
130
- };
131
- }
132
- const cleanups = [];
133
- cleanups.push(apply());
134
- nextTick(() => {
135
- cleanups.push(listen());
136
- });
137
- return function() {
138
- cleanups.forEach((cleanup) => cleanup == null ? void 0 : cleanup());
139
- };
81
+ function isWindow(value) {
82
+ return (value == null ? void 0 : value.toString()) === "[object Window]";
140
83
  }
141
- function getCache() {
142
- const g = globalThis;
143
- g.__styleCache__ = g.__styleCache__ || /* @__PURE__ */ new WeakMap();
144
- return g.__styleCache__;
84
+ function isFrame(element) {
85
+ return element.localName === "iframe";
145
86
  }
146
- function getComputedStyle(el) {
87
+ function getDocument(el) {
147
88
  var _a;
148
- if (!el)
149
- return {};
150
- const cache = getCache();
151
- let style = cache.get(el);
152
- if (!style) {
153
- const win = (_a = el == null ? void 0 : el.ownerDocument.defaultView) != null ? _a : window;
154
- style = win.getComputedStyle(el);
155
- cache.set(el, style);
156
- }
157
- return style;
89
+ if (isWindow(el))
90
+ return el.document;
91
+ return (_a = el == null ? void 0 : el.ownerDocument) != null ? _a : document;
92
+ }
93
+ function getEventTarget(event) {
94
+ var _a, _b;
95
+ return (_b = (_a = event.composedPath) == null ? void 0 : _a.call(event)[0]) != null ? _b : event.target;
158
96
  }
159
97
  function contains(parent, child) {
160
98
  if (!parent)
@@ -164,95 +102,74 @@ function contains(parent, child) {
164
102
  function isHTMLElement(v) {
165
103
  return typeof v === "object" && (v == null ? void 0 : v.nodeType) === Node.ELEMENT_NODE && typeof (v == null ? void 0 : v.nodeName) === "string";
166
104
  }
167
- var isDisabled = (el) => {
168
- return (el == null ? void 0 : el.getAttribute("disabled")) != null || !!(el == null ? void 0 : el.getAttribute("aria-disabled")) === true;
169
- };
170
- function validateBlur(event, opts) {
171
- var _a;
172
- const exclude = Array.isArray(opts.exclude) ? opts.exclude : [opts.exclude];
173
- const relatedTarget = (_a = event.relatedTarget) != null ? _a : opts.fallback;
174
- return exclude.every((el) => !(el == null ? void 0 : el.contains(relatedTarget)));
175
- }
176
- var focusableSelector = /* @__PURE__ */ [
177
- "input:not([disabled]):not([type=hidden])",
178
- "select:not([disabled])",
179
- "textarea:not([disabled])",
180
- "button:not([disabled])",
181
- "embed",
182
- "iframe",
183
- "object",
184
- "a[href]",
185
- "area[href]",
186
- "[tabindex]",
187
- "audio[controls]",
188
- "video[controls]",
189
- "*[tabindex]:not([aria-disabled])",
190
- "[contenteditable]:not([contenteditable=false])",
191
- "details > summary:first-of-type"
192
- ].join(",");
193
- function isHidden(el, until) {
194
- const style = getComputedStyle(el);
195
- if (!el || style.getPropertyValue("visibility") === "hidden")
196
- return true;
197
- while (el) {
198
- if (until != null && el === until)
199
- return false;
200
- if (style.getPropertyValue("display") === "none")
201
- return true;
202
- el = el.parentElement;
203
- }
204
- return false;
105
+ function isVisible(el) {
106
+ if (!isHTMLElement(el))
107
+ return false;
108
+ return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0;
205
109
  }
206
- var getFocusables = (el, includeContainer = false) => {
207
- if (!el)
110
+ function hasNegativeTabIndex(element) {
111
+ const tabIndex = parseInt(element.getAttribute("tabindex") || "0", 10);
112
+ return tabIndex < 0;
113
+ }
114
+ 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";
115
+ var getFocusables = (container, includeContainer = false) => {
116
+ if (!container)
208
117
  return [];
209
- let els = Array.from(el.querySelectorAll(focusableSelector));
210
- const shouldAddContainer = includeContainer == true || includeContainer == "if-empty" && els.length === 0;
211
- if (shouldAddContainer && isHTMLElement(el)) {
212
- els.unshift(el);
118
+ const elements = Array.from(container.querySelectorAll(focusableSelector));
119
+ const include = includeContainer == true || includeContainer == "if-empty" && elements.length === 0;
120
+ if (include && isHTMLElement(container) && isFocusable(container)) {
121
+ elements.unshift(container);
213
122
  }
214
- return els.filter((el2) => isFocusable(el2) && !isHidden(el2));
123
+ const focusableElements = elements.filter(isFocusable);
124
+ focusableElements.forEach((element, i) => {
125
+ if (isFrame(element) && element.contentDocument) {
126
+ const frameBody = element.contentDocument.body;
127
+ focusableElements.splice(i, 1, ...getFocusables(frameBody));
128
+ }
129
+ });
130
+ return focusableElements;
215
131
  };
216
- var isFocusable = (el) => {
217
- if (!isHTMLElement(el) || isHidden(el) || isDisabled(el))
132
+ function isFocusable(element) {
133
+ if (!element)
218
134
  return false;
219
- return el == null ? void 0 : el.matches(focusableSelector);
220
- };
221
- var getTabbables = (el, includeContainer = false) => {
222
- if (!el)
135
+ return element.matches(focusableSelector) && isVisible(element);
136
+ }
137
+ function getTabbables(container, includeContainer) {
138
+ if (!container)
223
139
  return [];
224
- return getFocusables(el, includeContainer).filter(isTabbable);
225
- };
226
- var isTabbable = (el) => {
227
- return isFocusable(el) && !isDisabled(el) && !isHidden(el);
228
- };
229
- function trackPointerDown(doc, onPointerDown) {
230
- var _a;
231
- const win = (_a = doc.defaultView) != null ? _a : window;
232
- const fn = (event) => {
233
- if (event.target instanceof win.HTMLElement) {
234
- onPointerDown(event.target);
140
+ const elements = Array.from(container.querySelectorAll(focusableSelector));
141
+ const tabbableElements = elements.filter(isTabbable);
142
+ if (includeContainer && isTabbable(container)) {
143
+ tabbableElements.unshift(container);
144
+ }
145
+ tabbableElements.forEach((element, i) => {
146
+ if (isFrame(element) && element.contentDocument) {
147
+ const frameBody = element.contentDocument.body;
148
+ const allFrameTabbable = getTabbables(frameBody);
149
+ tabbableElements.splice(i, 1, ...allFrameTabbable);
235
150
  }
236
- };
237
- return addDomEvent(doc, "pointerdown", fn);
151
+ });
152
+ if (!tabbableElements.length && includeContainer) {
153
+ return elements;
154
+ }
155
+ return tabbableElements;
156
+ }
157
+ function isTabbable(el) {
158
+ return isFocusable(el) && !hasNegativeTabIndex(el);
159
+ }
160
+ function getFirstTabbable(container, includeContainer) {
161
+ const [first] = getTabbables(container, includeContainer);
162
+ return first || null;
163
+ }
164
+ function getLastTabbable(container, includeContainer) {
165
+ const elements = getTabbables(container, includeContainer);
166
+ return elements[elements.length - 1] || null;
238
167
  }
239
168
 
240
169
  // src/popover.connect.ts
241
170
  var import_popper = require("@zag-js/popper");
242
171
 
243
- // ../../types/dist/index.mjs
244
- function createNormalizer(fn) {
245
- return new Proxy({}, {
246
- get() {
247
- return fn;
248
- }
249
- });
250
- }
251
- var normalizeProp = createNormalizer((v) => v);
252
-
253
172
  // ../../utilities/core/dist/index.mjs
254
- var first = (v) => v[0];
255
- var last = (v) => v[v.length - 1];
256
173
  function nextIndex(v, idx, opts = {}) {
257
174
  const { step = 1, loop = true } = opts;
258
175
  const next2 = idx + step;
@@ -269,11 +186,11 @@ function nextIndex(v, idx, opts = {}) {
269
186
  function next(v, idx, opts = {}) {
270
187
  return v[nextIndex(v, idx, opts)];
271
188
  }
189
+ var isModifiedEvent = (v) => v.ctrlKey || v.altKey || v.metaKey;
272
190
  var runIfFn2 = (v, ...a) => {
273
191
  const res = typeof v === "function" ? v(...a) : v;
274
192
  return res != null ? res : void 0;
275
193
  };
276
- var cast = (v) => v;
277
194
 
278
195
  // src/popover.dom.ts
279
196
  var dom = {
@@ -281,6 +198,10 @@ var dom = {
281
198
  var _a;
282
199
  return (_a = ctx.doc) != null ? _a : document;
283
200
  },
201
+ getWin: (ctx) => {
202
+ var _a;
203
+ return (_a = dom.getDoc(ctx).defaultView) != null ? _a : window;
204
+ },
284
205
  getActiveEl: (ctx) => dom.getDoc(ctx).activeElement,
285
206
  getRootNode: (ctx) => {
286
207
  var _a;
@@ -320,10 +241,10 @@ var dom = {
320
241
  getDescriptionEl: (ctx) => dom.getRootNode(ctx).getElementById(dom.getDescriptionId(ctx)),
321
242
  getFocusableEls: (ctx) => getFocusables(dom.getContentEl(ctx)),
322
243
  getFirstFocusableEl: (ctx) => dom.getFocusableEls(ctx)[0],
323
- getDocTabbableEls: (ctx) => getTabbables(cast(dom.getDoc(ctx))),
244
+ getDocTabbableEls: (ctx) => getTabbables(dom.getDoc(ctx).body),
324
245
  getTabbableEls: (ctx) => getTabbables(dom.getContentEl(ctx), "if-empty"),
325
- getFirstTabbableEl: (ctx) => first(dom.getTabbableEls(ctx)),
326
- getLastTabbableEl: (ctx) => last(dom.getTabbableEls(ctx)),
246
+ getFirstTabbableEl: (ctx) => getFirstTabbable(dom.getContentEl(ctx), "if-empty"),
247
+ getLastTabbableEl: (ctx) => getLastTabbable(dom.getContentEl(ctx), "if-empty"),
327
248
  getInitialFocusEl: (ctx) => {
328
249
  let el = runIfFn2(ctx.initialFocusEl);
329
250
  if (!el && ctx.autoFocus)
@@ -335,16 +256,17 @@ var dom = {
335
256
  };
336
257
 
337
258
  // src/popover.connect.ts
338
- function connect(state, send, normalize = normalizeProp) {
259
+ function connect(state, send, normalize) {
339
260
  const isOpen = state.matches("open");
340
- const pointerdownNode = state.context.pointerdownNode;
341
261
  const currentPlacement = state.context.currentPlacement;
262
+ const portalled = state.context.currentPortalled;
263
+ const rendered = state.context.renderedElements;
342
264
  const popperStyles = (0, import_popper.getPlacementStyles)({
343
265
  measured: !!state.context.isPlacementComplete,
344
266
  placement: currentPlacement
345
267
  });
346
268
  return {
347
- portalled: state.context.currentPortalled,
269
+ portalled,
348
270
  isOpen,
349
271
  open() {
350
272
  send("OPEN");
@@ -375,12 +297,10 @@ function connect(state, send, normalize = normalizeProp) {
375
297
  "data-expanded": dataAttr(isOpen),
376
298
  "aria-controls": dom.getContentId(state.context),
377
299
  onClick() {
378
- send("TRIGGER_CLICK");
300
+ send("TOGGLE");
379
301
  },
380
- onKeyDown(event) {
381
- if (event.key === "Escape") {
382
- send("ESCAPE");
383
- }
302
+ onBlur(event) {
303
+ send({ type: "TRIGGER_BLUR", target: event.relatedTarget });
384
304
  }
385
305
  }),
386
306
  positionerProps: normalize.element({
@@ -395,34 +315,9 @@ function connect(state, send, normalize = normalizeProp) {
395
315
  role: "dialog",
396
316
  hidden: !isOpen,
397
317
  "data-expanded": dataAttr(isOpen),
398
- "aria-labelledby": state.context.renderedElements.title ? dom.getTitleId(state.context) : void 0,
399
- "aria-describedby": state.context.renderedElements.description ? dom.getDescriptionId(state.context) : void 0,
400
- "data-placement": currentPlacement,
401
- onKeyDown(event) {
402
- const keyMap = {
403
- Escape(event2) {
404
- send("ESCAPE");
405
- event2.stopPropagation();
406
- },
407
- Tab(event2) {
408
- const type = event2.shiftKey ? "SHIFT_TAB" : "TAB";
409
- send({ type, preventDefault: () => event2.preventDefault() });
410
- }
411
- };
412
- const exec = keyMap[event.key];
413
- exec == null ? void 0 : exec(event);
414
- },
415
- onBlur(event) {
416
- var _a;
417
- const isValidBlur = validateBlur(event, {
418
- exclude: [dom.getTriggerEl(state.context), dom.getContentEl(state.context)],
419
- fallback: pointerdownNode
420
- });
421
- if (isValidBlur) {
422
- const el = (_a = event.relatedTarget) != null ? _a : pointerdownNode;
423
- send({ type: "INTERACT_OUTSIDE", focusable: isFocusable(el) });
424
- }
425
- }
318
+ "aria-labelledby": rendered.title ? dom.getTitleId(state.context) : void 0,
319
+ "aria-describedby": rendered.description ? dom.getDescriptionId(state.context) : void 0,
320
+ "data-placement": currentPlacement
426
321
  }),
427
322
  titleProps: normalize.element({
428
323
  "data-part": "title",
@@ -438,7 +333,7 @@ function connect(state, send, normalize = normalizeProp) {
438
333
  type: "button",
439
334
  "aria-label": "close",
440
335
  onClick() {
441
- send("CLOSE");
336
+ send("REQUEST_CLOSE");
442
337
  }
443
338
  })
444
339
  };
@@ -447,17 +342,324 @@ function connect(state, send, normalize = normalizeProp) {
447
342
  // src/popover.machine.ts
448
343
  var import_aria_hidden = require("@zag-js/aria-hidden");
449
344
  var import_core = require("@zag-js/core");
345
+
346
+ // ../../utilities/interact-outside/dist/index.mjs
347
+ var hasProp2 = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
348
+ var runIfFn3 = (v, ...a) => {
349
+ const res = typeof v === "function" ? v(...a) : v;
350
+ return res != null ? res : void 0;
351
+ };
352
+ var isRef2 = (v) => hasProp2(v, "current");
353
+ function addDomEvent2(target, eventName, handler, options) {
354
+ const node = isRef2(target) ? target.current : runIfFn3(target);
355
+ node == null ? void 0 : node.addEventListener(eventName, handler, options);
356
+ return () => {
357
+ node == null ? void 0 : node.removeEventListener(eventName, handler, options);
358
+ };
359
+ }
360
+ function isWindow2(value) {
361
+ return (value == null ? void 0 : value.toString()) === "[object Window]";
362
+ }
363
+ function getDocument2(el) {
364
+ var _a;
365
+ if (isWindow2(el))
366
+ return el.document;
367
+ return (_a = el == null ? void 0 : el.ownerDocument) != null ? _a : document;
368
+ }
369
+ function getWindow(el) {
370
+ var _a;
371
+ return (_a = el == null ? void 0 : el.ownerDocument.defaultView) != null ? _a : window;
372
+ }
373
+ function getEventTarget2(event) {
374
+ var _a, _b;
375
+ return (_b = (_a = event.composedPath) == null ? void 0 : _a.call(event)[0]) != null ? _b : event.target;
376
+ }
377
+ function contains2(parent, child) {
378
+ if (!parent)
379
+ return false;
380
+ return parent === child || isHTMLElement2(parent) && isHTMLElement2(child) && parent.contains(child);
381
+ }
382
+ function isHTMLElement2(v) {
383
+ return typeof v === "object" && (v == null ? void 0 : v.nodeType) === Node.ELEMENT_NODE && typeof (v == null ? void 0 : v.nodeName) === "string";
384
+ }
385
+ function isVisible2(el) {
386
+ if (!isHTMLElement2(el))
387
+ return false;
388
+ return el.offsetWidth > 0 || el.offsetHeight > 0 || el.getClientRects().length > 0;
389
+ }
390
+ function fireCustomEvent(el, type, init) {
391
+ if (!el)
392
+ return;
393
+ const event = new CustomEvent(type, init);
394
+ return el.dispatchEvent(event);
395
+ }
396
+ var focusableSelector2 = "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";
397
+ function isFocusable2(element) {
398
+ if (!element)
399
+ return false;
400
+ return element.matches(focusableSelector2) && isVisible2(element);
401
+ }
402
+ var isDom = () => typeof window !== "undefined";
403
+ function getPlatform() {
404
+ var _a;
405
+ const agent = navigator.userAgentData;
406
+ return (_a = agent == null ? void 0 : agent.platform) != null ? _a : navigator.platform;
407
+ }
408
+ var pt = (v) => isDom() && v.test(getPlatform());
409
+ var isTouchDevice = () => isDom() && !!navigator.maxTouchPoints;
410
+ var isMac = () => pt(/^Mac/) && !isTouchDevice;
411
+ var isContextMenuEvent = (e) => {
412
+ return e.button === 2 || isCtrlKey(e) && e.button === 0;
413
+ };
414
+ var isCtrlKey = (v) => isMac() ? v.metaKey && !v.ctrlKey : v.ctrlKey && !v.metaKey;
415
+ var POINTER_OUTSIDE_EVENT = "pointerdown.outside";
416
+ var FOCUS_OUTSIDE_EVENT = "focus.outside";
417
+ function trackInteractOutside(node, options) {
418
+ const { exclude, onFocusOutside, onPointerDownOutside } = options;
419
+ if (!node)
420
+ return;
421
+ const doc = getDocument2(node);
422
+ const win = getWindow(node);
423
+ function isEventOutside(event) {
424
+ const target = getEventTarget2(event);
425
+ if (!(target instanceof win.HTMLElement)) {
426
+ return false;
427
+ }
428
+ if (!contains2(doc.documentElement, target)) {
429
+ return false;
430
+ }
431
+ if (contains2(node, target)) {
432
+ return false;
433
+ }
434
+ return !(exclude == null ? void 0 : exclude(target));
435
+ }
436
+ let clickHandler;
437
+ function onPointerDown(event) {
438
+ function handler() {
439
+ if (!node || !isEventOutside(event))
440
+ return;
441
+ if (onPointerDownOutside) {
442
+ node.addEventListener(POINTER_OUTSIDE_EVENT, onPointerDownOutside, { once: true });
443
+ }
444
+ fireCustomEvent(node, POINTER_OUTSIDE_EVENT, {
445
+ bubbles: false,
446
+ cancelable: true,
447
+ detail: {
448
+ originalEvent: event,
449
+ contextmenu: isContextMenuEvent(event),
450
+ focusable: isFocusable2(getEventTarget2(event))
451
+ }
452
+ });
453
+ }
454
+ if (event.pointerType === "touch") {
455
+ doc.removeEventListener("click", handler);
456
+ clickHandler = handler;
457
+ doc.addEventListener("click", handler, { once: true });
458
+ } else {
459
+ handler();
460
+ }
461
+ }
462
+ const cleanups = /* @__PURE__ */ new Set();
463
+ const timer = setTimeout(() => {
464
+ cleanups.add(addDomEvent2(doc, "pointerdown", onPointerDown, true));
465
+ }, 0);
466
+ function onFocusin(event) {
467
+ if (!node || !isEventOutside(event))
468
+ return;
469
+ if (onFocusOutside) {
470
+ node.addEventListener(FOCUS_OUTSIDE_EVENT, onFocusOutside, { once: true });
471
+ }
472
+ fireCustomEvent(node, FOCUS_OUTSIDE_EVENT, {
473
+ bubbles: false,
474
+ cancelable: true,
475
+ detail: {
476
+ originalEvent: event,
477
+ contextmenu: false,
478
+ focusable: isFocusable2(getEventTarget2(event))
479
+ }
480
+ });
481
+ }
482
+ cleanups.add(addDomEvent2(doc, "focusin", onFocusin, true));
483
+ return () => {
484
+ clearTimeout(timer);
485
+ if (clickHandler)
486
+ doc.removeEventListener("click", clickHandler);
487
+ cleanups.forEach((fn) => fn());
488
+ };
489
+ }
490
+
491
+ // ../../utilities/dismissable/src/escape-keydown.ts
492
+ function trackEscapeKeydown(fn) {
493
+ const handleKeyDown = (event) => {
494
+ if (event.key === "Escape")
495
+ fn == null ? void 0 : fn(event);
496
+ };
497
+ return addDomEvent(document, "keydown", handleKeyDown);
498
+ }
499
+
500
+ // ../../utilities/dismissable/src/layer-stack.ts
501
+ var layerStack = {
502
+ layers: [],
503
+ branches: [],
504
+ count() {
505
+ return this.layers.length;
506
+ },
507
+ pointerBlockingLayers() {
508
+ return this.layers.filter((layer) => layer.pointerBlocking);
509
+ },
510
+ topMostPointerBlockingLayer() {
511
+ return [...this.pointerBlockingLayers()].slice(-1)[0];
512
+ },
513
+ hasPointerBlockingLayer() {
514
+ return this.pointerBlockingLayers().length > 0;
515
+ },
516
+ isBelowPointerBlockingLayer(node) {
517
+ var _a;
518
+ const index = this.indexOf(node);
519
+ const highestBlockingIndex = this.topMostPointerBlockingLayer() ? this.indexOf((_a = this.topMostPointerBlockingLayer()) == null ? void 0 : _a.node) : -1;
520
+ return index < highestBlockingIndex;
521
+ },
522
+ isTopMost(node) {
523
+ const layer = this.layers[this.count() - 1];
524
+ return (layer == null ? void 0 : layer.node) === node;
525
+ },
526
+ getChildLayers(node) {
527
+ return this.layers.slice(this.indexOf(node));
528
+ },
529
+ isInChildLayer(node, target) {
530
+ return this.getChildLayers(node).some((layer) => contains(layer.node, target));
531
+ },
532
+ isInBranch(target) {
533
+ return [...this.branches].some((branch) => contains(branch, target));
534
+ },
535
+ add(layer) {
536
+ this.layers.push(layer);
537
+ },
538
+ addBranch(node) {
539
+ this.branches.push(node);
540
+ },
541
+ remove(node) {
542
+ const index = this.indexOf(node);
543
+ if (index + 1 < this.count() - 1) {
544
+ this.layers.splice(index, this.count()).forEach((item) => item.dismiss());
545
+ }
546
+ this.layers = this.layers.filter((item) => item.node !== node);
547
+ },
548
+ removeBranch(node) {
549
+ const index = this.branches.indexOf(node);
550
+ if (index >= 0)
551
+ this.branches.splice(index, 1);
552
+ },
553
+ indexOf(node) {
554
+ return this.layers.findIndex((layer) => layer.node === node);
555
+ },
556
+ dismiss(node) {
557
+ var _a;
558
+ (_a = this.layers[this.indexOf(node)]) == null ? void 0 : _a.dismiss();
559
+ },
560
+ clear() {
561
+ this.remove(this.layers[0].node);
562
+ }
563
+ };
564
+
565
+ // ../../utilities/dismissable/src/pointer-event-outside.ts
566
+ var originalBodyPointerEvents;
567
+ function assignPointerEventToLayers() {
568
+ layerStack.layers.forEach(({ node }) => {
569
+ node.style.pointerEvents = layerStack.isBelowPointerBlockingLayer(node) ? "none" : "auto";
570
+ });
571
+ }
572
+ function clearPointerEvent(node) {
573
+ node.style.pointerEvents = "";
574
+ }
575
+ var DATA_ATTR = "data-inert";
576
+ function disablePointerEventsOutside(node) {
577
+ const doc = getDocument(node);
578
+ if (layerStack.hasPointerBlockingLayer() && !doc.body.hasAttribute(DATA_ATTR)) {
579
+ originalBodyPointerEvents = document.body.style.pointerEvents;
580
+ doc.body.style.pointerEvents = "none";
581
+ doc.body.setAttribute(DATA_ATTR, "");
582
+ }
583
+ return () => {
584
+ if (layerStack.hasPointerBlockingLayer())
585
+ return;
586
+ doc.body.style.pointerEvents = originalBodyPointerEvents;
587
+ doc.body.removeAttribute(DATA_ATTR);
588
+ if (doc.body.style.length === 0)
589
+ doc.body.removeAttribute("style");
590
+ };
591
+ }
592
+
593
+ // ../../utilities/dismissable/src/dismissable-layer.ts
594
+ function trackDismissableElement(node, options) {
595
+ if (!node)
596
+ return;
597
+ const { onDismiss, pointerBlocking, exclude: excludeContainers } = options;
598
+ const layer = { dismiss: onDismiss, node, pointerBlocking };
599
+ layerStack.add(layer);
600
+ assignPointerEventToLayers();
601
+ function onPointerDownOutside(event) {
602
+ var _a, _b;
603
+ const target = getEventTarget(event.detail.originalEvent);
604
+ if (layerStack.isBelowPointerBlockingLayer(node) || layerStack.isInBranch(target))
605
+ return;
606
+ (_a = options.onPointerDownOutside) == null ? void 0 : _a.call(options, event);
607
+ (_b = options.onInteractOutside) == null ? void 0 : _b.call(options, event);
608
+ if (event.defaultPrevented)
609
+ return;
610
+ onDismiss == null ? void 0 : onDismiss();
611
+ }
612
+ function onFocusOutside(event) {
613
+ var _a, _b;
614
+ const target = getEventTarget(event.detail.originalEvent);
615
+ if (layerStack.isInBranch(target))
616
+ return;
617
+ (_a = options.onFocusOutside) == null ? void 0 : _a.call(options, event);
618
+ (_b = options.onInteractOutside) == null ? void 0 : _b.call(options, event);
619
+ if (event.defaultPrevented)
620
+ return;
621
+ onDismiss == null ? void 0 : onDismiss();
622
+ }
623
+ function onEscapeKeyDown(event) {
624
+ var _a;
625
+ if (!layerStack.isTopMost(node))
626
+ return;
627
+ (_a = options.onEscapeKeyDown) == null ? void 0 : _a.call(options, event);
628
+ if (!event.defaultPrevented && onDismiss) {
629
+ event.preventDefault();
630
+ onDismiss();
631
+ }
632
+ }
633
+ function exclude(target) {
634
+ const containers = typeof excludeContainers === "function" ? excludeContainers() : excludeContainers;
635
+ const inContainers = Array.isArray(containers) ? containers : [containers];
636
+ return inContainers.some((node2) => contains(node2, target)) || layerStack.isInChildLayer(node, target);
637
+ }
638
+ const cleanups = [
639
+ pointerBlocking ? disablePointerEventsOutside(node) : void 0,
640
+ trackEscapeKeydown(onEscapeKeyDown),
641
+ trackInteractOutside(node, { exclude, onFocusOutside, onPointerDownOutside })
642
+ ];
643
+ return () => {
644
+ layerStack.remove(node);
645
+ assignPointerEventToLayers();
646
+ clearPointerEvent(node);
647
+ cleanups.forEach((fn) => fn == null ? void 0 : fn());
648
+ };
649
+ }
650
+
651
+ // src/popover.machine.ts
450
652
  var import_popper2 = require("@zag-js/popper");
451
653
  var import_remove_scroll = require("@zag-js/remove-scroll");
452
654
  var import_focus_trap = require("focus-trap");
453
- var { and, or } = import_core.guards;
655
+ var { and, or, not } = import_core.guards;
454
656
  function machine(ctx = {}) {
455
657
  return (0, import_core.createMachine)({
456
658
  id: "popover",
457
659
  initial: "unknown",
458
660
  context: __spreadProps(__spreadValues({
459
661
  uid: "",
460
- closeOnBlur: true,
662
+ closeOnInteractOutside: true,
461
663
  closeOnEsc: true,
462
664
  autoFocus: true,
463
665
  modal: false,
@@ -466,6 +668,7 @@ function machine(ctx = {}) {
466
668
  }, ctx.positioning),
467
669
  currentPlacement: void 0
468
670
  }, ctx), {
671
+ preventReturnFocus: false,
469
672
  renderedElements: {
470
673
  title: true,
471
674
  description: true,
@@ -487,55 +690,46 @@ function machine(ctx = {}) {
487
690
  closed: {
488
691
  entry: ["clearPointerDown", "invokeOnClose"],
489
692
  on: {
490
- TRIGGER_CLICK: "open",
693
+ TOGGLE: "open",
491
694
  OPEN: "open"
492
695
  }
493
696
  },
494
697
  open: {
495
698
  activities: [
496
- "trackPointerDown",
497
699
  "trapFocus",
498
700
  "preventScroll",
499
701
  "hideContentBelow",
500
- "disableOutsidePointerEvents",
501
- "computePlacement"
702
+ "computePlacement",
703
+ "trackInteractionOutside",
704
+ "trackTabKeyDown"
502
705
  ],
503
706
  entry: ["setInitialFocus", "invokeOnOpen"],
504
707
  on: {
505
- CLOSE: {
506
- target: "closed",
507
- actions: "focusTrigger"
508
- },
509
- TRIGGER_CLICK: {
708
+ CLOSE: "closed",
709
+ REQUEST_CLOSE: {
510
710
  target: "closed",
511
- actions: "focusTrigger"
711
+ actions: "focusTriggerIfNeeded"
512
712
  },
513
- ESCAPE: {
514
- guard: "closeOnEsc",
515
- target: "closed",
516
- actions: "focusTrigger"
517
- },
518
- TAB: {
519
- guard: and("isLastTabbableElement", "closeOnBlur", "portalled"),
520
- target: "closed",
521
- actions: "focusNextTabbableElementAfterTrigger"
522
- },
523
- SHIFT_TAB: {
524
- guard: and(or("isFirstTabbableElement", "isContentFocused"), "closeOnBlur", "portalled"),
525
- target: "closed",
526
- actions: "focusTrigger"
713
+ TOGGLE: "closed",
714
+ TRIGGER_BLUR: {
715
+ guard: not("isRelatedTargetWithinContent"),
716
+ target: "closed"
527
717
  },
528
- INTERACT_OUTSIDE: [
718
+ TAB: [
529
719
  {
530
- guard: and("closeOnBlur", "isRelatedTargetFocusable"),
531
- target: "closed"
720
+ guard: and("isTriggerFocused", "portalled"),
721
+ actions: "focusFirstTabbableElement"
532
722
  },
533
723
  {
534
- guard: "closeOnBlur",
724
+ guard: and("isLastTabbableElement", "closeOnInteractOutside", "portalled"),
535
725
  target: "closed",
536
- actions: "focusTrigger"
726
+ actions: "focusNextTabbableElementAfterTrigger"
537
727
  }
538
- ]
728
+ ],
729
+ SHIFT_TAB: {
730
+ guard: and(or("isFirstTabbableElement", "isContentFocused"), "portalled"),
731
+ actions: "focusTriggerIfNeeded"
732
+ }
539
733
  }
540
734
  }
541
735
  }
@@ -555,32 +749,70 @@ function machine(ctx = {}) {
555
749
  }
556
750
  }));
557
751
  },
558
- trackPointerDown(ctx2) {
559
- return trackPointerDown(dom.getDoc(ctx2), (el) => {
560
- ctx2.pointerdownNode = (0, import_core.ref)(el);
752
+ trackInteractionOutside(ctx2, _evt, { send }) {
753
+ return trackDismissableElement(dom.getContentEl(ctx2), {
754
+ pointerBlocking: ctx2.modal,
755
+ exclude: dom.getTriggerEl(ctx2),
756
+ onEscapeKeyDown(event) {
757
+ var _a;
758
+ (_a = ctx2.onEscapeKeyDown) == null ? void 0 : _a.call(ctx2, event);
759
+ if (ctx2.closeOnEsc)
760
+ return;
761
+ ctx2.preventReturnFocus = false;
762
+ event.preventDefault();
763
+ },
764
+ onInteractOutside(event) {
765
+ var _a;
766
+ (_a = ctx2.onInteractOutside) == null ? void 0 : _a.call(ctx2, event);
767
+ if (event.defaultPrevented)
768
+ return;
769
+ ctx2.preventReturnFocus = event.detail.focusable || event.detail.contextmenu;
770
+ if (!ctx2.closeOnInteractOutside) {
771
+ event.preventDefault();
772
+ }
773
+ },
774
+ onPointerDownOutside(event) {
775
+ var _a;
776
+ (_a = ctx2.onPointerDownOutside) == null ? void 0 : _a.call(ctx2, event);
777
+ },
778
+ onFocusOutside(event) {
779
+ var _a;
780
+ (_a = ctx2.onFocusOutside) == null ? void 0 : _a.call(ctx2, event);
781
+ if (ctx2.currentPortalled) {
782
+ event.preventDefault();
783
+ }
784
+ },
785
+ onDismiss() {
786
+ send({ type: "REQUEST_CLOSE", src: "#interact-outside" });
787
+ }
561
788
  });
562
789
  },
563
- disableOutsidePointerEvents(ctx2) {
564
- const el = dom.getContentEl(ctx2);
565
- return preventBodyPointerEvents(el, {
566
- document: dom.getDoc(ctx2),
567
- disabled: !ctx2.modal
568
- });
790
+ trackTabKeyDown(ctx2, _evt, { send }) {
791
+ if (ctx2.modal)
792
+ return;
793
+ return addDomEvent(dom.getWin(ctx2), "keydown", (event) => {
794
+ const isTabKey = event.key === "Tab" && !isModifiedEvent(event);
795
+ if (!isTabKey)
796
+ return;
797
+ send({
798
+ type: event.shiftKey ? "SHIFT_TAB" : "TAB",
799
+ preventDefault: () => event.preventDefault()
800
+ });
801
+ }, true);
569
802
  },
570
803
  hideContentBelow(ctx2) {
571
804
  if (!ctx2.modal)
572
805
  return;
573
- let unhide;
806
+ let cleanup;
574
807
  nextTick(() => {
575
- unhide = (0, import_aria_hidden.ariaHidden)([dom.getContentEl(ctx2), dom.getTriggerEl(ctx2)]);
808
+ cleanup = (0, import_aria_hidden.ariaHidden)([dom.getContentEl(ctx2), dom.getTriggerEl(ctx2)]);
576
809
  });
577
- return () => unhide == null ? void 0 : unhide();
810
+ return () => cleanup == null ? void 0 : cleanup();
578
811
  },
579
812
  preventScroll(ctx2) {
580
- return (0, import_remove_scroll.preventBodyScroll)({
581
- disabled: !ctx2.modal,
582
- document: dom.getDoc(ctx2)
583
- });
813
+ if (!ctx2.modal)
814
+ return;
815
+ return (0, import_remove_scroll.preventBodyScroll)(dom.getDoc(ctx2));
584
816
  },
585
817
  trapFocus(ctx2) {
586
818
  if (!ctx2.modal)
@@ -607,13 +839,11 @@ function machine(ctx = {}) {
607
839
  }
608
840
  },
609
841
  guards: {
610
- closeOnEsc: (ctx2) => !!ctx2.closeOnEsc,
611
- autoFocus: (ctx2) => !!ctx2.autoFocus,
612
- modal: (ctx2) => !!ctx2.modal,
613
- portalled: (ctx2) => !!ctx2.portalled,
614
- isRelatedTargetFocusable: (_ctx, evt) => evt.focusable,
615
- closeOnBlur: (ctx2) => !!ctx2.closeOnBlur,
842
+ portalled: (ctx2) => ctx2.currentPortalled,
843
+ isRelatedTargetWithinContent: (ctx2, evt) => contains(dom.getContentEl(ctx2), evt.target),
844
+ closeOnInteractOutside: (ctx2) => !!ctx2.closeOnInteractOutside,
616
845
  isContentFocused: (ctx2) => dom.getContentEl(ctx2) === dom.getActiveEl(ctx2),
846
+ isTriggerFocused: (ctx2) => dom.getTriggerEl(ctx2) === dom.getActiveEl(ctx2),
617
847
  isFirstTabbableElement: (ctx2) => dom.getFirstTabbableEl(ctx2) === dom.getActiveEl(ctx2),
618
848
  isLastTabbableElement: (ctx2) => dom.getLastTabbableEl(ctx2) === dom.getActiveEl(ctx2)
619
849
  },
@@ -643,32 +873,42 @@ function machine(ctx = {}) {
643
873
  (_a = dom.getInitialFocusEl(ctx2)) == null ? void 0 : _a.focus();
644
874
  });
645
875
  },
646
- focusTrigger(ctx2) {
647
- raf(() => {
876
+ focusTriggerIfNeeded(ctx2) {
877
+ const focus = () => {
648
878
  var _a;
649
- (_a = dom.getTriggerEl(ctx2)) == null ? void 0 : _a.focus();
879
+ return (_a = dom.getTriggerEl(ctx2)) == null ? void 0 : _a.focus();
880
+ };
881
+ raf(() => {
882
+ if (!ctx2.preventReturnFocus) {
883
+ focus();
884
+ ctx2.preventReturnFocus = false;
885
+ }
650
886
  });
651
887
  },
888
+ focusFirstTabbableElement(ctx2, evt) {
889
+ var _a;
890
+ evt.preventDefault();
891
+ (_a = dom.getFirstTabbableEl(ctx2)) == null ? void 0 : _a.focus();
892
+ },
652
893
  invokeOnOpen(ctx2, evt) {
653
894
  var _a;
654
895
  if (evt.type !== "SETUP") {
655
- (_a = ctx2.onOpen) == null ? void 0 : _a.call(ctx2);
896
+ (_a = ctx2.onOpenChange) == null ? void 0 : _a.call(ctx2, true);
656
897
  }
657
898
  },
658
899
  invokeOnClose(ctx2, evt) {
659
900
  var _a;
660
901
  if (evt.type !== "SETUP") {
661
- (_a = ctx2.onClose) == null ? void 0 : _a.call(ctx2);
902
+ (_a = ctx2.onOpenChange) == null ? void 0 : _a.call(ctx2, false);
662
903
  }
663
904
  },
664
905
  focusNextTabbableElementAfterTrigger(ctx2, evt) {
665
906
  const content = dom.getContentEl(ctx2);
666
- const doc = dom.getDoc(ctx2);
667
907
  const button = dom.getTriggerEl(ctx2);
668
908
  if (!content || !button)
669
909
  return;
670
910
  const lastTabbable = dom.getLastTabbableEl(ctx2);
671
- if (lastTabbable !== doc.activeElement)
911
+ if (lastTabbable !== dom.getActiveEl(ctx2))
672
912
  return;
673
913
  let tabbables = dom.getDocTabbableEls(ctx2);
674
914
  let elementAfterTrigger = next(tabbables, tabbables.indexOf(button), { loop: false });