@zag-js/popover 0.82.1 → 1.0.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.
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import { createAnatomy } from '@zag-js/anatomy';
2
- import { createScope, getFocusables, isSafari, dataAttr, proxyTabFocus, getInitialFocus, raf } from '@zag-js/dom-query';
3
- import { getPlacementStyles, getPlacement } from '@zag-js/popper';
2
+ import { proxyTabFocus, getInitialFocus, raf, isSafari, dataAttr } from '@zag-js/dom-query';
3
+ import { getPlacement, getPlacementStyles } from '@zag-js/popper';
4
4
  import { ariaHidden } from '@zag-js/aria-hidden';
5
5
  import { createMachine } from '@zag-js/core';
6
6
  import { trackDismissableElement } from '@zag-js/dismissable';
7
7
  import { trapFocus } from '@zag-js/focus-trap';
8
8
  import { preventBodyScroll } from '@zag-js/remove-scroll';
9
- import { createSplitProps, compact } from '@zag-js/utils';
10
9
  import { createProps } from '@zag-js/types';
10
+ import { createSplitProps } from '@zag-js/utils';
11
11
 
12
12
  // src/popover.anatomy.ts
13
13
  var anatomy = createAnatomy("popover").parts(
@@ -23,33 +23,30 @@ var anatomy = createAnatomy("popover").parts(
23
23
  "closeTrigger"
24
24
  );
25
25
  var parts = anatomy.build();
26
- var dom = createScope({
27
- getAnchorId: (ctx) => ctx.ids?.anchor ?? `popover:${ctx.id}:anchor`,
28
- getTriggerId: (ctx) => ctx.ids?.trigger ?? `popover:${ctx.id}:trigger`,
29
- getContentId: (ctx) => ctx.ids?.content ?? `popover:${ctx.id}:content`,
30
- getPositionerId: (ctx) => ctx.ids?.positioner ?? `popover:${ctx.id}:popper`,
31
- getArrowId: (ctx) => ctx.ids?.arrow ?? `popover:${ctx.id}:arrow`,
32
- getTitleId: (ctx) => ctx.ids?.title ?? `popover:${ctx.id}:title`,
33
- getDescriptionId: (ctx) => ctx.ids?.description ?? `popover:${ctx.id}:desc`,
34
- getCloseTriggerId: (ctx) => ctx.ids?.closeTrigger ?? `popover:${ctx.id}:close`,
35
- getAnchorEl: (ctx) => dom.getById(ctx, dom.getAnchorId(ctx)),
36
- getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
37
- getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
38
- getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
39
- getTitleEl: (ctx) => dom.getById(ctx, dom.getTitleId(ctx)),
40
- getDescriptionEl: (ctx) => dom.getById(ctx, dom.getDescriptionId(ctx)),
41
- getFocusableEls: (ctx) => getFocusables(dom.getContentEl(ctx)),
42
- getFirstFocusableEl: (ctx) => dom.getFocusableEls(ctx)[0]
43
- });
26
+ var getAnchorId = (scope) => scope.ids?.anchor ?? `popover:${scope.id}:anchor`;
27
+ var getTriggerId = (scope) => scope.ids?.trigger ?? `popover:${scope.id}:trigger`;
28
+ var getContentId = (scope) => scope.ids?.content ?? `popover:${scope.id}:content`;
29
+ var getPositionerId = (scope) => scope.ids?.positioner ?? `popover:${scope.id}:popper`;
30
+ var getArrowId = (scope) => scope.ids?.arrow ?? `popover:${scope.id}:arrow`;
31
+ var getTitleId = (scope) => scope.ids?.title ?? `popover:${scope.id}:title`;
32
+ var getDescriptionId = (scope) => scope.ids?.description ?? `popover:${scope.id}:desc`;
33
+ var getCloseTriggerId = (scope) => scope.ids?.closeTrigger ?? `popover:${scope.id}:close`;
34
+ var getAnchorEl = (scope) => scope.getById(getAnchorId(scope));
35
+ var getTriggerEl = (scope) => scope.getById(getTriggerId(scope));
36
+ var getContentEl = (scope) => scope.getById(getContentId(scope));
37
+ var getPositionerEl = (scope) => scope.getById(getPositionerId(scope));
38
+ var getTitleEl = (scope) => scope.getById(getTitleId(scope));
39
+ var getDescriptionEl = (scope) => scope.getById(getDescriptionId(scope));
44
40
 
45
41
  // src/popover.connect.ts
46
- function connect(state, send, normalize) {
42
+ function connect(service, normalize) {
43
+ const { state, context, send, computed, prop, scope } = service;
47
44
  const open = state.matches("open");
48
- const currentPlacement = state.context.currentPlacement;
49
- const portalled = state.context.currentPortalled;
50
- const rendered = state.context.renderedElements;
45
+ const currentPlacement = context.get("currentPlacement");
46
+ const portalled = computed("currentPortalled");
47
+ const rendered = context.get("renderedElements");
51
48
  const popperStyles = getPlacementStyles({
52
- ...state.context.positioning,
49
+ ...prop("positioning"),
53
50
  placement: currentPlacement
54
51
  });
55
52
  return {
@@ -57,44 +54,44 @@ function connect(state, send, normalize) {
57
54
  open,
58
55
  setOpen(nextOpen) {
59
56
  if (nextOpen === open) return;
60
- send(nextOpen ? "OPEN" : "CLOSE");
57
+ send({ type: nextOpen ? "OPEN" : "CLOSE" });
61
58
  },
62
59
  reposition(options = {}) {
63
60
  send({ type: "POSITIONING.SET", options });
64
61
  },
65
62
  getArrowProps() {
66
63
  return normalize.element({
67
- id: dom.getArrowId(state.context),
64
+ id: getArrowId(scope),
68
65
  ...parts.arrow.attrs,
69
- dir: state.context.dir,
66
+ dir: prop("dir"),
70
67
  style: popperStyles.arrow
71
68
  });
72
69
  },
73
70
  getArrowTipProps() {
74
71
  return normalize.element({
75
72
  ...parts.arrowTip.attrs,
76
- dir: state.context.dir,
73
+ dir: prop("dir"),
77
74
  style: popperStyles.arrowTip
78
75
  });
79
76
  },
80
77
  getAnchorProps() {
81
78
  return normalize.element({
82
79
  ...parts.anchor.attrs,
83
- dir: state.context.dir,
84
- id: dom.getAnchorId(state.context)
80
+ dir: prop("dir"),
81
+ id: getAnchorId(scope)
85
82
  });
86
83
  },
87
84
  getTriggerProps() {
88
85
  return normalize.button({
89
86
  ...parts.trigger.attrs,
90
- dir: state.context.dir,
87
+ dir: prop("dir"),
91
88
  type: "button",
92
89
  "data-placement": currentPlacement,
93
- id: dom.getTriggerId(state.context),
90
+ id: getTriggerId(scope),
94
91
  "aria-haspopup": "dialog",
95
92
  "aria-expanded": open,
96
93
  "data-state": open ? "open" : "closed",
97
- "aria-controls": dom.getContentId(state.context),
94
+ "aria-controls": getContentId(scope),
98
95
  onPointerDown(event) {
99
96
  if (isSafari()) {
100
97
  event.currentTarget.focus();
@@ -102,7 +99,7 @@ function connect(state, send, normalize) {
102
99
  },
103
100
  onClick(event) {
104
101
  if (event.defaultPrevented) return;
105
- send("TOGGLE");
102
+ send({ type: "TOGGLE" });
106
103
  },
107
104
  onBlur(event) {
108
105
  send({ type: "TRIGGER_BLUR", target: event.relatedTarget });
@@ -112,293 +109,299 @@ function connect(state, send, normalize) {
112
109
  getIndicatorProps() {
113
110
  return normalize.element({
114
111
  ...parts.indicator.attrs,
115
- dir: state.context.dir,
112
+ dir: prop("dir"),
116
113
  "data-state": open ? "open" : "closed"
117
114
  });
118
115
  },
119
116
  getPositionerProps() {
120
117
  return normalize.element({
121
- id: dom.getPositionerId(state.context),
118
+ id: getPositionerId(scope),
122
119
  ...parts.positioner.attrs,
123
- dir: state.context.dir,
120
+ dir: prop("dir"),
124
121
  style: popperStyles.floating
125
122
  });
126
123
  },
127
124
  getContentProps() {
128
125
  return normalize.element({
129
126
  ...parts.content.attrs,
130
- dir: state.context.dir,
131
- id: dom.getContentId(state.context),
127
+ dir: prop("dir"),
128
+ id: getContentId(scope),
132
129
  tabIndex: -1,
133
130
  role: "dialog",
134
131
  hidden: !open,
135
132
  "data-state": open ? "open" : "closed",
136
133
  "data-expanded": dataAttr(open),
137
- "aria-labelledby": rendered.title ? dom.getTitleId(state.context) : void 0,
138
- "aria-describedby": rendered.description ? dom.getDescriptionId(state.context) : void 0,
134
+ "aria-labelledby": rendered.title ? getTitleId(scope) : void 0,
135
+ "aria-describedby": rendered.description ? getDescriptionId(scope) : void 0,
139
136
  "data-placement": currentPlacement
140
137
  });
141
138
  },
142
139
  getTitleProps() {
143
140
  return normalize.element({
144
141
  ...parts.title.attrs,
145
- id: dom.getTitleId(state.context),
146
- dir: state.context.dir
142
+ id: getTitleId(scope),
143
+ dir: prop("dir")
147
144
  });
148
145
  },
149
146
  getDescriptionProps() {
150
147
  return normalize.element({
151
148
  ...parts.description.attrs,
152
- id: dom.getDescriptionId(state.context),
153
- dir: state.context.dir
149
+ id: getDescriptionId(scope),
150
+ dir: prop("dir")
154
151
  });
155
152
  },
156
153
  getCloseTriggerProps() {
157
154
  return normalize.button({
158
155
  ...parts.closeTrigger.attrs,
159
- dir: state.context.dir,
160
- id: dom.getCloseTriggerId(state.context),
156
+ dir: prop("dir"),
157
+ id: getCloseTriggerId(scope),
161
158
  type: "button",
162
159
  "aria-label": "close",
163
160
  onClick(event) {
164
161
  if (event.defaultPrevented) return;
165
- send("CLOSE");
162
+ send({ type: "CLOSE" });
166
163
  }
167
164
  });
168
165
  }
169
166
  };
170
167
  }
171
- function machine(userContext) {
172
- const ctx = compact(userContext);
173
- return createMachine(
174
- {
175
- id: "popover",
176
- initial: ctx.open ? "open" : "closed",
177
- context: {
178
- closeOnInteractOutside: true,
179
- closeOnEscape: true,
180
- autoFocus: true,
181
- modal: false,
182
- portalled: true,
183
- positioning: {
184
- placement: "bottom",
185
- ...ctx.positioning
168
+ var machine = createMachine({
169
+ props({ props: props2 }) {
170
+ return {
171
+ closeOnInteractOutside: true,
172
+ closeOnEscape: true,
173
+ autoFocus: true,
174
+ modal: false,
175
+ portalled: true,
176
+ ...props2,
177
+ positioning: {
178
+ placement: "bottom",
179
+ ...props2.positioning
180
+ }
181
+ };
182
+ },
183
+ initialState({ prop }) {
184
+ const open = prop("open") || prop("defaultOpen");
185
+ return open ? "open" : "closed";
186
+ },
187
+ context({ bindable }) {
188
+ return {
189
+ currentPlacement: bindable(() => ({
190
+ defaultValue: void 0
191
+ })),
192
+ renderedElements: bindable(() => ({
193
+ defaultValue: { title: true, description: true }
194
+ }))
195
+ };
196
+ },
197
+ computed: {
198
+ currentPortalled: ({ prop }) => !!prop("modal") || !!prop("portalled")
199
+ },
200
+ watch({ track, prop, action }) {
201
+ track([() => prop("open")], () => {
202
+ action(["toggleVisibility"]);
203
+ });
204
+ },
205
+ entry: ["checkRenderedElements"],
206
+ states: {
207
+ closed: {
208
+ on: {
209
+ "CONTROLLED.OPEN": {
210
+ target: "open",
211
+ actions: ["setInitialFocus"]
186
212
  },
187
- currentPlacement: void 0,
188
- ...ctx,
189
- renderedElements: {
190
- title: true,
191
- description: true
192
- }
193
- },
194
- computed: {
195
- currentPortalled: (ctx2) => !!ctx2.modal || !!ctx2.portalled
196
- },
197
- watch: {
198
- open: ["toggleVisibility"]
199
- },
200
- entry: ["checkRenderedElements"],
201
- states: {
202
- closed: {
203
- on: {
204
- "CONTROLLED.OPEN": {
205
- target: "open",
206
- actions: ["setInitialFocus"]
207
- },
208
- TOGGLE: [
209
- {
210
- guard: "isOpenControlled",
211
- actions: ["invokeOnOpen"]
212
- },
213
- {
214
- target: "open",
215
- actions: ["invokeOnOpen", "setInitialFocus"]
216
- }
217
- ],
218
- OPEN: [
219
- {
220
- guard: "isOpenControlled",
221
- actions: ["invokeOnOpen"]
222
- },
223
- {
224
- target: "open",
225
- actions: ["invokeOnOpen", "setInitialFocus"]
226
- }
227
- ]
213
+ TOGGLE: [
214
+ {
215
+ guard: "isOpenControlled",
216
+ actions: ["invokeOnOpen"]
217
+ },
218
+ {
219
+ target: "open",
220
+ actions: ["invokeOnOpen", "setInitialFocus"]
221
+ }
222
+ ],
223
+ OPEN: [
224
+ {
225
+ guard: "isOpenControlled",
226
+ actions: ["invokeOnOpen"]
227
+ },
228
+ {
229
+ target: "open",
230
+ actions: ["invokeOnOpen", "setInitialFocus"]
228
231
  }
232
+ ]
233
+ }
234
+ },
235
+ open: {
236
+ effects: [
237
+ "trapFocus",
238
+ "preventScroll",
239
+ "hideContentBelow",
240
+ "trackPositioning",
241
+ "trackDismissableElement",
242
+ "proxyTabFocus"
243
+ ],
244
+ on: {
245
+ "CONTROLLED.CLOSE": {
246
+ target: "closed",
247
+ actions: ["setFinalFocus"]
229
248
  },
230
- open: {
231
- activities: [
232
- "trapFocus",
233
- "preventScroll",
234
- "hideContentBelow",
235
- "trackPositioning",
236
- "trackDismissableElement",
237
- "proxyTabFocus"
238
- ],
239
- on: {
240
- "CONTROLLED.CLOSE": {
241
- target: "closed",
242
- actions: ["setFinalFocus"]
243
- },
244
- CLOSE: [
245
- {
246
- guard: "isOpenControlled",
247
- actions: ["invokeOnClose"]
248
- },
249
- {
250
- target: "closed",
251
- actions: ["invokeOnClose", "setFinalFocus"]
252
- }
253
- ],
254
- TOGGLE: [
255
- {
256
- guard: "isOpenControlled",
257
- actions: ["invokeOnClose"]
258
- },
259
- {
260
- target: "closed",
261
- actions: ["invokeOnClose"]
262
- }
263
- ],
264
- "POSITIONING.SET": {
265
- actions: "reposition"
266
- }
249
+ CLOSE: [
250
+ {
251
+ guard: "isOpenControlled",
252
+ actions: ["invokeOnClose"]
253
+ },
254
+ {
255
+ target: "closed",
256
+ actions: ["invokeOnClose", "setFinalFocus"]
267
257
  }
258
+ ],
259
+ TOGGLE: [
260
+ {
261
+ guard: "isOpenControlled",
262
+ actions: ["invokeOnClose"]
263
+ },
264
+ {
265
+ target: "closed",
266
+ actions: ["invokeOnClose"]
267
+ }
268
+ ],
269
+ "POSITIONING.SET": {
270
+ actions: ["reposition"]
268
271
  }
269
272
  }
273
+ }
274
+ },
275
+ implementations: {
276
+ guards: {
277
+ isOpenControlled: ({ prop }) => prop("open") != void 0
270
278
  },
271
- {
272
- guards: {
273
- isOpenControlled: (ctx2) => !!ctx2["open.controlled"]
279
+ effects: {
280
+ trackPositioning({ context, prop, scope }) {
281
+ context.set("currentPlacement", prop("positioning").placement);
282
+ const anchorEl = getAnchorEl(scope) ?? getTriggerEl(scope);
283
+ const getPositionerEl2 = () => getPositionerEl(scope);
284
+ return getPlacement(anchorEl, getPositionerEl2, {
285
+ ...prop("positioning"),
286
+ defer: true,
287
+ onComplete(data) {
288
+ context.set("currentPlacement", data.placement);
289
+ }
290
+ });
274
291
  },
275
- activities: {
276
- trackPositioning(ctx2) {
277
- ctx2.currentPlacement = ctx2.positioning.placement;
278
- const anchorEl = dom.getAnchorEl(ctx2) ?? dom.getTriggerEl(ctx2);
279
- const getPositionerEl = () => dom.getPositionerEl(ctx2);
280
- return getPlacement(anchorEl, getPositionerEl, {
281
- ...ctx2.positioning,
282
- defer: true,
283
- onComplete(data) {
284
- ctx2.currentPlacement = data.placement;
285
- }
286
- });
287
- },
288
- trackDismissableElement(ctx2, _evt, { send }) {
289
- const getContentEl = () => dom.getContentEl(ctx2);
290
- let restoreFocus = true;
291
- return trackDismissableElement(getContentEl, {
292
- pointerBlocking: ctx2.modal,
293
- exclude: dom.getTriggerEl(ctx2),
294
- defer: true,
295
- onEscapeKeyDown(event) {
296
- ctx2.onEscapeKeyDown?.(event);
297
- if (ctx2.closeOnEscape) return;
292
+ trackDismissableElement({ send, prop, scope }) {
293
+ const getContentEl2 = () => getContentEl(scope);
294
+ let restoreFocus = true;
295
+ return trackDismissableElement(getContentEl2, {
296
+ pointerBlocking: prop("modal"),
297
+ exclude: getTriggerEl(scope),
298
+ defer: true,
299
+ onEscapeKeyDown(event) {
300
+ prop("onEscapeKeyDown")?.(event);
301
+ if (prop("closeOnEscape")) return;
302
+ event.preventDefault();
303
+ },
304
+ onInteractOutside(event) {
305
+ prop("onInteractOutside")?.(event);
306
+ if (event.defaultPrevented) return;
307
+ restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
308
+ if (!prop("closeOnInteractOutside")) {
298
309
  event.preventDefault();
299
- },
300
- onInteractOutside(event) {
301
- ctx2.onInteractOutside?.(event);
302
- if (event.defaultPrevented) return;
303
- restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
304
- if (!ctx2.closeOnInteractOutside) {
305
- event.preventDefault();
306
- }
307
- },
308
- onPointerDownOutside: ctx2.onPointerDownOutside,
309
- onFocusOutside: ctx2.onFocusOutside,
310
- persistentElements: ctx2.persistentElements,
311
- onDismiss() {
312
- send({ type: "CLOSE", src: "interact-outside", restoreFocus });
313
310
  }
314
- });
315
- },
316
- proxyTabFocus(ctx2) {
317
- if (ctx2.modal || !ctx2.portalled) return;
318
- const getContentEl = () => dom.getContentEl(ctx2);
319
- return proxyTabFocus(getContentEl, {
320
- triggerElement: dom.getTriggerEl(ctx2),
321
- defer: true,
322
- onFocus(el) {
323
- el.focus({ preventScroll: true });
324
- }
325
- });
326
- },
327
- hideContentBelow(ctx2) {
328
- if (!ctx2.modal) return;
329
- const getElements = () => [dom.getContentEl(ctx2), dom.getTriggerEl(ctx2)];
330
- return ariaHidden(getElements, { defer: true });
331
- },
332
- preventScroll(ctx2) {
333
- if (!ctx2.modal) return;
334
- return preventBodyScroll(dom.getDoc(ctx2));
335
- },
336
- trapFocus(ctx2) {
337
- if (!ctx2.modal) return;
338
- const contentEl = () => dom.getContentEl(ctx2);
339
- return trapFocus(contentEl, {
340
- initialFocus: () => getInitialFocus({
341
- root: dom.getContentEl(ctx2),
342
- getInitialEl: ctx2.initialFocusEl,
343
- enabled: ctx2.autoFocus
344
- })
345
- });
346
- }
311
+ },
312
+ onPointerDownOutside: prop("onPointerDownOutside"),
313
+ onFocusOutside: prop("onFocusOutside"),
314
+ persistentElements: prop("persistentElements"),
315
+ onDismiss() {
316
+ send({ type: "CLOSE", src: "interact-outside", restoreFocus });
317
+ }
318
+ });
347
319
  },
348
- actions: {
349
- reposition(ctx2, evt) {
350
- const anchorEl = dom.getAnchorEl(ctx2) ?? dom.getTriggerEl(ctx2);
351
- const getPositionerEl = () => dom.getPositionerEl(ctx2);
352
- getPlacement(anchorEl, getPositionerEl, {
353
- ...ctx2.positioning,
354
- ...evt.options,
355
- defer: true,
356
- listeners: false,
357
- onComplete(data) {
358
- ctx2.currentPlacement = data.placement;
359
- }
360
- });
361
- },
362
- checkRenderedElements(ctx2) {
363
- raf(() => {
364
- Object.assign(ctx2.renderedElements, {
365
- title: !!dom.getTitleEl(ctx2),
366
- description: !!dom.getDescriptionEl(ctx2)
367
- });
368
- });
369
- },
370
- setInitialFocus(ctx2) {
371
- if (ctx2.modal) return;
372
- raf(() => {
373
- const element = getInitialFocus({
374
- root: dom.getContentEl(ctx2),
375
- getInitialEl: ctx2.initialFocusEl,
376
- enabled: ctx2.autoFocus
377
- });
378
- element?.focus({ preventScroll: true });
320
+ proxyTabFocus({ prop, scope }) {
321
+ if (prop("modal") || !prop("portalled")) return;
322
+ const getContentEl2 = () => getContentEl(scope);
323
+ return proxyTabFocus(getContentEl2, {
324
+ triggerElement: getTriggerEl(scope),
325
+ defer: true,
326
+ onFocus(el) {
327
+ el.focus({ preventScroll: true });
328
+ }
329
+ });
330
+ },
331
+ hideContentBelow({ prop, scope }) {
332
+ if (!prop("modal")) return;
333
+ const getElements = () => [getContentEl(scope), getTriggerEl(scope)];
334
+ return ariaHidden(getElements, { defer: true });
335
+ },
336
+ preventScroll({ prop, scope }) {
337
+ if (!prop("modal")) return;
338
+ return preventBodyScroll(scope.getDoc());
339
+ },
340
+ trapFocus({ prop, scope }) {
341
+ if (!prop("modal")) return;
342
+ const contentEl = () => getContentEl(scope);
343
+ return trapFocus(contentEl, {
344
+ initialFocus: () => getInitialFocus({
345
+ root: getContentEl(scope),
346
+ getInitialEl: prop("initialFocusEl"),
347
+ enabled: prop("autoFocus")
348
+ })
349
+ });
350
+ }
351
+ },
352
+ actions: {
353
+ reposition({ event, prop, scope, context }) {
354
+ const anchorEl = getAnchorEl(scope) ?? getTriggerEl(scope);
355
+ const getPositionerEl2 = () => getPositionerEl(scope);
356
+ getPlacement(anchorEl, getPositionerEl2, {
357
+ ...prop("positioning"),
358
+ ...event.options,
359
+ defer: true,
360
+ listeners: false,
361
+ onComplete(data) {
362
+ context.set("currentPlacement", data.placement);
363
+ }
364
+ });
365
+ },
366
+ checkRenderedElements({ context, scope }) {
367
+ raf(() => {
368
+ Object.assign(context.get("renderedElements"), {
369
+ title: !!getTitleEl(scope),
370
+ description: !!getDescriptionEl(scope)
379
371
  });
380
- },
381
- setFinalFocus(ctx2, evt) {
382
- const restoreFocus = evt.restoreFocus ?? evt.previousEvent?.restoreFocus;
383
- if (restoreFocus != null && !restoreFocus) return;
384
- raf(() => {
385
- const element = dom.getTriggerEl(ctx2);
386
- element?.focus({ preventScroll: true });
372
+ });
373
+ },
374
+ setInitialFocus({ prop, scope }) {
375
+ if (prop("modal")) return;
376
+ raf(() => {
377
+ const element = getInitialFocus({
378
+ root: getContentEl(scope),
379
+ getInitialEl: prop("initialFocusEl"),
380
+ enabled: prop("autoFocus")
387
381
  });
388
- },
389
- invokeOnOpen(ctx2) {
390
- ctx2.onOpenChange?.({ open: true });
391
- },
392
- invokeOnClose(ctx2) {
393
- ctx2.onOpenChange?.({ open: false });
394
- },
395
- toggleVisibility(ctx2, evt, { send }) {
396
- send({ type: ctx2.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: evt });
397
- }
382
+ element?.focus({ preventScroll: true });
383
+ });
384
+ },
385
+ setFinalFocus({ event, scope }) {
386
+ const restoreFocus = event.restoreFocus ?? event.previousEvent?.restoreFocus;
387
+ if (restoreFocus != null && !restoreFocus) return;
388
+ raf(() => {
389
+ const element = getTriggerEl(scope);
390
+ element?.focus({ preventScroll: true });
391
+ });
392
+ },
393
+ invokeOnOpen({ prop }) {
394
+ prop("onOpenChange")?.({ open: true });
395
+ },
396
+ invokeOnClose({ prop }) {
397
+ prop("onOpenChange")?.({ open: false });
398
+ },
399
+ toggleVisibility({ event, send, prop }) {
400
+ send({ type: prop("open") ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: event });
398
401
  }
399
402
  }
400
- );
401
- }
403
+ }
404
+ });
402
405
  var props = createProps()([
403
406
  "autoFocus",
404
407
  "closeOnEscape",
@@ -414,7 +417,7 @@ var props = createProps()([
414
417
  "onInteractOutside",
415
418
  "onOpenChange",
416
419
  "onPointerDownOutside",
417
- "open.controlled",
420
+ "defaultOpen",
418
421
  "open",
419
422
  "persistentElements",
420
423
  "portalled",