@zag-js/popover 0.0.0-dev-20220628115342 → 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,85 +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
172
  // ../../utilities/core/dist/index.mjs
244
- var first = (v) => v[0];
245
- var last = (v) => v[v.length - 1];
246
173
  function nextIndex(v, idx, opts = {}) {
247
174
  const { step = 1, loop = true } = opts;
248
175
  const next2 = idx + step;
@@ -259,11 +186,11 @@ function nextIndex(v, idx, opts = {}) {
259
186
  function next(v, idx, opts = {}) {
260
187
  return v[nextIndex(v, idx, opts)];
261
188
  }
189
+ var isModifiedEvent = (v) => v.ctrlKey || v.altKey || v.metaKey;
262
190
  var runIfFn2 = (v, ...a) => {
263
191
  const res = typeof v === "function" ? v(...a) : v;
264
192
  return res != null ? res : void 0;
265
193
  };
266
- var cast = (v) => v;
267
194
 
268
195
  // src/popover.dom.ts
269
196
  var dom = {
@@ -271,6 +198,10 @@ var dom = {
271
198
  var _a;
272
199
  return (_a = ctx.doc) != null ? _a : document;
273
200
  },
201
+ getWin: (ctx) => {
202
+ var _a;
203
+ return (_a = dom.getDoc(ctx).defaultView) != null ? _a : window;
204
+ },
274
205
  getActiveEl: (ctx) => dom.getDoc(ctx).activeElement,
275
206
  getRootNode: (ctx) => {
276
207
  var _a;
@@ -310,10 +241,10 @@ var dom = {
310
241
  getDescriptionEl: (ctx) => dom.getRootNode(ctx).getElementById(dom.getDescriptionId(ctx)),
311
242
  getFocusableEls: (ctx) => getFocusables(dom.getContentEl(ctx)),
312
243
  getFirstFocusableEl: (ctx) => dom.getFocusableEls(ctx)[0],
313
- getDocTabbableEls: (ctx) => getTabbables(cast(dom.getDoc(ctx))),
244
+ getDocTabbableEls: (ctx) => getTabbables(dom.getDoc(ctx).body),
314
245
  getTabbableEls: (ctx) => getTabbables(dom.getContentEl(ctx), "if-empty"),
315
- getFirstTabbableEl: (ctx) => first(dom.getTabbableEls(ctx)),
316
- getLastTabbableEl: (ctx) => last(dom.getTabbableEls(ctx)),
246
+ getFirstTabbableEl: (ctx) => getFirstTabbable(dom.getContentEl(ctx), "if-empty"),
247
+ getLastTabbableEl: (ctx) => getLastTabbable(dom.getContentEl(ctx), "if-empty"),
317
248
  getInitialFocusEl: (ctx) => {
318
249
  let el = runIfFn2(ctx.initialFocusEl);
319
250
  if (!el && ctx.autoFocus)
@@ -327,14 +258,15 @@ var dom = {
327
258
  // src/popover.connect.ts
328
259
  function connect(state, send, normalize) {
329
260
  const isOpen = state.matches("open");
330
- const pointerdownNode = state.context.pointerdownNode;
331
261
  const currentPlacement = state.context.currentPlacement;
262
+ const portalled = state.context.currentPortalled;
263
+ const rendered = state.context.renderedElements;
332
264
  const popperStyles = (0, import_popper.getPlacementStyles)({
333
265
  measured: !!state.context.isPlacementComplete,
334
266
  placement: currentPlacement
335
267
  });
336
268
  return {
337
- portalled: state.context.currentPortalled,
269
+ portalled,
338
270
  isOpen,
339
271
  open() {
340
272
  send("OPEN");
@@ -365,12 +297,10 @@ function connect(state, send, normalize) {
365
297
  "data-expanded": dataAttr(isOpen),
366
298
  "aria-controls": dom.getContentId(state.context),
367
299
  onClick() {
368
- send("TRIGGER_CLICK");
300
+ send("TOGGLE");
369
301
  },
370
- onKeyDown(event) {
371
- if (event.key === "Escape") {
372
- send("ESCAPE");
373
- }
302
+ onBlur(event) {
303
+ send({ type: "TRIGGER_BLUR", target: event.relatedTarget });
374
304
  }
375
305
  }),
376
306
  positionerProps: normalize.element({
@@ -385,34 +315,9 @@ function connect(state, send, normalize) {
385
315
  role: "dialog",
386
316
  hidden: !isOpen,
387
317
  "data-expanded": dataAttr(isOpen),
388
- "aria-labelledby": state.context.renderedElements.title ? dom.getTitleId(state.context) : void 0,
389
- "aria-describedby": state.context.renderedElements.description ? dom.getDescriptionId(state.context) : void 0,
390
- "data-placement": currentPlacement,
391
- onKeyDown(event) {
392
- const keyMap = {
393
- Escape(event2) {
394
- send("ESCAPE");
395
- event2.stopPropagation();
396
- },
397
- Tab(event2) {
398
- const type = event2.shiftKey ? "SHIFT_TAB" : "TAB";
399
- send({ type, preventDefault: () => event2.preventDefault() });
400
- }
401
- };
402
- const exec = keyMap[event.key];
403
- exec == null ? void 0 : exec(event);
404
- },
405
- onBlur(event) {
406
- var _a;
407
- const isValidBlur = validateBlur(event, {
408
- exclude: [dom.getTriggerEl(state.context), dom.getContentEl(state.context)],
409
- fallback: pointerdownNode
410
- });
411
- if (isValidBlur) {
412
- const el = (_a = event.relatedTarget) != null ? _a : pointerdownNode;
413
- send({ type: "INTERACT_OUTSIDE", focusable: isFocusable(el) });
414
- }
415
- }
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
416
321
  }),
417
322
  titleProps: normalize.element({
418
323
  "data-part": "title",
@@ -428,7 +333,7 @@ function connect(state, send, normalize) {
428
333
  type: "button",
429
334
  "aria-label": "close",
430
335
  onClick() {
431
- send("CLOSE");
336
+ send("REQUEST_CLOSE");
432
337
  }
433
338
  })
434
339
  };
@@ -437,17 +342,324 @@ function connect(state, send, normalize) {
437
342
  // src/popover.machine.ts
438
343
  var import_aria_hidden = require("@zag-js/aria-hidden");
439
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
440
652
  var import_popper2 = require("@zag-js/popper");
441
653
  var import_remove_scroll = require("@zag-js/remove-scroll");
442
654
  var import_focus_trap = require("focus-trap");
443
- var { and, or } = import_core.guards;
655
+ var { and, or, not } = import_core.guards;
444
656
  function machine(ctx = {}) {
445
657
  return (0, import_core.createMachine)({
446
658
  id: "popover",
447
659
  initial: "unknown",
448
660
  context: __spreadProps(__spreadValues({
449
661
  uid: "",
450
- closeOnBlur: true,
662
+ closeOnInteractOutside: true,
451
663
  closeOnEsc: true,
452
664
  autoFocus: true,
453
665
  modal: false,
@@ -456,6 +668,7 @@ function machine(ctx = {}) {
456
668
  }, ctx.positioning),
457
669
  currentPlacement: void 0
458
670
  }, ctx), {
671
+ preventReturnFocus: false,
459
672
  renderedElements: {
460
673
  title: true,
461
674
  description: true,
@@ -477,55 +690,46 @@ function machine(ctx = {}) {
477
690
  closed: {
478
691
  entry: ["clearPointerDown", "invokeOnClose"],
479
692
  on: {
480
- TRIGGER_CLICK: "open",
693
+ TOGGLE: "open",
481
694
  OPEN: "open"
482
695
  }
483
696
  },
484
697
  open: {
485
698
  activities: [
486
- "trackPointerDown",
487
699
  "trapFocus",
488
700
  "preventScroll",
489
701
  "hideContentBelow",
490
- "disableOutsidePointerEvents",
491
- "computePlacement"
702
+ "computePlacement",
703
+ "trackInteractionOutside",
704
+ "trackTabKeyDown"
492
705
  ],
493
706
  entry: ["setInitialFocus", "invokeOnOpen"],
494
707
  on: {
495
- CLOSE: {
708
+ CLOSE: "closed",
709
+ REQUEST_CLOSE: {
496
710
  target: "closed",
497
- actions: "focusTrigger"
711
+ actions: "focusTriggerIfNeeded"
498
712
  },
499
- TRIGGER_CLICK: {
500
- target: "closed",
501
- actions: "focusTrigger"
502
- },
503
- ESCAPE: {
504
- guard: "closeOnEsc",
505
- target: "closed",
506
- actions: "focusTrigger"
507
- },
508
- TAB: {
509
- guard: and("isLastTabbableElement", "closeOnBlur", "portalled"),
510
- target: "closed",
511
- actions: "focusNextTabbableElementAfterTrigger"
512
- },
513
- SHIFT_TAB: {
514
- guard: and(or("isFirstTabbableElement", "isContentFocused"), "closeOnBlur", "portalled"),
515
- target: "closed",
516
- actions: "focusTrigger"
713
+ TOGGLE: "closed",
714
+ TRIGGER_BLUR: {
715
+ guard: not("isRelatedTargetWithinContent"),
716
+ target: "closed"
517
717
  },
518
- INTERACT_OUTSIDE: [
718
+ TAB: [
519
719
  {
520
- guard: and("closeOnBlur", "isRelatedTargetFocusable"),
521
- target: "closed"
720
+ guard: and("isTriggerFocused", "portalled"),
721
+ actions: "focusFirstTabbableElement"
522
722
  },
523
723
  {
524
- guard: "closeOnBlur",
724
+ guard: and("isLastTabbableElement", "closeOnInteractOutside", "portalled"),
525
725
  target: "closed",
526
- actions: "focusTrigger"
726
+ actions: "focusNextTabbableElementAfterTrigger"
527
727
  }
528
- ]
728
+ ],
729
+ SHIFT_TAB: {
730
+ guard: and(or("isFirstTabbableElement", "isContentFocused"), "portalled"),
731
+ actions: "focusTriggerIfNeeded"
732
+ }
529
733
  }
530
734
  }
531
735
  }
@@ -545,32 +749,70 @@ function machine(ctx = {}) {
545
749
  }
546
750
  }));
547
751
  },
548
- trackPointerDown(ctx2) {
549
- return trackPointerDown(dom.getDoc(ctx2), (el) => {
550
- 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
+ }
551
788
  });
552
789
  },
553
- disableOutsidePointerEvents(ctx2) {
554
- const el = dom.getContentEl(ctx2);
555
- return preventBodyPointerEvents(el, {
556
- document: dom.getDoc(ctx2),
557
- disabled: !ctx2.modal
558
- });
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);
559
802
  },
560
803
  hideContentBelow(ctx2) {
561
804
  if (!ctx2.modal)
562
805
  return;
563
- let unhide;
806
+ let cleanup;
564
807
  nextTick(() => {
565
- 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)]);
566
809
  });
567
- return () => unhide == null ? void 0 : unhide();
810
+ return () => cleanup == null ? void 0 : cleanup();
568
811
  },
569
812
  preventScroll(ctx2) {
570
- return (0, import_remove_scroll.preventBodyScroll)({
571
- disabled: !ctx2.modal,
572
- document: dom.getDoc(ctx2)
573
- });
813
+ if (!ctx2.modal)
814
+ return;
815
+ return (0, import_remove_scroll.preventBodyScroll)(dom.getDoc(ctx2));
574
816
  },
575
817
  trapFocus(ctx2) {
576
818
  if (!ctx2.modal)
@@ -597,13 +839,11 @@ function machine(ctx = {}) {
597
839
  }
598
840
  },
599
841
  guards: {
600
- closeOnEsc: (ctx2) => !!ctx2.closeOnEsc,
601
- autoFocus: (ctx2) => !!ctx2.autoFocus,
602
- modal: (ctx2) => !!ctx2.modal,
603
- portalled: (ctx2) => !!ctx2.portalled,
604
- isRelatedTargetFocusable: (_ctx, evt) => evt.focusable,
605
- closeOnBlur: (ctx2) => !!ctx2.closeOnBlur,
842
+ portalled: (ctx2) => ctx2.currentPortalled,
843
+ isRelatedTargetWithinContent: (ctx2, evt) => contains(dom.getContentEl(ctx2), evt.target),
844
+ closeOnInteractOutside: (ctx2) => !!ctx2.closeOnInteractOutside,
606
845
  isContentFocused: (ctx2) => dom.getContentEl(ctx2) === dom.getActiveEl(ctx2),
846
+ isTriggerFocused: (ctx2) => dom.getTriggerEl(ctx2) === dom.getActiveEl(ctx2),
607
847
  isFirstTabbableElement: (ctx2) => dom.getFirstTabbableEl(ctx2) === dom.getActiveEl(ctx2),
608
848
  isLastTabbableElement: (ctx2) => dom.getLastTabbableEl(ctx2) === dom.getActiveEl(ctx2)
609
849
  },
@@ -633,32 +873,42 @@ function machine(ctx = {}) {
633
873
  (_a = dom.getInitialFocusEl(ctx2)) == null ? void 0 : _a.focus();
634
874
  });
635
875
  },
636
- focusTrigger(ctx2) {
637
- raf(() => {
876
+ focusTriggerIfNeeded(ctx2) {
877
+ const focus = () => {
638
878
  var _a;
639
- (_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
+ }
640
886
  });
641
887
  },
888
+ focusFirstTabbableElement(ctx2, evt) {
889
+ var _a;
890
+ evt.preventDefault();
891
+ (_a = dom.getFirstTabbableEl(ctx2)) == null ? void 0 : _a.focus();
892
+ },
642
893
  invokeOnOpen(ctx2, evt) {
643
894
  var _a;
644
895
  if (evt.type !== "SETUP") {
645
- (_a = ctx2.onOpen) == null ? void 0 : _a.call(ctx2);
896
+ (_a = ctx2.onOpenChange) == null ? void 0 : _a.call(ctx2, true);
646
897
  }
647
898
  },
648
899
  invokeOnClose(ctx2, evt) {
649
900
  var _a;
650
901
  if (evt.type !== "SETUP") {
651
- (_a = ctx2.onClose) == null ? void 0 : _a.call(ctx2);
902
+ (_a = ctx2.onOpenChange) == null ? void 0 : _a.call(ctx2, false);
652
903
  }
653
904
  },
654
905
  focusNextTabbableElementAfterTrigger(ctx2, evt) {
655
906
  const content = dom.getContentEl(ctx2);
656
- const doc = dom.getDoc(ctx2);
657
907
  const button = dom.getTriggerEl(ctx2);
658
908
  if (!content || !button)
659
909
  return;
660
910
  const lastTabbable = dom.getLastTabbableEl(ctx2);
661
- if (lastTabbable !== doc.activeElement)
911
+ if (lastTabbable !== dom.getActiveEl(ctx2))
662
912
  return;
663
913
  let tabbables = dom.getDocTabbableEls(ctx2);
664
914
  let elementAfterTrigger = next(tabbables, tabbables.indexOf(button), { loop: false });