@zag-js/popover 0.2.13 → 0.2.15

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.
@@ -4,15 +4,14 @@ import {
4
4
 
5
5
  // src/popover.machine.ts
6
6
  import { ariaHidden } from "@zag-js/aria-hidden";
7
- import { createMachine, guards } from "@zag-js/core";
7
+ import { createMachine } from "@zag-js/core";
8
8
  import { trackDismissableElement } from "@zag-js/dismissable";
9
- import { contains, nextTick, raf } from "@zag-js/dom-query";
10
- import { addDomEvent, isModifiedEvent } from "@zag-js/dom-event";
9
+ import { nextTick, raf } from "@zag-js/dom-query";
11
10
  import { getPlacement } from "@zag-js/popper";
12
11
  import { preventBodyScroll } from "@zag-js/remove-scroll";
13
- import { compact, next, runIfFn } from "@zag-js/utils";
12
+ import { proxyTabFocus } from "@zag-js/tabbable";
13
+ import { compact, runIfFn } from "@zag-js/utils";
14
14
  import { createFocusTrap } from "focus-trap";
15
- var { and, or, not } = guards;
16
15
  function machine(userContext) {
17
16
  const ctx = compact(userContext);
18
17
  return createMachine(
@@ -33,8 +32,7 @@ function machine(userContext) {
33
32
  focusTriggerOnClose: true,
34
33
  renderedElements: {
35
34
  title: true,
36
- description: true,
37
- anchor: false
35
+ description: true
38
36
  }
39
37
  },
40
38
  computed: {
@@ -54,9 +52,9 @@ function machine(userContext) {
54
52
  "trapFocus",
55
53
  "preventScroll",
56
54
  "hideContentBelow",
57
- "computePlacement",
58
- "trackInteractionOutside",
59
- "trackTabKeyDown"
55
+ "trackPositioning",
56
+ "trackDismissableElement",
57
+ "proxyTabFocus"
60
58
  ],
61
59
  entry: ["setInitialFocus", "invokeOnOpen"],
62
60
  on: {
@@ -66,24 +64,8 @@ function machine(userContext) {
66
64
  actions: "focusTriggerIfNeeded"
67
65
  },
68
66
  TOGGLE: "closed",
69
- TRIGGER_BLUR: {
70
- guard: not("isRelatedTargetWithinContent"),
71
- target: "closed"
72
- },
73
- TAB: [
74
- {
75
- guard: and("isTriggerFocused", "portalled"),
76
- actions: "focusFirstTabbableElement"
77
- },
78
- {
79
- guard: and("isLastTabbableElement", "closeOnInteractOutside", "portalled"),
80
- target: "closed",
81
- actions: "focusNextTabbableElementAfterTrigger"
82
- }
83
- ],
84
- SHIFT_TAB: {
85
- guard: and(or("isFirstTabbableElement", "isContentFocused"), "portalled"),
86
- actions: "focusTriggerIfNeeded"
67
+ SET_POSITIONING: {
68
+ actions: "setPositioning"
87
69
  }
88
70
  }
89
71
  }
@@ -91,22 +73,20 @@ function machine(userContext) {
91
73
  },
92
74
  {
93
75
  activities: {
94
- computePlacement(ctx2) {
76
+ trackPositioning(ctx2) {
95
77
  ctx2.currentPlacement = ctx2.positioning.placement;
96
- const anchorEl = ctx2.renderedElements.anchor ? dom.getAnchorEl(ctx2) : dom.getTriggerEl(ctx2);
78
+ const anchorEl = dom.getAnchorEl(ctx2) ?? dom.getTriggerEl(ctx2);
97
79
  return getPlacement(anchorEl, dom.getPositionerEl(ctx2), {
98
80
  ...ctx2.positioning,
99
81
  onComplete(data) {
100
82
  ctx2.currentPlacement = data.placement;
101
- ctx2.isPlacementComplete = true;
102
83
  },
103
84
  onCleanup() {
104
85
  ctx2.currentPlacement = void 0;
105
- ctx2.isPlacementComplete = false;
106
86
  }
107
87
  });
108
88
  },
109
- trackInteractionOutside(ctx2, _evt, { send }) {
89
+ trackDismissableElement(ctx2, _evt, { send }) {
110
90
  return trackDismissableElement(dom.getContentEl(ctx2), {
111
91
  pointerBlocking: ctx2.modal,
112
92
  exclude: dom.getTriggerEl(ctx2),
@@ -131,32 +111,18 @@ function machine(userContext) {
131
111
  },
132
112
  onFocusOutside(event) {
133
113
  ctx2.onFocusOutside?.(event);
134
- if (ctx2.currentPortalled) {
135
- event.preventDefault();
136
- }
137
114
  },
138
115
  onDismiss() {
139
116
  send({ type: "REQUEST_CLOSE", src: "#interact-outside" });
140
117
  }
141
118
  });
142
119
  },
143
- trackTabKeyDown(ctx2, _evt, { send }) {
144
- if (ctx2.modal)
120
+ proxyTabFocus(ctx2) {
121
+ if (ctx2.modal || !ctx2.portalled)
145
122
  return;
146
- return addDomEvent(
147
- dom.getWin(ctx2),
148
- "keydown",
149
- (event) => {
150
- const isTabKey = event.key === "Tab" && !isModifiedEvent(event);
151
- if (!isTabKey)
152
- return;
153
- send({
154
- type: event.shiftKey ? "SHIFT_TAB" : "TAB",
155
- preventDefault: () => event.preventDefault()
156
- });
157
- },
158
- true
159
- );
123
+ return proxyTabFocus(dom.getContentEl(ctx2), dom.getTriggerEl(ctx2), (el) => {
124
+ el.focus({ preventScroll: true });
125
+ });
160
126
  },
161
127
  hideContentBelow(ctx2) {
162
128
  if (!ctx2.modal)
@@ -196,22 +162,22 @@ function machine(userContext) {
196
162
  return () => trap?.deactivate();
197
163
  }
198
164
  },
199
- guards: {
200
- portalled: (ctx2) => ctx2.currentPortalled,
201
- isRelatedTargetWithinContent: (ctx2, evt) => contains(dom.getContentEl(ctx2), evt.target),
202
- closeOnInteractOutside: (ctx2) => !!ctx2.closeOnInteractOutside,
203
- isContentFocused: (ctx2) => dom.getContentEl(ctx2) === dom.getActiveEl(ctx2),
204
- isTriggerFocused: (ctx2) => dom.getTriggerEl(ctx2) === dom.getActiveEl(ctx2),
205
- isFirstTabbableElement: (ctx2) => dom.getFirstTabbableEl(ctx2) === dom.getActiveEl(ctx2),
206
- isLastTabbableElement: (ctx2) => dom.getLastTabbableEl(ctx2) === dom.getActiveEl(ctx2)
207
- },
208
165
  actions: {
166
+ setPositioning(ctx2, evt) {
167
+ raf(() => {
168
+ const anchorEl = dom.getAnchorEl(ctx2) ?? dom.getTriggerEl(ctx2);
169
+ getPlacement(anchorEl, dom.getPositionerEl(ctx2), {
170
+ ...ctx2.positioning,
171
+ ...evt.options,
172
+ listeners: false
173
+ });
174
+ });
175
+ },
209
176
  checkRenderedElements(ctx2) {
210
177
  raf(() => {
211
178
  Object.assign(ctx2.renderedElements, {
212
179
  title: !!dom.getTitleEl(ctx2),
213
- description: !!dom.getDescriptionEl(ctx2),
214
- anchor: !!dom.getAnchorEl(ctx2)
180
+ description: !!dom.getDescriptionEl(ctx2)
215
181
  });
216
182
  });
217
183
  },
@@ -225,38 +191,11 @@ function machine(userContext) {
225
191
  return;
226
192
  raf(() => dom.getTriggerEl(ctx2)?.focus());
227
193
  },
228
- focusFirstTabbableElement(ctx2, evt) {
229
- evt.preventDefault();
230
- dom.getFirstTabbableEl(ctx2)?.focus();
231
- },
232
- invokeOnOpen(ctx2, evt) {
233
- if (evt.type !== "SETUP") {
234
- ctx2.onOpenChange?.(true);
235
- }
236
- },
237
- invokeOnClose(ctx2, evt) {
238
- if (evt.type !== "SETUP") {
239
- ctx2.onOpenChange?.(false);
240
- }
194
+ invokeOnOpen(ctx2) {
195
+ ctx2.onOpenChange?.(true);
241
196
  },
242
- focusNextTabbableElementAfterTrigger(ctx2, evt) {
243
- const content = dom.getContentEl(ctx2);
244
- const button = dom.getTriggerEl(ctx2);
245
- if (!content || !button)
246
- return;
247
- const lastTabbable = dom.getLastTabbableEl(ctx2);
248
- if (lastTabbable !== dom.getActiveEl(ctx2))
249
- return;
250
- let tabbables = dom.getDocTabbableEls(ctx2);
251
- let elementAfterTrigger = next(tabbables, tabbables.indexOf(button), { loop: false });
252
- if (elementAfterTrigger === content) {
253
- tabbables = tabbables.filter((el) => !contains(content, el));
254
- elementAfterTrigger = next(tabbables, tabbables.indexOf(button), { loop: false });
255
- }
256
- if (!elementAfterTrigger || elementAfterTrigger === button)
257
- return;
258
- evt.preventDefault();
259
- raf(() => elementAfterTrigger?.focus());
197
+ invokeOnClose(ctx2) {
198
+ ctx2.onOpenChange?.(false);
260
199
  }
261
200
  }
262
201
  }
@@ -14,7 +14,6 @@ function connect(state, send, normalize) {
14
14
  const portalled = state.context.currentPortalled;
15
15
  const rendered = state.context.renderedElements;
16
16
  const popperStyles = getPlacementStyles({
17
- measured: !!state.context.isPlacementComplete,
18
17
  placement: currentPlacement
19
18
  });
20
19
  return {
@@ -38,6 +37,12 @@ function connect(state, send, normalize) {
38
37
  close() {
39
38
  send("CLOSE");
40
39
  },
40
+ /**
41
+ * Function to reposition the popover
42
+ */
43
+ setPositioning(options) {
44
+ send({ type: "SET_POSITIONING", options });
45
+ },
41
46
  arrowProps: normalize.element({
42
47
  id: dom.getArrowId(state.context),
43
48
  ...parts.arrow.attrs,
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { connect } from './popover.connect.js';
3
3
  export { machine } from './popover.machine.js';
4
4
  export { UserDefinedContext as Context } from './popover.types.js';
5
5
  import '@zag-js/anatomy';
6
+ import '@zag-js/popper';
6
7
  import '@zag-js/types';
7
8
  import '@zag-js/core';
8
9
  import '@zag-js/dismissable';
9
- import '@zag-js/popper';
package/dist/index.js CHANGED
@@ -88,7 +88,6 @@ function connect(state, send, normalize) {
88
88
  const portalled = state.context.currentPortalled;
89
89
  const rendered = state.context.renderedElements;
90
90
  const popperStyles = (0, import_popper.getPlacementStyles)({
91
- measured: !!state.context.isPlacementComplete,
92
91
  placement: currentPlacement
93
92
  });
94
93
  return {
@@ -112,6 +111,12 @@ function connect(state, send, normalize) {
112
111
  close() {
113
112
  send("CLOSE");
114
113
  },
114
+ /**
115
+ * Function to reposition the popover
116
+ */
117
+ setPositioning(options) {
118
+ send({ type: "SET_POSITIONING", options });
119
+ },
115
120
  arrowProps: normalize.element({
116
121
  id: dom.getArrowId(state.context),
117
122
  ...parts.arrow.attrs,
@@ -182,12 +187,11 @@ var import_aria_hidden = require("@zag-js/aria-hidden");
182
187
  var import_core = require("@zag-js/core");
183
188
  var import_dismissable = require("@zag-js/dismissable");
184
189
  var import_dom_query3 = require("@zag-js/dom-query");
185
- var import_dom_event = require("@zag-js/dom-event");
186
190
  var import_popper2 = require("@zag-js/popper");
187
191
  var import_remove_scroll = require("@zag-js/remove-scroll");
192
+ var import_tabbable2 = require("@zag-js/tabbable");
188
193
  var import_utils2 = require("@zag-js/utils");
189
194
  var import_focus_trap = require("focus-trap");
190
- var { and, or, not } = import_core.guards;
191
195
  function machine(userContext) {
192
196
  const ctx = (0, import_utils2.compact)(userContext);
193
197
  return (0, import_core.createMachine)(
@@ -208,8 +212,7 @@ function machine(userContext) {
208
212
  focusTriggerOnClose: true,
209
213
  renderedElements: {
210
214
  title: true,
211
- description: true,
212
- anchor: false
215
+ description: true
213
216
  }
214
217
  },
215
218
  computed: {
@@ -229,9 +232,9 @@ function machine(userContext) {
229
232
  "trapFocus",
230
233
  "preventScroll",
231
234
  "hideContentBelow",
232
- "computePlacement",
233
- "trackInteractionOutside",
234
- "trackTabKeyDown"
235
+ "trackPositioning",
236
+ "trackDismissableElement",
237
+ "proxyTabFocus"
235
238
  ],
236
239
  entry: ["setInitialFocus", "invokeOnOpen"],
237
240
  on: {
@@ -241,24 +244,8 @@ function machine(userContext) {
241
244
  actions: "focusTriggerIfNeeded"
242
245
  },
243
246
  TOGGLE: "closed",
244
- TRIGGER_BLUR: {
245
- guard: not("isRelatedTargetWithinContent"),
246
- target: "closed"
247
- },
248
- TAB: [
249
- {
250
- guard: and("isTriggerFocused", "portalled"),
251
- actions: "focusFirstTabbableElement"
252
- },
253
- {
254
- guard: and("isLastTabbableElement", "closeOnInteractOutside", "portalled"),
255
- target: "closed",
256
- actions: "focusNextTabbableElementAfterTrigger"
257
- }
258
- ],
259
- SHIFT_TAB: {
260
- guard: and(or("isFirstTabbableElement", "isContentFocused"), "portalled"),
261
- actions: "focusTriggerIfNeeded"
247
+ SET_POSITIONING: {
248
+ actions: "setPositioning"
262
249
  }
263
250
  }
264
251
  }
@@ -266,22 +253,20 @@ function machine(userContext) {
266
253
  },
267
254
  {
268
255
  activities: {
269
- computePlacement(ctx2) {
256
+ trackPositioning(ctx2) {
270
257
  ctx2.currentPlacement = ctx2.positioning.placement;
271
- const anchorEl = ctx2.renderedElements.anchor ? dom.getAnchorEl(ctx2) : dom.getTriggerEl(ctx2);
258
+ const anchorEl = dom.getAnchorEl(ctx2) ?? dom.getTriggerEl(ctx2);
272
259
  return (0, import_popper2.getPlacement)(anchorEl, dom.getPositionerEl(ctx2), {
273
260
  ...ctx2.positioning,
274
261
  onComplete(data) {
275
262
  ctx2.currentPlacement = data.placement;
276
- ctx2.isPlacementComplete = true;
277
263
  },
278
264
  onCleanup() {
279
265
  ctx2.currentPlacement = void 0;
280
- ctx2.isPlacementComplete = false;
281
266
  }
282
267
  });
283
268
  },
284
- trackInteractionOutside(ctx2, _evt, { send }) {
269
+ trackDismissableElement(ctx2, _evt, { send }) {
285
270
  return (0, import_dismissable.trackDismissableElement)(dom.getContentEl(ctx2), {
286
271
  pointerBlocking: ctx2.modal,
287
272
  exclude: dom.getTriggerEl(ctx2),
@@ -306,32 +291,18 @@ function machine(userContext) {
306
291
  },
307
292
  onFocusOutside(event) {
308
293
  ctx2.onFocusOutside?.(event);
309
- if (ctx2.currentPortalled) {
310
- event.preventDefault();
311
- }
312
294
  },
313
295
  onDismiss() {
314
296
  send({ type: "REQUEST_CLOSE", src: "#interact-outside" });
315
297
  }
316
298
  });
317
299
  },
318
- trackTabKeyDown(ctx2, _evt, { send }) {
319
- if (ctx2.modal)
300
+ proxyTabFocus(ctx2) {
301
+ if (ctx2.modal || !ctx2.portalled)
320
302
  return;
321
- return (0, import_dom_event.addDomEvent)(
322
- dom.getWin(ctx2),
323
- "keydown",
324
- (event) => {
325
- const isTabKey = event.key === "Tab" && !(0, import_dom_event.isModifiedEvent)(event);
326
- if (!isTabKey)
327
- return;
328
- send({
329
- type: event.shiftKey ? "SHIFT_TAB" : "TAB",
330
- preventDefault: () => event.preventDefault()
331
- });
332
- },
333
- true
334
- );
303
+ return (0, import_tabbable2.proxyTabFocus)(dom.getContentEl(ctx2), dom.getTriggerEl(ctx2), (el) => {
304
+ el.focus({ preventScroll: true });
305
+ });
335
306
  },
336
307
  hideContentBelow(ctx2) {
337
308
  if (!ctx2.modal)
@@ -371,22 +342,22 @@ function machine(userContext) {
371
342
  return () => trap?.deactivate();
372
343
  }
373
344
  },
374
- guards: {
375
- portalled: (ctx2) => ctx2.currentPortalled,
376
- isRelatedTargetWithinContent: (ctx2, evt) => (0, import_dom_query3.contains)(dom.getContentEl(ctx2), evt.target),
377
- closeOnInteractOutside: (ctx2) => !!ctx2.closeOnInteractOutside,
378
- isContentFocused: (ctx2) => dom.getContentEl(ctx2) === dom.getActiveEl(ctx2),
379
- isTriggerFocused: (ctx2) => dom.getTriggerEl(ctx2) === dom.getActiveEl(ctx2),
380
- isFirstTabbableElement: (ctx2) => dom.getFirstTabbableEl(ctx2) === dom.getActiveEl(ctx2),
381
- isLastTabbableElement: (ctx2) => dom.getLastTabbableEl(ctx2) === dom.getActiveEl(ctx2)
382
- },
383
345
  actions: {
346
+ setPositioning(ctx2, evt) {
347
+ (0, import_dom_query3.raf)(() => {
348
+ const anchorEl = dom.getAnchorEl(ctx2) ?? dom.getTriggerEl(ctx2);
349
+ (0, import_popper2.getPlacement)(anchorEl, dom.getPositionerEl(ctx2), {
350
+ ...ctx2.positioning,
351
+ ...evt.options,
352
+ listeners: false
353
+ });
354
+ });
355
+ },
384
356
  checkRenderedElements(ctx2) {
385
357
  (0, import_dom_query3.raf)(() => {
386
358
  Object.assign(ctx2.renderedElements, {
387
359
  title: !!dom.getTitleEl(ctx2),
388
- description: !!dom.getDescriptionEl(ctx2),
389
- anchor: !!dom.getAnchorEl(ctx2)
360
+ description: !!dom.getDescriptionEl(ctx2)
390
361
  });
391
362
  });
392
363
  },
@@ -400,38 +371,11 @@ function machine(userContext) {
400
371
  return;
401
372
  (0, import_dom_query3.raf)(() => dom.getTriggerEl(ctx2)?.focus());
402
373
  },
403
- focusFirstTabbableElement(ctx2, evt) {
404
- evt.preventDefault();
405
- dom.getFirstTabbableEl(ctx2)?.focus();
406
- },
407
- invokeOnOpen(ctx2, evt) {
408
- if (evt.type !== "SETUP") {
409
- ctx2.onOpenChange?.(true);
410
- }
411
- },
412
- invokeOnClose(ctx2, evt) {
413
- if (evt.type !== "SETUP") {
414
- ctx2.onOpenChange?.(false);
415
- }
374
+ invokeOnOpen(ctx2) {
375
+ ctx2.onOpenChange?.(true);
416
376
  },
417
- focusNextTabbableElementAfterTrigger(ctx2, evt) {
418
- const content = dom.getContentEl(ctx2);
419
- const button = dom.getTriggerEl(ctx2);
420
- if (!content || !button)
421
- return;
422
- const lastTabbable = dom.getLastTabbableEl(ctx2);
423
- if (lastTabbable !== dom.getActiveEl(ctx2))
424
- return;
425
- let tabbables = dom.getDocTabbableEls(ctx2);
426
- let elementAfterTrigger = (0, import_utils2.next)(tabbables, tabbables.indexOf(button), { loop: false });
427
- if (elementAfterTrigger === content) {
428
- tabbables = tabbables.filter((el) => !(0, import_dom_query3.contains)(content, el));
429
- elementAfterTrigger = (0, import_utils2.next)(tabbables, tabbables.indexOf(button), { loop: false });
430
- }
431
- if (!elementAfterTrigger || elementAfterTrigger === button)
432
- return;
433
- evt.preventDefault();
434
- (0, import_dom_query3.raf)(() => elementAfterTrigger?.focus());
377
+ invokeOnClose(ctx2) {
378
+ ctx2.onOpenChange?.(false);
435
379
  }
436
380
  }
437
381
  }
package/dist/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  connect
3
- } from "./chunk-GKHXQZZB.mjs";
3
+ } from "./chunk-QLF6NDJW.mjs";
4
4
  import {
5
5
  anatomy
6
6
  } from "./chunk-KTOPDXGV.mjs";
7
7
  import {
8
8
  machine
9
- } from "./chunk-JT2RXXW4.mjs";
9
+ } from "./chunk-NPQGVKMX.mjs";
10
10
  import "./chunk-4IGGT6KB.mjs";
11
11
  export {
12
12
  anatomy,
@@ -1,8 +1,8 @@
1
+ import { PositioningOptions } from '@zag-js/popper';
1
2
  import { PropTypes, NormalizeProps } from '@zag-js/types';
2
3
  import { State, Send } from './popover.types.js';
3
4
  import '@zag-js/core';
4
5
  import '@zag-js/dismissable';
5
- import '@zag-js/popper';
6
6
 
7
7
  declare function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): {
8
8
  /**
@@ -21,6 +21,10 @@ declare function connect<T extends PropTypes>(state: State, send: Send, normaliz
21
21
  * Function to close the popover
22
22
  */
23
23
  close(): void;
24
+ /**
25
+ * Function to reposition the popover
26
+ */
27
+ setPositioning(options: Partial<PositioningOptions>): void;
24
28
  arrowProps: T["element"];
25
29
  arrowTipProps: T["element"];
26
30
  anchorProps: T["element"];
@@ -84,7 +84,6 @@ function connect(state, send, normalize) {
84
84
  const portalled = state.context.currentPortalled;
85
85
  const rendered = state.context.renderedElements;
86
86
  const popperStyles = (0, import_popper.getPlacementStyles)({
87
- measured: !!state.context.isPlacementComplete,
88
87
  placement: currentPlacement
89
88
  });
90
89
  return {
@@ -108,6 +107,12 @@ function connect(state, send, normalize) {
108
107
  close() {
109
108
  send("CLOSE");
110
109
  },
110
+ /**
111
+ * Function to reposition the popover
112
+ */
113
+ setPositioning(options) {
114
+ send({ type: "SET_POSITIONING", options });
115
+ },
111
116
  arrowProps: normalize.element({
112
117
  id: dom.getArrowId(state.context),
113
118
  ...parts.arrow.attrs,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  connect
3
- } from "./chunk-GKHXQZZB.mjs";
3
+ } from "./chunk-QLF6NDJW.mjs";
4
4
  import "./chunk-KTOPDXGV.mjs";
5
5
  import "./chunk-4IGGT6KB.mjs";
6
6
  export {
@@ -27,9 +27,9 @@ var import_aria_hidden = require("@zag-js/aria-hidden");
27
27
  var import_core = require("@zag-js/core");
28
28
  var import_dismissable = require("@zag-js/dismissable");
29
29
  var import_dom_query2 = require("@zag-js/dom-query");
30
- var import_dom_event = require("@zag-js/dom-event");
31
30
  var import_popper = require("@zag-js/popper");
32
31
  var import_remove_scroll = require("@zag-js/remove-scroll");
32
+ var import_tabbable2 = require("@zag-js/tabbable");
33
33
  var import_utils2 = require("@zag-js/utils");
34
34
  var import_focus_trap = require("focus-trap");
35
35
 
@@ -70,7 +70,6 @@ var dom = (0, import_dom_query.createScope)({
70
70
  });
71
71
 
72
72
  // src/popover.machine.ts
73
- var { and, or, not } = import_core.guards;
74
73
  function machine(userContext) {
75
74
  const ctx = (0, import_utils2.compact)(userContext);
76
75
  return (0, import_core.createMachine)(
@@ -91,8 +90,7 @@ function machine(userContext) {
91
90
  focusTriggerOnClose: true,
92
91
  renderedElements: {
93
92
  title: true,
94
- description: true,
95
- anchor: false
93
+ description: true
96
94
  }
97
95
  },
98
96
  computed: {
@@ -112,9 +110,9 @@ function machine(userContext) {
112
110
  "trapFocus",
113
111
  "preventScroll",
114
112
  "hideContentBelow",
115
- "computePlacement",
116
- "trackInteractionOutside",
117
- "trackTabKeyDown"
113
+ "trackPositioning",
114
+ "trackDismissableElement",
115
+ "proxyTabFocus"
118
116
  ],
119
117
  entry: ["setInitialFocus", "invokeOnOpen"],
120
118
  on: {
@@ -124,24 +122,8 @@ function machine(userContext) {
124
122
  actions: "focusTriggerIfNeeded"
125
123
  },
126
124
  TOGGLE: "closed",
127
- TRIGGER_BLUR: {
128
- guard: not("isRelatedTargetWithinContent"),
129
- target: "closed"
130
- },
131
- TAB: [
132
- {
133
- guard: and("isTriggerFocused", "portalled"),
134
- actions: "focusFirstTabbableElement"
135
- },
136
- {
137
- guard: and("isLastTabbableElement", "closeOnInteractOutside", "portalled"),
138
- target: "closed",
139
- actions: "focusNextTabbableElementAfterTrigger"
140
- }
141
- ],
142
- SHIFT_TAB: {
143
- guard: and(or("isFirstTabbableElement", "isContentFocused"), "portalled"),
144
- actions: "focusTriggerIfNeeded"
125
+ SET_POSITIONING: {
126
+ actions: "setPositioning"
145
127
  }
146
128
  }
147
129
  }
@@ -149,22 +131,20 @@ function machine(userContext) {
149
131
  },
150
132
  {
151
133
  activities: {
152
- computePlacement(ctx2) {
134
+ trackPositioning(ctx2) {
153
135
  ctx2.currentPlacement = ctx2.positioning.placement;
154
- const anchorEl = ctx2.renderedElements.anchor ? dom.getAnchorEl(ctx2) : dom.getTriggerEl(ctx2);
136
+ const anchorEl = dom.getAnchorEl(ctx2) ?? dom.getTriggerEl(ctx2);
155
137
  return (0, import_popper.getPlacement)(anchorEl, dom.getPositionerEl(ctx2), {
156
138
  ...ctx2.positioning,
157
139
  onComplete(data) {
158
140
  ctx2.currentPlacement = data.placement;
159
- ctx2.isPlacementComplete = true;
160
141
  },
161
142
  onCleanup() {
162
143
  ctx2.currentPlacement = void 0;
163
- ctx2.isPlacementComplete = false;
164
144
  }
165
145
  });
166
146
  },
167
- trackInteractionOutside(ctx2, _evt, { send }) {
147
+ trackDismissableElement(ctx2, _evt, { send }) {
168
148
  return (0, import_dismissable.trackDismissableElement)(dom.getContentEl(ctx2), {
169
149
  pointerBlocking: ctx2.modal,
170
150
  exclude: dom.getTriggerEl(ctx2),
@@ -189,32 +169,18 @@ function machine(userContext) {
189
169
  },
190
170
  onFocusOutside(event) {
191
171
  ctx2.onFocusOutside?.(event);
192
- if (ctx2.currentPortalled) {
193
- event.preventDefault();
194
- }
195
172
  },
196
173
  onDismiss() {
197
174
  send({ type: "REQUEST_CLOSE", src: "#interact-outside" });
198
175
  }
199
176
  });
200
177
  },
201
- trackTabKeyDown(ctx2, _evt, { send }) {
202
- if (ctx2.modal)
178
+ proxyTabFocus(ctx2) {
179
+ if (ctx2.modal || !ctx2.portalled)
203
180
  return;
204
- return (0, import_dom_event.addDomEvent)(
205
- dom.getWin(ctx2),
206
- "keydown",
207
- (event) => {
208
- const isTabKey = event.key === "Tab" && !(0, import_dom_event.isModifiedEvent)(event);
209
- if (!isTabKey)
210
- return;
211
- send({
212
- type: event.shiftKey ? "SHIFT_TAB" : "TAB",
213
- preventDefault: () => event.preventDefault()
214
- });
215
- },
216
- true
217
- );
181
+ return (0, import_tabbable2.proxyTabFocus)(dom.getContentEl(ctx2), dom.getTriggerEl(ctx2), (el) => {
182
+ el.focus({ preventScroll: true });
183
+ });
218
184
  },
219
185
  hideContentBelow(ctx2) {
220
186
  if (!ctx2.modal)
@@ -254,22 +220,22 @@ function machine(userContext) {
254
220
  return () => trap?.deactivate();
255
221
  }
256
222
  },
257
- guards: {
258
- portalled: (ctx2) => ctx2.currentPortalled,
259
- isRelatedTargetWithinContent: (ctx2, evt) => (0, import_dom_query2.contains)(dom.getContentEl(ctx2), evt.target),
260
- closeOnInteractOutside: (ctx2) => !!ctx2.closeOnInteractOutside,
261
- isContentFocused: (ctx2) => dom.getContentEl(ctx2) === dom.getActiveEl(ctx2),
262
- isTriggerFocused: (ctx2) => dom.getTriggerEl(ctx2) === dom.getActiveEl(ctx2),
263
- isFirstTabbableElement: (ctx2) => dom.getFirstTabbableEl(ctx2) === dom.getActiveEl(ctx2),
264
- isLastTabbableElement: (ctx2) => dom.getLastTabbableEl(ctx2) === dom.getActiveEl(ctx2)
265
- },
266
223
  actions: {
224
+ setPositioning(ctx2, evt) {
225
+ (0, import_dom_query2.raf)(() => {
226
+ const anchorEl = dom.getAnchorEl(ctx2) ?? dom.getTriggerEl(ctx2);
227
+ (0, import_popper.getPlacement)(anchorEl, dom.getPositionerEl(ctx2), {
228
+ ...ctx2.positioning,
229
+ ...evt.options,
230
+ listeners: false
231
+ });
232
+ });
233
+ },
267
234
  checkRenderedElements(ctx2) {
268
235
  (0, import_dom_query2.raf)(() => {
269
236
  Object.assign(ctx2.renderedElements, {
270
237
  title: !!dom.getTitleEl(ctx2),
271
- description: !!dom.getDescriptionEl(ctx2),
272
- anchor: !!dom.getAnchorEl(ctx2)
238
+ description: !!dom.getDescriptionEl(ctx2)
273
239
  });
274
240
  });
275
241
  },
@@ -283,38 +249,11 @@ function machine(userContext) {
283
249
  return;
284
250
  (0, import_dom_query2.raf)(() => dom.getTriggerEl(ctx2)?.focus());
285
251
  },
286
- focusFirstTabbableElement(ctx2, evt) {
287
- evt.preventDefault();
288
- dom.getFirstTabbableEl(ctx2)?.focus();
289
- },
290
- invokeOnOpen(ctx2, evt) {
291
- if (evt.type !== "SETUP") {
292
- ctx2.onOpenChange?.(true);
293
- }
294
- },
295
- invokeOnClose(ctx2, evt) {
296
- if (evt.type !== "SETUP") {
297
- ctx2.onOpenChange?.(false);
298
- }
252
+ invokeOnOpen(ctx2) {
253
+ ctx2.onOpenChange?.(true);
299
254
  },
300
- focusNextTabbableElementAfterTrigger(ctx2, evt) {
301
- const content = dom.getContentEl(ctx2);
302
- const button = dom.getTriggerEl(ctx2);
303
- if (!content || !button)
304
- return;
305
- const lastTabbable = dom.getLastTabbableEl(ctx2);
306
- if (lastTabbable !== dom.getActiveEl(ctx2))
307
- return;
308
- let tabbables = dom.getDocTabbableEls(ctx2);
309
- let elementAfterTrigger = (0, import_utils2.next)(tabbables, tabbables.indexOf(button), { loop: false });
310
- if (elementAfterTrigger === content) {
311
- tabbables = tabbables.filter((el) => !(0, import_dom_query2.contains)(content, el));
312
- elementAfterTrigger = (0, import_utils2.next)(tabbables, tabbables.indexOf(button), { loop: false });
313
- }
314
- if (!elementAfterTrigger || elementAfterTrigger === button)
315
- return;
316
- evt.preventDefault();
317
- (0, import_dom_query2.raf)(() => elementAfterTrigger?.focus());
255
+ invokeOnClose(ctx2) {
256
+ ctx2.onOpenChange?.(false);
318
257
  }
319
258
  }
320
259
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  machine
3
- } from "./chunk-JT2RXXW4.mjs";
3
+ } from "./chunk-NPQGVKMX.mjs";
4
4
  import "./chunk-4IGGT6KB.mjs";
5
5
  export {
6
6
  machine
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/popover",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "Core logic for the popover widget implemented as a state machine",
5
5
  "keywords": [
6
6
  "js",
@@ -26,17 +26,16 @@
26
26
  "url": "https://github.com/chakra-ui/zag/issues"
27
27
  },
28
28
  "dependencies": {
29
- "focus-trap": "7.3.1",
29
+ "focus-trap": "7.4.0",
30
30
  "@zag-js/anatomy": "0.1.4",
31
31
  "@zag-js/aria-hidden": "0.2.2",
32
- "@zag-js/core": "0.2.10",
32
+ "@zag-js/core": "0.2.12",
33
33
  "@zag-js/dom-query": "0.1.4",
34
- "@zag-js/dom-event": "0.0.1",
35
- "@zag-js/utils": "0.3.3",
36
- "@zag-js/dismissable": "0.2.4",
37
- "@zag-js/tabbable": "0.0.1",
38
- "@zag-js/popper": "0.2.5",
34
+ "@zag-js/utils": "0.3.4",
35
+ "@zag-js/dismissable": "0.2.6",
36
+ "@zag-js/popper": "0.2.7",
39
37
  "@zag-js/remove-scroll": "0.2.4",
38
+ "@zag-js/tabbable": "0.1.1",
40
39
  "@zag-js/types": "0.3.4"
41
40
  },
42
41
  "devDependencies": {