@zag-js/popover 1.39.0 → 1.40.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.
@@ -49,6 +49,7 @@ var machine = (0, import_core.createMachine)({
49
49
  autoFocus: true,
50
50
  modal: false,
51
51
  portalled: true,
52
+ restoreFocus: true,
52
53
  ...props,
53
54
  translations: {
54
55
  closeTriggerLabel: "close",
@@ -236,15 +237,29 @@ var machine = (0, import_core.createMachine)({
236
237
  if (!prop("modal")) return;
237
238
  return (0, import_remove_scroll.preventBodyScroll)(scope.getDoc());
238
239
  },
239
- trapFocus({ prop, scope }) {
240
+ trapFocus({ prop, scope, context }) {
240
241
  if (!prop("modal")) return;
241
242
  const contentEl = () => dom.getContentEl(scope);
242
243
  return (0, import_focus_trap.trapFocus)(contentEl, {
244
+ preventScroll: true,
245
+ returnFocusOnDeactivate: !!prop("restoreFocus"),
243
246
  initialFocus: () => (0, import_dom_query.getInitialFocus)({
244
247
  root: dom.getContentEl(scope),
245
248
  getInitialEl: prop("initialFocusEl"),
246
249
  enabled: prop("autoFocus")
247
250
  }),
251
+ setReturnFocus: (el) => {
252
+ const finalFocusEl = prop("finalFocusEl")?.();
253
+ if (finalFocusEl) return finalFocusEl;
254
+ const triggerValue = context.get("triggerValue");
255
+ if (triggerValue) {
256
+ const activeTriggerEl = dom.getActiveTriggerEl(scope, triggerValue);
257
+ if (activeTriggerEl) return activeTriggerEl;
258
+ }
259
+ const fallbackTrigger = dom.getTriggerEls(scope)[0];
260
+ if (fallbackTrigger) return fallbackTrigger;
261
+ return el;
262
+ },
248
263
  getShadowRoot: true
249
264
  });
250
265
  }
@@ -287,10 +302,16 @@ var machine = (0, import_core.createMachine)({
287
302
  element?.focus({ preventScroll: true });
288
303
  });
289
304
  },
290
- setFinalFocus({ event, scope, context }) {
291
- const restoreFocus = event.restoreFocus ?? event.previousEvent?.restoreFocus;
292
- if (restoreFocus != null && !restoreFocus) return;
305
+ setFinalFocus({ event, prop, scope, context }) {
306
+ const eventRestoreFocus = event.restoreFocus ?? event.previousEvent?.restoreFocus;
307
+ if (eventRestoreFocus != null && !eventRestoreFocus) return;
308
+ if (!prop("restoreFocus")) return;
293
309
  (0, import_dom_query.raf)(() => {
310
+ const finalFocusEl = prop("finalFocusEl")?.();
311
+ if (finalFocusEl) {
312
+ finalFocusEl.focus({ preventScroll: true });
313
+ return;
314
+ }
294
315
  const element = dom.getActiveTriggerEl(scope, context.get("triggerValue"));
295
316
  element?.focus({ preventScroll: true });
296
317
  });
@@ -15,6 +15,7 @@ var machine = createMachine({
15
15
  autoFocus: true,
16
16
  modal: false,
17
17
  portalled: true,
18
+ restoreFocus: true,
18
19
  ...props,
19
20
  translations: {
20
21
  closeTriggerLabel: "close",
@@ -202,15 +203,29 @@ var machine = createMachine({
202
203
  if (!prop("modal")) return;
203
204
  return preventBodyScroll(scope.getDoc());
204
205
  },
205
- trapFocus({ prop, scope }) {
206
+ trapFocus({ prop, scope, context }) {
206
207
  if (!prop("modal")) return;
207
208
  const contentEl = () => dom.getContentEl(scope);
208
209
  return trapFocus(contentEl, {
210
+ preventScroll: true,
211
+ returnFocusOnDeactivate: !!prop("restoreFocus"),
209
212
  initialFocus: () => getInitialFocus({
210
213
  root: dom.getContentEl(scope),
211
214
  getInitialEl: prop("initialFocusEl"),
212
215
  enabled: prop("autoFocus")
213
216
  }),
217
+ setReturnFocus: (el) => {
218
+ const finalFocusEl = prop("finalFocusEl")?.();
219
+ if (finalFocusEl) return finalFocusEl;
220
+ const triggerValue = context.get("triggerValue");
221
+ if (triggerValue) {
222
+ const activeTriggerEl = dom.getActiveTriggerEl(scope, triggerValue);
223
+ if (activeTriggerEl) return activeTriggerEl;
224
+ }
225
+ const fallbackTrigger = dom.getTriggerEls(scope)[0];
226
+ if (fallbackTrigger) return fallbackTrigger;
227
+ return el;
228
+ },
214
229
  getShadowRoot: true
215
230
  });
216
231
  }
@@ -253,10 +268,16 @@ var machine = createMachine({
253
268
  element?.focus({ preventScroll: true });
254
269
  });
255
270
  },
256
- setFinalFocus({ event, scope, context }) {
257
- const restoreFocus = event.restoreFocus ?? event.previousEvent?.restoreFocus;
258
- if (restoreFocus != null && !restoreFocus) return;
271
+ setFinalFocus({ event, prop, scope, context }) {
272
+ const eventRestoreFocus = event.restoreFocus ?? event.previousEvent?.restoreFocus;
273
+ if (eventRestoreFocus != null && !eventRestoreFocus) return;
274
+ if (!prop("restoreFocus")) return;
259
275
  raf(() => {
276
+ const finalFocusEl = prop("finalFocusEl")?.();
277
+ if (finalFocusEl) {
278
+ finalFocusEl.focus({ preventScroll: true });
279
+ return;
280
+ }
260
281
  const element = dom.getActiveTriggerEl(scope, context.get("triggerValue"));
261
282
  element?.focus({ preventScroll: true });
262
283
  });
@@ -36,6 +36,7 @@ var props = (0, import_types.createProps)()([
36
36
  "getRootNode",
37
37
  "id",
38
38
  "ids",
39
+ "finalFocusEl",
39
40
  "initialFocusEl",
40
41
  "modal",
41
42
  "onEscapeKeyDown",
@@ -48,6 +49,7 @@ var props = (0, import_types.createProps)()([
48
49
  "open",
49
50
  "persistentElements",
50
51
  "portalled",
52
+ "restoreFocus",
51
53
  "positioning",
52
54
  "translations",
53
55
  "triggerValue"
@@ -11,6 +11,7 @@ var props = createProps()([
11
11
  "getRootNode",
12
12
  "id",
13
13
  "ids",
14
+ "finalFocusEl",
14
15
  "initialFocusEl",
15
16
  "modal",
16
17
  "onEscapeKeyDown",
@@ -23,6 +24,7 @@ var props = createProps()([
23
24
  "open",
24
25
  "persistentElements",
25
26
  "portalled",
27
+ "restoreFocus",
26
28
  "positioning",
27
29
  "translations",
28
30
  "triggerValue"
@@ -2,7 +2,7 @@ import { Machine, EventObject, Service } from '@zag-js/core';
2
2
  import { DismissableElementHandlers, PersistentElementOptions } from '@zag-js/dismissable';
3
3
  import { PositioningOptions, Placement } from '@zag-js/popper';
4
4
  export { Placement, PositioningOptions } from '@zag-js/popper';
5
- import { PropTypes, RequiredBy, CommonProperties, DirectionProperty } from '@zag-js/types';
5
+ import { PropTypes, RequiredBy, CommonProperties, DirectionProperty, MaybeElement } from '@zag-js/types';
6
6
 
7
7
  interface OpenChangeDetails {
8
8
  open: boolean;
@@ -67,6 +67,16 @@ interface PopoverProps extends CommonProperties, DirectionProperty, DismissableE
67
67
  * The element to focus on when the popover is opened.
68
68
  */
69
69
  initialFocusEl?: (() => HTMLElement | null) | undefined;
70
+ /**
71
+ * Element to receive focus when the popover is closed.
72
+ */
73
+ finalFocusEl?: (() => MaybeElement) | undefined;
74
+ /**
75
+ * Whether to restore focus to the element that had focus before the popover was opened.
76
+ *
77
+ * @default true
78
+ */
79
+ restoreFocus?: boolean | undefined;
70
80
  /**
71
81
  * Whether to close the popover when the user clicks outside of the popover.
72
82
  * @default true
@@ -108,7 +118,7 @@ interface PopoverProps extends CommonProperties, DirectionProperty, DismissableE
108
118
  */
109
119
  onTriggerValueChange?: ((details: TriggerValueChangeDetails) => void) | undefined;
110
120
  }
111
- type PropsWithDefault = "closeOnInteractOutside" | "closeOnEscape" | "modal" | "portalled" | "autoFocus" | "positioning" | "translations";
121
+ type PropsWithDefault = "closeOnInteractOutside" | "closeOnEscape" | "modal" | "portalled" | "autoFocus" | "restoreFocus" | "positioning" | "translations";
112
122
  type ComputedContext = Readonly<{
113
123
  /**
114
124
  * The computed value of `portalled`
@@ -2,7 +2,7 @@ import { Machine, EventObject, Service } from '@zag-js/core';
2
2
  import { DismissableElementHandlers, PersistentElementOptions } from '@zag-js/dismissable';
3
3
  import { PositioningOptions, Placement } from '@zag-js/popper';
4
4
  export { Placement, PositioningOptions } from '@zag-js/popper';
5
- import { PropTypes, RequiredBy, CommonProperties, DirectionProperty } from '@zag-js/types';
5
+ import { PropTypes, RequiredBy, CommonProperties, DirectionProperty, MaybeElement } from '@zag-js/types';
6
6
 
7
7
  interface OpenChangeDetails {
8
8
  open: boolean;
@@ -67,6 +67,16 @@ interface PopoverProps extends CommonProperties, DirectionProperty, DismissableE
67
67
  * The element to focus on when the popover is opened.
68
68
  */
69
69
  initialFocusEl?: (() => HTMLElement | null) | undefined;
70
+ /**
71
+ * Element to receive focus when the popover is closed.
72
+ */
73
+ finalFocusEl?: (() => MaybeElement) | undefined;
74
+ /**
75
+ * Whether to restore focus to the element that had focus before the popover was opened.
76
+ *
77
+ * @default true
78
+ */
79
+ restoreFocus?: boolean | undefined;
70
80
  /**
71
81
  * Whether to close the popover when the user clicks outside of the popover.
72
82
  * @default true
@@ -108,7 +118,7 @@ interface PopoverProps extends CommonProperties, DirectionProperty, DismissableE
108
118
  */
109
119
  onTriggerValueChange?: ((details: TriggerValueChangeDetails) => void) | undefined;
110
120
  }
111
- type PropsWithDefault = "closeOnInteractOutside" | "closeOnEscape" | "modal" | "portalled" | "autoFocus" | "positioning" | "translations";
121
+ type PropsWithDefault = "closeOnInteractOutside" | "closeOnEscape" | "modal" | "portalled" | "autoFocus" | "restoreFocus" | "positioning" | "translations";
112
122
  type ComputedContext = Readonly<{
113
123
  /**
114
124
  * The computed value of `portalled`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/popover",
3
- "version": "1.39.0",
3
+ "version": "1.40.0",
4
4
  "description": "Core logic for the popover widget implemented as a state machine",
5
5
  "keywords": [
6
6
  "js",
@@ -26,16 +26,16 @@
26
26
  "url": "https://github.com/chakra-ui/zag/issues"
27
27
  },
28
28
  "dependencies": {
29
- "@zag-js/anatomy": "1.39.0",
30
- "@zag-js/aria-hidden": "1.39.0",
31
- "@zag-js/core": "1.39.0",
32
- "@zag-js/dom-query": "1.39.0",
33
- "@zag-js/utils": "1.39.0",
34
- "@zag-js/dismissable": "1.39.0",
35
- "@zag-js/popper": "1.39.0",
36
- "@zag-js/remove-scroll": "1.39.0",
37
- "@zag-js/types": "1.39.0",
38
- "@zag-js/focus-trap": "1.39.0"
29
+ "@zag-js/anatomy": "1.40.0",
30
+ "@zag-js/aria-hidden": "1.40.0",
31
+ "@zag-js/core": "1.40.0",
32
+ "@zag-js/dom-query": "1.40.0",
33
+ "@zag-js/utils": "1.40.0",
34
+ "@zag-js/dismissable": "1.40.0",
35
+ "@zag-js/popper": "1.40.0",
36
+ "@zag-js/remove-scroll": "1.40.0",
37
+ "@zag-js/types": "1.40.0",
38
+ "@zag-js/focus-trap": "1.40.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "clean-package": "2.2.0"