@zag-js/popover 2.0.0-next.1 → 2.0.0-next.3

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.
@@ -36,12 +36,16 @@ module.exports = __toCommonJS(popover_connect_exports);
36
36
  var import_dismissable = require("@zag-js/dismissable");
37
37
  var import_dom_query = require("@zag-js/dom-query");
38
38
  var import_popper = require("@zag-js/popper");
39
+ var import_utils = require("@zag-js/utils");
39
40
  var import_popover = require("./popover.anatomy.js");
40
41
  var dom = __toESM(require("./popover.dom.js"));
42
+ var defaultTranslations = {
43
+ closeTriggerLabel: "close"
44
+ };
41
45
  function connect(service, normalize) {
42
46
  const { state, context, send, prop, scope } = service;
43
47
  const layer = context.get("layer");
44
- const translations = prop("translations");
48
+ const translations = (0, import_utils.mergeWithDefault)(defaultTranslations, prop("translations"));
45
49
  const open = state.matches("open");
46
50
  const currentPlacement = context.get("currentPlacement");
47
51
  const currentPlacementSide = currentPlacement ? (0, import_popper.getPlacementSide)(currentPlacement) : void 0;
@@ -72,9 +76,7 @@ function connect(service, normalize) {
72
76
  return {
73
77
  open,
74
78
  setOpen(nextOpen) {
75
- const open2 = state.matches("open");
76
- if (open2 === nextOpen) return;
77
- send({ type: nextOpen ? "OPEN" : "CLOSE" });
79
+ send({ type: nextOpen ? "OPEN" : "CLOSE", replaces: "open" });
78
80
  },
79
81
  triggerValue,
80
82
  setTriggerValue(value) {
@@ -2,12 +2,16 @@
2
2
  import { getDismissableLayerAttrs, getDismissableLayerStyle } from "@zag-js/dismissable";
3
3
  import { ariaAttr, dataAttr, isLeftClick, isSafari } from "@zag-js/dom-query";
4
4
  import { getPlacementSide, getPlacementStyles } from "@zag-js/popper";
5
+ import { mergeWithDefault } from "@zag-js/utils";
5
6
  import { parts } from "./popover.anatomy.mjs";
6
7
  import * as dom from "./popover.dom.mjs";
8
+ var defaultTranslations = {
9
+ closeTriggerLabel: "close"
10
+ };
7
11
  function connect(service, normalize) {
8
12
  const { state, context, send, prop, scope } = service;
9
13
  const layer = context.get("layer");
10
- const translations = prop("translations");
14
+ const translations = mergeWithDefault(defaultTranslations, prop("translations"));
11
15
  const open = state.matches("open");
12
16
  const currentPlacement = context.get("currentPlacement");
13
17
  const currentPlacementSide = currentPlacement ? getPlacementSide(currentPlacement) : void 0;
@@ -38,9 +42,7 @@ function connect(service, normalize) {
38
42
  return {
39
43
  open,
40
44
  setOpen(nextOpen) {
41
- const open2 = state.matches("open");
42
- if (open2 === nextOpen) return;
43
- send({ type: nextOpen ? "OPEN" : "CLOSE" });
45
+ send({ type: nextOpen ? "OPEN" : "CLOSE", replaces: "open" });
44
46
  },
45
47
  triggerValue,
46
48
  setTriggerValue(value) {
@@ -13,9 +13,10 @@ declare const getTriggerEls: (scope: Scope) => HTMLElement[];
13
13
  declare const getActiveTriggerEl: (scope: Scope, value: string | null) => HTMLElement | null;
14
14
  declare const getContentEl: (scope: Scope) => HTMLElement | null;
15
15
  declare const getPositionerEl: (scope: Scope) => HTMLElement | null;
16
+ declare const getArrowEl: (scope: Scope) => HTMLElement | null;
16
17
  declare const getTitleEl: (scope: Scope) => HTMLElement | null;
17
18
  declare const getDescriptionEl: (scope: Scope) => HTMLElement | null;
18
19
  declare const getFocusableEls: (scope: Scope) => HTMLElement[];
19
20
  declare const getFirstFocusableEl: (scope: Scope) => HTMLElement;
20
21
 
21
- export { getActiveTriggerEl, getAnchorEl, getAnchorId, getArrowId, getCloseTriggerId, getContentEl, getContentId, getDescriptionEl, getDescriptionId, getFirstFocusableEl, getFocusableEls, getPositionerEl, getPositionerId, getTitleEl, getTitleId, getTriggerEls, getTriggerId };
22
+ export { getActiveTriggerEl, getAnchorEl, getAnchorId, getArrowEl, getArrowId, getCloseTriggerId, getContentEl, getContentId, getDescriptionEl, getDescriptionId, getFirstFocusableEl, getFocusableEls, getPositionerEl, getPositionerId, getTitleEl, getTitleId, getTriggerEls, getTriggerId };
@@ -13,9 +13,10 @@ declare const getTriggerEls: (scope: Scope) => HTMLElement[];
13
13
  declare const getActiveTriggerEl: (scope: Scope, value: string | null) => HTMLElement | null;
14
14
  declare const getContentEl: (scope: Scope) => HTMLElement | null;
15
15
  declare const getPositionerEl: (scope: Scope) => HTMLElement | null;
16
+ declare const getArrowEl: (scope: Scope) => HTMLElement | null;
16
17
  declare const getTitleEl: (scope: Scope) => HTMLElement | null;
17
18
  declare const getDescriptionEl: (scope: Scope) => HTMLElement | null;
18
19
  declare const getFocusableEls: (scope: Scope) => HTMLElement[];
19
20
  declare const getFirstFocusableEl: (scope: Scope) => HTMLElement;
20
21
 
21
- export { getActiveTriggerEl, getAnchorEl, getAnchorId, getArrowId, getCloseTriggerId, getContentEl, getContentId, getDescriptionEl, getDescriptionId, getFirstFocusableEl, getFocusableEls, getPositionerEl, getPositionerId, getTitleEl, getTitleId, getTriggerEls, getTriggerId };
22
+ export { getActiveTriggerEl, getAnchorEl, getAnchorId, getArrowEl, getArrowId, getCloseTriggerId, getContentEl, getContentId, getDescriptionEl, getDescriptionId, getFirstFocusableEl, getFocusableEls, getPositionerEl, getPositionerId, getTitleEl, getTitleId, getTriggerEls, getTriggerId };
@@ -23,6 +23,7 @@ __export(popover_dom_exports, {
23
23
  getActiveTriggerEl: () => getActiveTriggerEl,
24
24
  getAnchorEl: () => getAnchorEl,
25
25
  getAnchorId: () => getAnchorId,
26
+ getArrowEl: () => getArrowEl,
26
27
  getArrowId: () => getArrowId,
27
28
  getCloseTriggerId: () => getCloseTriggerId,
28
29
  getContentEl: () => getContentEl,
@@ -62,6 +63,7 @@ var getActiveTriggerEl = (scope, value) => {
62
63
  };
63
64
  var getContentEl = (scope) => scope.query(scope.selector(import_popover.parts.content));
64
65
  var getPositionerEl = (scope) => scope.query(scope.selector(import_popover.parts.positioner));
66
+ var getArrowEl = (scope) => scope.query(scope.selector(import_popover.parts.arrow));
65
67
  var getTitleEl = (scope) => scope.query(scope.selector(import_popover.parts.title));
66
68
  var getDescriptionEl = (scope) => scope.query(scope.selector(import_popover.parts.description));
67
69
  var getFocusableEls = (scope) => (0, import_dom_query.getFocusables)(getContentEl(scope));
@@ -71,6 +73,7 @@ var getFirstFocusableEl = (scope) => getFocusableEls(scope)[0];
71
73
  getActiveTriggerEl,
72
74
  getAnchorEl,
73
75
  getAnchorId,
76
+ getArrowEl,
74
77
  getArrowId,
75
78
  getCloseTriggerId,
76
79
  getContentEl,
@@ -22,6 +22,7 @@ var getActiveTriggerEl = (scope, value) => {
22
22
  };
23
23
  var getContentEl = (scope) => scope.query(scope.selector(parts.content));
24
24
  var getPositionerEl = (scope) => scope.query(scope.selector(parts.positioner));
25
+ var getArrowEl = (scope) => scope.query(scope.selector(parts.arrow));
25
26
  var getTitleEl = (scope) => scope.query(scope.selector(parts.title));
26
27
  var getDescriptionEl = (scope) => scope.query(scope.selector(parts.description));
27
28
  var getFocusableEls = (scope) => getFocusables(getContentEl(scope));
@@ -30,6 +31,7 @@ export {
30
31
  getActiveTriggerEl,
31
32
  getAnchorEl,
32
33
  getAnchorId,
34
+ getArrowEl,
33
35
  getArrowId,
34
36
  getCloseTriggerId,
35
37
  getContentEl,
@@ -50,10 +50,6 @@ var machine = (0, import_core.createMachine)({
50
50
  modal: false,
51
51
  restoreFocus: true,
52
52
  ...props,
53
- translations: {
54
- closeTriggerLabel: "close",
55
- ...props.translations
56
- },
57
53
  positioning: {
58
54
  placement: "bottom",
59
55
  ...props.positioning
@@ -178,6 +174,7 @@ var machine = (0, import_core.createMachine)({
178
174
  const getPositionerEl2 = () => dom.getPositionerEl(scope);
179
175
  const getTriggerEl = () => anchorEl ?? dom.getActiveTriggerEl(scope, context.get("triggerValue"));
180
176
  return (0, import_popper.getPlacement)(getTriggerEl, getPositionerEl2, {
177
+ getArrowElement: () => dom.getArrowEl(scope),
181
178
  ...prop("positioning"),
182
179
  defer: true,
183
180
  onComplete(data) {
@@ -185,93 +182,107 @@ var machine = (0, import_core.createMachine)({
185
182
  }
186
183
  });
187
184
  },
188
- trackDismissableElement({ send, prop, scope, context }) {
189
- const getContentEl2 = () => dom.getContentEl(scope);
190
- let restoreFocus = true;
191
- return (0, import_dismissable.trackDismissableElement)(getContentEl2, {
192
- type: "popover",
193
- pointerBlocking: prop("modal"),
194
- onLayerChange(layer) {
195
- context.set("layer", layer);
196
- },
197
- exclude: dom.getTriggerEls(scope),
198
- defer: true,
199
- onEscapeKeyDown(event) {
200
- prop("onEscapeKeyDown")?.(event);
201
- if (prop("closeOnEscape")) return;
202
- event.preventDefault();
203
- },
204
- onInteractOutside(event) {
205
- prop("onInteractOutside")?.(event);
206
- if (event.defaultPrevented) return;
207
- restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
208
- if (!prop("closeOnInteractOutside")) {
185
+ trackDismissableElement({ send, prop, scope, context, watchEffect }) {
186
+ return watchEffect([() => prop("modal")], () => {
187
+ const getContentEl2 = () => dom.getContentEl(scope);
188
+ let restoreFocus = true;
189
+ return (0, import_dismissable.trackDismissableElement)(getContentEl2, {
190
+ type: "popover",
191
+ pointerBlocking: prop("modal"),
192
+ onLayerChange(layer) {
193
+ context.set("layer", layer);
194
+ },
195
+ exclude: dom.getTriggerEls(scope),
196
+ defer: true,
197
+ onEscapeKeyDown(event) {
198
+ prop("onEscapeKeyDown")?.(event);
199
+ if (prop("closeOnEscape")) return;
209
200
  event.preventDefault();
201
+ },
202
+ onInteractOutside(event) {
203
+ prop("onInteractOutside")?.(event);
204
+ if (event.defaultPrevented) return;
205
+ restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
206
+ if (!prop("closeOnInteractOutside")) {
207
+ event.preventDefault();
208
+ }
209
+ },
210
+ onPointerDownOutside: prop("onPointerDownOutside"),
211
+ onFocusOutside: prop("onFocusOutside"),
212
+ persistentElements: prop("persistentElements"),
213
+ onRequestDismiss: prop("onRequestDismiss"),
214
+ onDismiss() {
215
+ send({ type: "CLOSE", src: "interact-outside", restoreFocus });
210
216
  }
211
- },
212
- onPointerDownOutside: prop("onPointerDownOutside"),
213
- onFocusOutside: prop("onFocusOutside"),
214
- persistentElements: prop("persistentElements"),
215
- onRequestDismiss: prop("onRequestDismiss"),
216
- onDismiss() {
217
- send({ type: "CLOSE", src: "interact-outside", restoreFocus });
218
- }
217
+ });
219
218
  });
220
219
  },
221
- proxyTabFocus({ prop, scope, context }) {
222
- if (prop("modal")) return;
223
- const getContentEl2 = () => dom.getContentEl(scope);
224
- let cleanup;
225
- const rafCleanup = (0, import_dom_query.raf)(() => {
226
- const triggerEl = dom.getActiveTriggerEl(scope, context.get("triggerValue"));
227
- const contentEl = getContentEl2();
228
- if (!triggerEl || !contentEl || (0, import_dom_query.contains)(triggerEl.parentElement, contentEl)) return;
229
- cleanup = (0, import_dom_query.proxyTabFocus)(getContentEl2, {
230
- triggerElement: triggerEl,
231
- getShadowRoot: true,
232
- onFocus(el) {
233
- el.focus({ preventScroll: true });
234
- }
220
+ proxyTabFocus({ prop, scope, context, watchEffect }) {
221
+ return watchEffect([() => prop("modal")], () => {
222
+ if (prop("modal")) return;
223
+ const getContentEl2 = () => dom.getContentEl(scope);
224
+ let cleanup;
225
+ const rafCleanup = (0, import_dom_query.raf)(() => {
226
+ const triggerEl = dom.getActiveTriggerEl(scope, context.get("triggerValue"));
227
+ const contentEl = getContentEl2();
228
+ if (!triggerEl || !contentEl || (0, import_dom_query.contains)(triggerEl.parentElement, contentEl)) return;
229
+ cleanup = (0, import_dom_query.proxyTabFocus)(getContentEl2, {
230
+ triggerElement: triggerEl,
231
+ getShadowRoot: true,
232
+ onFocus(el) {
233
+ el.focus({ preventScroll: true });
234
+ }
235
+ });
235
236
  });
237
+ return () => {
238
+ rafCleanup();
239
+ cleanup?.();
240
+ };
236
241
  });
237
- return () => {
238
- rafCleanup();
239
- cleanup?.();
240
- };
241
242
  },
242
- hideContentBelow({ prop, scope, context }) {
243
- if (!prop("modal")) return;
244
- const getElements = () => [dom.getContentEl(scope), dom.getActiveTriggerEl(scope, context.get("triggerValue"))];
245
- return (0, import_aria_hidden.ariaHidden)(getElements, { defer: true });
243
+ hideContentBelow({ prop, scope, context, watchEffect }) {
244
+ return watchEffect([() => prop("modal")], () => {
245
+ if (!prop("modal")) return;
246
+ const getElements = () => [
247
+ dom.getContentEl(scope),
248
+ dom.getActiveTriggerEl(scope, context.get("triggerValue"))
249
+ ];
250
+ return (0, import_aria_hidden.ariaHidden)(getElements, { defer: true });
251
+ });
246
252
  },
247
- preventScroll({ prop, scope }) {
248
- if (!prop("modal")) return;
249
- return (0, import_remove_scroll.preventBodyScroll)(scope.getDoc());
253
+ preventScroll({ prop, scope, watchEffect }) {
254
+ return watchEffect([() => prop("modal")], () => {
255
+ if (!prop("modal")) return;
256
+ return (0, import_remove_scroll.preventBodyScroll)(scope.getDoc());
257
+ });
250
258
  },
251
- trapFocus({ prop, scope, context }) {
252
- if (!prop("modal")) return;
253
- const contentEl = () => dom.getContentEl(scope);
254
- return (0, import_focus_trap.trapFocus)(contentEl, {
255
- preventScroll: true,
256
- returnFocusOnDeactivate: !!prop("restoreFocus"),
257
- initialFocus: () => (0, import_dom_query.getInitialFocus)({
258
- root: dom.getContentEl(scope),
259
- getInitialEl: prop("initialFocusEl"),
260
- enabled: prop("autoFocus")
261
- }),
262
- setReturnFocus: (el) => {
263
- const finalFocusEl = prop("finalFocusEl")?.();
264
- if (finalFocusEl) return finalFocusEl;
265
- const triggerValue = context.get("triggerValue");
266
- if (triggerValue) {
267
- const activeTriggerEl = dom.getActiveTriggerEl(scope, triggerValue);
268
- if (activeTriggerEl) return activeTriggerEl;
269
- }
270
- const fallbackTrigger = dom.getTriggerEls(scope)[0];
271
- if (fallbackTrigger) return fallbackTrigger;
272
- return el;
273
- },
274
- getShadowRoot: true
259
+ trapFocus({ prop, scope, context, watchEffect }) {
260
+ return watchEffect([() => prop("modal")], () => {
261
+ if (!prop("modal")) return;
262
+ const contentEl = () => dom.getContentEl(scope);
263
+ const destroy = (0, import_focus_trap.trapFocus)(contentEl, {
264
+ preventScroll: true,
265
+ returnFocusOnDeactivate: !!prop("restoreFocus"),
266
+ initialFocus: () => (0, import_dom_query.getInitialFocus)({
267
+ root: dom.getContentEl(scope),
268
+ getInitialEl: prop("initialFocusEl"),
269
+ enabled: prop("autoFocus")
270
+ }),
271
+ setReturnFocus: (el) => {
272
+ const finalFocusEl = prop("finalFocusEl")?.();
273
+ if (finalFocusEl) return finalFocusEl;
274
+ const triggerValue = context.get("triggerValue");
275
+ if (triggerValue) {
276
+ const activeTriggerEl = dom.getActiveTriggerEl(scope, triggerValue);
277
+ if (activeTriggerEl) return activeTriggerEl;
278
+ }
279
+ const fallbackTrigger = dom.getTriggerEls(scope)[0];
280
+ if (fallbackTrigger) return fallbackTrigger;
281
+ return el;
282
+ },
283
+ getShadowRoot: true
284
+ });
285
+ return () => destroy({ returnFocus: !!prop("restoreFocus") && !!prop("modal") });
275
286
  });
276
287
  }
277
288
  },
@@ -281,6 +292,7 @@ var machine = (0, import_core.createMachine)({
281
292
  const getPositionerEl2 = () => dom.getPositionerEl(scope);
282
293
  const getTriggerEl = () => anchorEl ?? dom.getActiveTriggerEl(scope, context.get("triggerValue"));
283
294
  (0, import_popper.getPlacement)(getTriggerEl, getPositionerEl2, {
295
+ getArrowElement: () => dom.getArrowEl(scope),
284
296
  ...prop("positioning"),
285
297
  ...event.options,
286
298
  defer: true,
@@ -16,10 +16,6 @@ var machine = createMachine({
16
16
  modal: false,
17
17
  restoreFocus: true,
18
18
  ...props,
19
- translations: {
20
- closeTriggerLabel: "close",
21
- ...props.translations
22
- },
23
19
  positioning: {
24
20
  placement: "bottom",
25
21
  ...props.positioning
@@ -144,6 +140,7 @@ var machine = createMachine({
144
140
  const getPositionerEl2 = () => dom.getPositionerEl(scope);
145
141
  const getTriggerEl = () => anchorEl ?? dom.getActiveTriggerEl(scope, context.get("triggerValue"));
146
142
  return getPlacement(getTriggerEl, getPositionerEl2, {
143
+ getArrowElement: () => dom.getArrowEl(scope),
147
144
  ...prop("positioning"),
148
145
  defer: true,
149
146
  onComplete(data) {
@@ -151,93 +148,107 @@ var machine = createMachine({
151
148
  }
152
149
  });
153
150
  },
154
- trackDismissableElement({ send, prop, scope, context }) {
155
- const getContentEl2 = () => dom.getContentEl(scope);
156
- let restoreFocus = true;
157
- return trackDismissableElement(getContentEl2, {
158
- type: "popover",
159
- pointerBlocking: prop("modal"),
160
- onLayerChange(layer) {
161
- context.set("layer", layer);
162
- },
163
- exclude: dom.getTriggerEls(scope),
164
- defer: true,
165
- onEscapeKeyDown(event) {
166
- prop("onEscapeKeyDown")?.(event);
167
- if (prop("closeOnEscape")) return;
168
- event.preventDefault();
169
- },
170
- onInteractOutside(event) {
171
- prop("onInteractOutside")?.(event);
172
- if (event.defaultPrevented) return;
173
- restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
174
- if (!prop("closeOnInteractOutside")) {
151
+ trackDismissableElement({ send, prop, scope, context, watchEffect }) {
152
+ return watchEffect([() => prop("modal")], () => {
153
+ const getContentEl2 = () => dom.getContentEl(scope);
154
+ let restoreFocus = true;
155
+ return trackDismissableElement(getContentEl2, {
156
+ type: "popover",
157
+ pointerBlocking: prop("modal"),
158
+ onLayerChange(layer) {
159
+ context.set("layer", layer);
160
+ },
161
+ exclude: dom.getTriggerEls(scope),
162
+ defer: true,
163
+ onEscapeKeyDown(event) {
164
+ prop("onEscapeKeyDown")?.(event);
165
+ if (prop("closeOnEscape")) return;
175
166
  event.preventDefault();
167
+ },
168
+ onInteractOutside(event) {
169
+ prop("onInteractOutside")?.(event);
170
+ if (event.defaultPrevented) return;
171
+ restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
172
+ if (!prop("closeOnInteractOutside")) {
173
+ event.preventDefault();
174
+ }
175
+ },
176
+ onPointerDownOutside: prop("onPointerDownOutside"),
177
+ onFocusOutside: prop("onFocusOutside"),
178
+ persistentElements: prop("persistentElements"),
179
+ onRequestDismiss: prop("onRequestDismiss"),
180
+ onDismiss() {
181
+ send({ type: "CLOSE", src: "interact-outside", restoreFocus });
176
182
  }
177
- },
178
- onPointerDownOutside: prop("onPointerDownOutside"),
179
- onFocusOutside: prop("onFocusOutside"),
180
- persistentElements: prop("persistentElements"),
181
- onRequestDismiss: prop("onRequestDismiss"),
182
- onDismiss() {
183
- send({ type: "CLOSE", src: "interact-outside", restoreFocus });
184
- }
183
+ });
185
184
  });
186
185
  },
187
- proxyTabFocus({ prop, scope, context }) {
188
- if (prop("modal")) return;
189
- const getContentEl2 = () => dom.getContentEl(scope);
190
- let cleanup;
191
- const rafCleanup = raf(() => {
192
- const triggerEl = dom.getActiveTriggerEl(scope, context.get("triggerValue"));
193
- const contentEl = getContentEl2();
194
- if (!triggerEl || !contentEl || contains(triggerEl.parentElement, contentEl)) return;
195
- cleanup = proxyTabFocus(getContentEl2, {
196
- triggerElement: triggerEl,
197
- getShadowRoot: true,
198
- onFocus(el) {
199
- el.focus({ preventScroll: true });
200
- }
186
+ proxyTabFocus({ prop, scope, context, watchEffect }) {
187
+ return watchEffect([() => prop("modal")], () => {
188
+ if (prop("modal")) return;
189
+ const getContentEl2 = () => dom.getContentEl(scope);
190
+ let cleanup;
191
+ const rafCleanup = raf(() => {
192
+ const triggerEl = dom.getActiveTriggerEl(scope, context.get("triggerValue"));
193
+ const contentEl = getContentEl2();
194
+ if (!triggerEl || !contentEl || contains(triggerEl.parentElement, contentEl)) return;
195
+ cleanup = proxyTabFocus(getContentEl2, {
196
+ triggerElement: triggerEl,
197
+ getShadowRoot: true,
198
+ onFocus(el) {
199
+ el.focus({ preventScroll: true });
200
+ }
201
+ });
201
202
  });
203
+ return () => {
204
+ rafCleanup();
205
+ cleanup?.();
206
+ };
202
207
  });
203
- return () => {
204
- rafCleanup();
205
- cleanup?.();
206
- };
207
208
  },
208
- hideContentBelow({ prop, scope, context }) {
209
- if (!prop("modal")) return;
210
- const getElements = () => [dom.getContentEl(scope), dom.getActiveTriggerEl(scope, context.get("triggerValue"))];
211
- return ariaHidden(getElements, { defer: true });
209
+ hideContentBelow({ prop, scope, context, watchEffect }) {
210
+ return watchEffect([() => prop("modal")], () => {
211
+ if (!prop("modal")) return;
212
+ const getElements = () => [
213
+ dom.getContentEl(scope),
214
+ dom.getActiveTriggerEl(scope, context.get("triggerValue"))
215
+ ];
216
+ return ariaHidden(getElements, { defer: true });
217
+ });
212
218
  },
213
- preventScroll({ prop, scope }) {
214
- if (!prop("modal")) return;
215
- return preventBodyScroll(scope.getDoc());
219
+ preventScroll({ prop, scope, watchEffect }) {
220
+ return watchEffect([() => prop("modal")], () => {
221
+ if (!prop("modal")) return;
222
+ return preventBodyScroll(scope.getDoc());
223
+ });
216
224
  },
217
- trapFocus({ prop, scope, context }) {
218
- if (!prop("modal")) return;
219
- const contentEl = () => dom.getContentEl(scope);
220
- return trapFocus(contentEl, {
221
- preventScroll: true,
222
- returnFocusOnDeactivate: !!prop("restoreFocus"),
223
- initialFocus: () => getInitialFocus({
224
- root: dom.getContentEl(scope),
225
- getInitialEl: prop("initialFocusEl"),
226
- enabled: prop("autoFocus")
227
- }),
228
- setReturnFocus: (el) => {
229
- const finalFocusEl = prop("finalFocusEl")?.();
230
- if (finalFocusEl) return finalFocusEl;
231
- const triggerValue = context.get("triggerValue");
232
- if (triggerValue) {
233
- const activeTriggerEl = dom.getActiveTriggerEl(scope, triggerValue);
234
- if (activeTriggerEl) return activeTriggerEl;
235
- }
236
- const fallbackTrigger = dom.getTriggerEls(scope)[0];
237
- if (fallbackTrigger) return fallbackTrigger;
238
- return el;
239
- },
240
- getShadowRoot: true
225
+ trapFocus({ prop, scope, context, watchEffect }) {
226
+ return watchEffect([() => prop("modal")], () => {
227
+ if (!prop("modal")) return;
228
+ const contentEl = () => dom.getContentEl(scope);
229
+ const destroy = trapFocus(contentEl, {
230
+ preventScroll: true,
231
+ returnFocusOnDeactivate: !!prop("restoreFocus"),
232
+ initialFocus: () => getInitialFocus({
233
+ root: dom.getContentEl(scope),
234
+ getInitialEl: prop("initialFocusEl"),
235
+ enabled: prop("autoFocus")
236
+ }),
237
+ setReturnFocus: (el) => {
238
+ const finalFocusEl = prop("finalFocusEl")?.();
239
+ if (finalFocusEl) return finalFocusEl;
240
+ const triggerValue = context.get("triggerValue");
241
+ if (triggerValue) {
242
+ const activeTriggerEl = dom.getActiveTriggerEl(scope, triggerValue);
243
+ if (activeTriggerEl) return activeTriggerEl;
244
+ }
245
+ const fallbackTrigger = dom.getTriggerEls(scope)[0];
246
+ if (fallbackTrigger) return fallbackTrigger;
247
+ return el;
248
+ },
249
+ getShadowRoot: true
250
+ });
251
+ return () => destroy({ returnFocus: !!prop("restoreFocus") && !!prop("modal") });
241
252
  });
242
253
  }
243
254
  },
@@ -247,6 +258,7 @@ var machine = createMachine({
247
258
  const getPositionerEl2 = () => dom.getPositionerEl(scope);
248
259
  const getTriggerEl = () => anchorEl ?? dom.getActiveTriggerEl(scope, context.get("triggerValue"));
249
260
  getPlacement(getTriggerEl, getPositionerEl2, {
261
+ getArrowElement: () => dom.getArrowEl(scope),
250
262
  ...prop("positioning"),
251
263
  ...event.options,
252
264
  defer: true,
@@ -2,7 +2,7 @@ import { Machine, EventObject, Service } from '@zag-js/core';
2
2
  import { DismissableElementHandlers, PersistentElementOptions, LayerSnapshot } from '@zag-js/dismissable';
3
3
  import { PositioningOptions, Placement, PlacementSide } from '@zag-js/popper';
4
4
  export { Placement, PositioningOptions } from '@zag-js/popper';
5
- import { PropTypes, RequiredBy, CommonProperties, DirectionProperty, MaybeElement } from '@zag-js/types';
5
+ import { PropTypes, CommonProperties, DirectionProperty, MaybeElement } from '@zag-js/types';
6
6
 
7
7
  interface OpenChangeDetails {
8
8
  open: boolean;
@@ -20,16 +20,16 @@ interface TriggerValueChangeDetails {
20
20
  interface IntlTranslations {
21
21
  closeTriggerLabel?: string | undefined;
22
22
  }
23
- type ElementIds = Partial<{
24
- anchor: string;
25
- trigger: string | ((value?: string) => string);
26
- content: string;
27
- title: string;
28
- description: string;
29
- closeTrigger: string;
30
- positioner: string;
31
- arrow: string;
32
- }>;
23
+ interface ElementIds {
24
+ anchor?: string | undefined;
25
+ trigger?: (string | ((value?: string) => string)) | undefined;
26
+ content?: string | undefined;
27
+ title?: string | undefined;
28
+ description?: string | undefined;
29
+ closeTrigger?: string | undefined;
30
+ positioner?: string | undefined;
31
+ arrow?: string | undefined;
32
+ }
33
33
  interface PopoverProps extends CommonProperties, DirectionProperty, DismissableElementHandlers, PersistentElementOptions {
34
34
  /**
35
35
  * Specifies the localized strings that identifies the accessibility elements and their states
@@ -59,7 +59,7 @@ interface PopoverProps extends CommonProperties, DirectionProperty, DismissableE
59
59
  /**
60
60
  * The element to focus on when the popover is opened.
61
61
  */
62
- initialFocusEl?: (() => HTMLElement | null) | undefined;
62
+ initialFocusEl?: (() => HTMLElement | null) | null | undefined;
63
63
  /**
64
64
  * Element to receive focus when the popover is closed.
65
65
  */
@@ -111,7 +111,7 @@ interface PopoverProps extends CommonProperties, DirectionProperty, DismissableE
111
111
  */
112
112
  onTriggerValueChange?: ((details: TriggerValueChangeDetails) => void) | undefined;
113
113
  }
114
- type PropsWithDefault = "closeOnInteractOutside" | "closeOnEscape" | "modal" | "autoFocus" | "restoreFocus" | "positioning" | "translations";
114
+ type PropsWithDefault = "closeOnInteractOutside" | "closeOnEscape" | "modal" | "autoFocus" | "restoreFocus" | "positioning";
115
115
  interface PrivateContext {
116
116
  /**
117
117
  * The computed layer stack state used for declarative styles and attributes.
@@ -134,7 +134,8 @@ interface PrivateContext {
134
134
  triggerValue: string | null;
135
135
  }
136
136
  interface PopoverSchema {
137
- props: RequiredBy<PopoverProps, PropsWithDefault>;
137
+ props: PopoverProps;
138
+ defaultPropKey: PropsWithDefault;
138
139
  state: "open" | "closed";
139
140
  context: PrivateContext;
140
141
  computed: {};
@@ -149,7 +150,7 @@ interface TriggerProps {
149
150
  /**
150
151
  * The value that identifies this specific trigger
151
152
  */
152
- value?: string;
153
+ value?: string | undefined;
153
154
  }
154
155
  interface TriggerState {
155
156
  /**
@@ -2,7 +2,7 @@ import { Machine, EventObject, Service } from '@zag-js/core';
2
2
  import { DismissableElementHandlers, PersistentElementOptions, LayerSnapshot } from '@zag-js/dismissable';
3
3
  import { PositioningOptions, Placement, PlacementSide } from '@zag-js/popper';
4
4
  export { Placement, PositioningOptions } from '@zag-js/popper';
5
- import { PropTypes, RequiredBy, CommonProperties, DirectionProperty, MaybeElement } from '@zag-js/types';
5
+ import { PropTypes, CommonProperties, DirectionProperty, MaybeElement } from '@zag-js/types';
6
6
 
7
7
  interface OpenChangeDetails {
8
8
  open: boolean;
@@ -20,16 +20,16 @@ interface TriggerValueChangeDetails {
20
20
  interface IntlTranslations {
21
21
  closeTriggerLabel?: string | undefined;
22
22
  }
23
- type ElementIds = Partial<{
24
- anchor: string;
25
- trigger: string | ((value?: string) => string);
26
- content: string;
27
- title: string;
28
- description: string;
29
- closeTrigger: string;
30
- positioner: string;
31
- arrow: string;
32
- }>;
23
+ interface ElementIds {
24
+ anchor?: string | undefined;
25
+ trigger?: (string | ((value?: string) => string)) | undefined;
26
+ content?: string | undefined;
27
+ title?: string | undefined;
28
+ description?: string | undefined;
29
+ closeTrigger?: string | undefined;
30
+ positioner?: string | undefined;
31
+ arrow?: string | undefined;
32
+ }
33
33
  interface PopoverProps extends CommonProperties, DirectionProperty, DismissableElementHandlers, PersistentElementOptions {
34
34
  /**
35
35
  * Specifies the localized strings that identifies the accessibility elements and their states
@@ -59,7 +59,7 @@ interface PopoverProps extends CommonProperties, DirectionProperty, DismissableE
59
59
  /**
60
60
  * The element to focus on when the popover is opened.
61
61
  */
62
- initialFocusEl?: (() => HTMLElement | null) | undefined;
62
+ initialFocusEl?: (() => HTMLElement | null) | null | undefined;
63
63
  /**
64
64
  * Element to receive focus when the popover is closed.
65
65
  */
@@ -111,7 +111,7 @@ interface PopoverProps extends CommonProperties, DirectionProperty, DismissableE
111
111
  */
112
112
  onTriggerValueChange?: ((details: TriggerValueChangeDetails) => void) | undefined;
113
113
  }
114
- type PropsWithDefault = "closeOnInteractOutside" | "closeOnEscape" | "modal" | "autoFocus" | "restoreFocus" | "positioning" | "translations";
114
+ type PropsWithDefault = "closeOnInteractOutside" | "closeOnEscape" | "modal" | "autoFocus" | "restoreFocus" | "positioning";
115
115
  interface PrivateContext {
116
116
  /**
117
117
  * The computed layer stack state used for declarative styles and attributes.
@@ -134,7 +134,8 @@ interface PrivateContext {
134
134
  triggerValue: string | null;
135
135
  }
136
136
  interface PopoverSchema {
137
- props: RequiredBy<PopoverProps, PropsWithDefault>;
137
+ props: PopoverProps;
138
+ defaultPropKey: PropsWithDefault;
138
139
  state: "open" | "closed";
139
140
  context: PrivateContext;
140
141
  computed: {};
@@ -149,7 +150,7 @@ interface TriggerProps {
149
150
  /**
150
151
  * The value that identifies this specific trigger
151
152
  */
152
- value?: string;
153
+ value?: string | undefined;
153
154
  }
154
155
  interface TriggerState {
155
156
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/popover",
3
- "version": "2.0.0-next.1",
3
+ "version": "2.0.0-next.3",
4
4
  "description": "Core logic for the popover widget implemented as a state machine",
5
5
  "keywords": [
6
6
  "js",
@@ -29,16 +29,16 @@
29
29
  "url": "https://github.com/chakra-ui/zag/issues"
30
30
  },
31
31
  "dependencies": {
32
- "@zag-js/anatomy": "2.0.0-next.1",
33
- "@zag-js/aria-hidden": "2.0.0-next.1",
34
- "@zag-js/core": "2.0.0-next.1",
35
- "@zag-js/dom-query": "2.0.0-next.1",
36
- "@zag-js/utils": "2.0.0-next.1",
37
- "@zag-js/dismissable": "2.0.0-next.1",
38
- "@zag-js/popper": "2.0.0-next.1",
39
- "@zag-js/remove-scroll": "2.0.0-next.1",
40
- "@zag-js/types": "2.0.0-next.1",
41
- "@zag-js/focus-trap": "2.0.0-next.1"
32
+ "@zag-js/anatomy": "2.0.0-next.3",
33
+ "@zag-js/aria-hidden": "2.0.0-next.3",
34
+ "@zag-js/core": "2.0.0-next.3",
35
+ "@zag-js/dom-query": "2.0.0-next.3",
36
+ "@zag-js/utils": "2.0.0-next.3",
37
+ "@zag-js/dismissable": "2.0.0-next.3",
38
+ "@zag-js/popper": "2.0.0-next.3",
39
+ "@zag-js/remove-scroll": "2.0.0-next.3",
40
+ "@zag-js/types": "2.0.0-next.3",
41
+ "@zag-js/focus-trap": "2.0.0-next.3"
42
42
  },
43
43
  "devDependencies": {
44
44
  "clean-package": "2.2.0"
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "scripts": {
74
74
  "build": "tsup",
75
- "lint": "eslint src",
75
+ "lint": "oxlint src",
76
76
  "typecheck": "tsc --noEmit"
77
77
  }
78
78
  }