@zag-js/popover 0.1.15 → 0.2.0

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