@zag-js/tooltip 0.82.2 → 1.0.1

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.js CHANGED
@@ -4,467 +4,494 @@ var anatomy$1 = require('@zag-js/anatomy');
4
4
  var domQuery = require('@zag-js/dom-query');
5
5
  var focusVisible = require('@zag-js/focus-visible');
6
6
  var popper = require('@zag-js/popper');
7
+ var store$1 = require('@zag-js/store');
7
8
  var core = require('@zag-js/core');
8
- var utils = require('@zag-js/utils');
9
9
  var types = require('@zag-js/types');
10
+ var utils = require('@zag-js/utils');
10
11
 
11
12
  // src/tooltip.anatomy.ts
12
13
  var anatomy = anatomy$1.createAnatomy("tooltip").parts("trigger", "arrow", "arrowTip", "positioner", "content");
13
14
  var parts = anatomy.build();
14
- var dom = domQuery.createScope({
15
- getTriggerId: (ctx) => ctx.ids?.trigger ?? `tooltip:${ctx.id}:trigger`,
16
- getContentId: (ctx) => ctx.ids?.content ?? `tooltip:${ctx.id}:content`,
17
- getArrowId: (ctx) => ctx.ids?.arrow ?? `tooltip:${ctx.id}:arrow`,
18
- getPositionerId: (ctx) => ctx.ids?.positioner ?? `tooltip:${ctx.id}:popper`,
19
- getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
20
- getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
21
- getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
22
- getArrowEl: (ctx) => dom.getById(ctx, dom.getArrowId(ctx))
23
- });
24
- var store = core.proxy({
25
- id: null,
26
- prevId: null,
27
- setId(val) {
28
- this.prevId = this.id;
29
- this.id = val;
30
- }
31
- });
15
+
16
+ // src/tooltip.dom.ts
17
+ var getTriggerId = (scope) => scope.ids?.trigger ?? `tooltip:${scope.id}:trigger`;
18
+ var getContentId = (scope) => scope.ids?.content ?? `tooltip:${scope.id}:content`;
19
+ var getArrowId = (scope) => scope.ids?.arrow ?? `tooltip:${scope.id}:arrow`;
20
+ var getPositionerId = (scope) => scope.ids?.positioner ?? `tooltip:${scope.id}:popper`;
21
+ var getTriggerEl = (scope) => scope.getById(getTriggerId(scope));
22
+ var getPositionerEl = (scope) => scope.getById(getPositionerId(scope));
23
+ var store = store$1.proxy({ id: null });
32
24
 
33
25
  // src/tooltip.connect.ts
34
- function connect(state, send, normalize) {
35
- const id = state.context.id;
36
- const hasAriaLabel = state.context.hasAriaLabel;
37
- const open = state.hasTag("open");
38
- const triggerId = dom.getTriggerId(state.context);
39
- const contentId = dom.getContentId(state.context);
40
- const disabled = state.context.disabled;
26
+ function connect(service, normalize) {
27
+ const { state, context, send, scope, prop, event: _event } = service;
28
+ const id = prop("id");
29
+ const hasAriaLabel = !!prop("aria-label");
30
+ const open = state.matches("open", "closing");
31
+ const triggerId = getTriggerId(scope);
32
+ const contentId = getContentId(scope);
33
+ const disabled = prop("disabled");
41
34
  const popperStyles = popper.getPlacementStyles({
42
- ...state.context.positioning,
43
- placement: state.context.currentPlacement
35
+ ...prop("positioning"),
36
+ placement: context.get("currentPlacement")
44
37
  });
45
38
  return {
46
39
  open,
47
40
  setOpen(nextOpen) {
48
41
  if (nextOpen === open) return;
49
- send(nextOpen ? "OPEN" : "CLOSE");
42
+ send({ type: nextOpen ? "open" : "close" });
50
43
  },
51
44
  reposition(options = {}) {
52
- send({ type: "POSITIONING.SET", options });
45
+ send({ type: "positioning.set", options });
53
46
  },
54
47
  getTriggerProps() {
55
48
  return normalize.button({
56
49
  ...parts.trigger.attrs,
57
50
  id: triggerId,
58
- dir: state.context.dir,
51
+ dir: prop("dir"),
59
52
  "data-expanded": domQuery.dataAttr(open),
60
53
  "data-state": open ? "open" : "closed",
61
54
  "aria-describedby": open ? contentId : void 0,
62
55
  onClick(event) {
63
56
  if (event.defaultPrevented) return;
64
57
  if (disabled) return;
65
- if (!state.context.closeOnClick) return;
66
- send({ type: "CLOSE", src: "trigger.click" });
58
+ if (!prop("closeOnClick")) return;
59
+ send({ type: "close", src: "trigger.click" });
67
60
  },
68
61
  onFocus(event) {
69
- if (event.defaultPrevented) return;
70
- if (disabled) return;
71
- if (state.event.src === "trigger.pointerdown") return;
72
- if (!focusVisible.isFocusVisible()) return;
73
- send({ type: "OPEN", src: "trigger.focus" });
62
+ queueMicrotask(() => {
63
+ if (event.defaultPrevented) return;
64
+ if (disabled) return;
65
+ if (_event.src === "trigger.pointerdown") return;
66
+ if (!focusVisible.isFocusVisible()) return;
67
+ send({ type: "open", src: "trigger.focus" });
68
+ });
74
69
  },
75
70
  onBlur(event) {
76
71
  if (event.defaultPrevented) return;
77
72
  if (disabled) return;
78
73
  if (id === store.id) {
79
- send({ type: "CLOSE", src: "trigger.blur" });
74
+ send({ type: "close", src: "trigger.blur" });
80
75
  }
81
76
  },
82
77
  onPointerDown(event) {
83
78
  if (event.defaultPrevented) return;
84
79
  if (disabled) return;
85
- if (!state.context.closeOnPointerDown) return;
80
+ if (!prop("closeOnPointerDown")) return;
86
81
  if (id === store.id) {
87
- send({ type: "CLOSE", src: "trigger.pointerdown" });
82
+ send({ type: "close", src: "trigger.pointerdown" });
88
83
  }
89
84
  },
90
85
  onPointerMove(event) {
91
86
  if (event.defaultPrevented) return;
92
87
  if (disabled) return;
93
88
  if (event.pointerType === "touch") return;
94
- send("POINTER_MOVE");
89
+ send({ type: "pointer.move" });
95
90
  },
96
91
  onPointerLeave() {
97
92
  if (disabled) return;
98
- send("POINTER_LEAVE");
93
+ send({ type: "pointer.leave" });
99
94
  },
100
95
  onPointerCancel() {
101
96
  if (disabled) return;
102
- send("POINTER_LEAVE");
97
+ send({ type: "pointer.leave" });
103
98
  }
104
99
  });
105
100
  },
106
101
  getArrowProps() {
107
102
  return normalize.element({
108
- id: dom.getArrowId(state.context),
103
+ id: getArrowId(scope),
109
104
  ...parts.arrow.attrs,
110
- dir: state.context.dir,
105
+ dir: prop("dir"),
111
106
  style: popperStyles.arrow
112
107
  });
113
108
  },
114
109
  getArrowTipProps() {
115
110
  return normalize.element({
116
111
  ...parts.arrowTip.attrs,
117
- dir: state.context.dir,
112
+ dir: prop("dir"),
118
113
  style: popperStyles.arrowTip
119
114
  });
120
115
  },
121
116
  getPositionerProps() {
122
117
  return normalize.element({
123
- id: dom.getPositionerId(state.context),
118
+ id: getPositionerId(scope),
124
119
  ...parts.positioner.attrs,
125
- dir: state.context.dir,
120
+ dir: prop("dir"),
126
121
  style: popperStyles.floating
127
122
  });
128
123
  },
129
124
  getContentProps() {
130
125
  return normalize.element({
131
126
  ...parts.content.attrs,
132
- dir: state.context.dir,
127
+ dir: prop("dir"),
133
128
  hidden: !open,
134
129
  "data-state": open ? "open" : "closed",
135
130
  role: hasAriaLabel ? void 0 : "tooltip",
136
131
  id: hasAriaLabel ? void 0 : contentId,
137
- "data-placement": state.context.currentPlacement,
132
+ "data-placement": context.get("currentPlacement"),
138
133
  onPointerEnter() {
139
- send("CONTENT.POINTER_MOVE");
134
+ send({ type: "content.pointer.move" });
140
135
  },
141
136
  onPointerLeave() {
142
- send("CONTENT.POINTER_LEAVE");
137
+ send({ type: "content.pointer.leave" });
143
138
  },
144
139
  style: {
145
- pointerEvents: state.context.interactive ? "auto" : "none"
140
+ pointerEvents: prop("interactive") ? "auto" : "none"
146
141
  }
147
142
  });
148
143
  }
149
144
  };
150
145
  }
151
- var { and, not } = core.guards;
152
- function machine(userContext) {
153
- const ctx = utils.compact(userContext);
154
- return core.createMachine(
155
- {
156
- id: "tooltip",
157
- initial: ctx.open ? "open" : "closed",
158
- activities: ["trackFocusVisible"],
159
- context: {
160
- openDelay: 1e3,
161
- closeDelay: 500,
162
- closeOnPointerDown: true,
163
- closeOnEscape: true,
164
- interactive: false,
165
- closeOnScroll: true,
166
- closeOnClick: true,
167
- disabled: false,
168
- ...ctx,
169
- currentPlacement: void 0,
170
- hasPointerMoveOpened: false,
171
- positioning: {
172
- placement: "bottom",
173
- ...ctx.positioning
174
- }
175
- },
176
- computed: {
177
- hasAriaLabel: (ctx2) => !!ctx2["aria-label"]
178
- },
179
- watch: {
180
- disabled: ["closeIfDisabled"],
181
- open: ["toggleVisibility"]
182
- },
183
- states: {
184
- closed: {
185
- tags: ["closed"],
186
- entry: ["clearGlobalId"],
187
- on: {
188
- "CONTROLLED.OPEN": "open",
189
- OPEN: [
190
- {
191
- guard: "isOpenControlled",
192
- actions: ["invokeOnOpen"]
193
- },
194
- {
195
- target: "open",
196
- actions: ["invokeOnOpen"]
197
- }
198
- ],
199
- POINTER_LEAVE: {
200
- actions: ["clearPointerMoveOpened"]
201
- },
202
- POINTER_MOVE: [
203
- {
204
- guard: and("noVisibleTooltip", not("hasPointerMoveOpened")),
205
- target: "opening"
206
- },
207
- {
208
- guard: not("hasPointerMoveOpened"),
209
- target: "open",
210
- actions: ["setPointerMoveOpened", "invokeOnOpen"]
211
- }
212
- ]
146
+ var { and, not } = core.createGuards();
147
+ var machine = core.createMachine({
148
+ initialState: ({ prop }) => {
149
+ const open = prop("open") || prop("defaultOpen");
150
+ return open ? "open" : "closed";
151
+ },
152
+ props({ props: props2 }) {
153
+ return {
154
+ id: "x",
155
+ openDelay: 1e3,
156
+ closeDelay: 500,
157
+ closeOnPointerDown: true,
158
+ closeOnEscape: true,
159
+ interactive: false,
160
+ closeOnScroll: true,
161
+ closeOnClick: true,
162
+ disabled: false,
163
+ ...props2,
164
+ positioning: {
165
+ placement: "bottom",
166
+ ...props2.positioning
167
+ }
168
+ };
169
+ },
170
+ effects: ["trackFocusVisible", "trackStore"],
171
+ context: ({ bindable }) => ({
172
+ currentPlacement: bindable(() => ({ defaultValue: void 0 })),
173
+ hasPointerMoveOpened: bindable(() => ({ defaultValue: false }))
174
+ }),
175
+ watch({ track, action, prop }) {
176
+ track([() => prop("disabled")], () => {
177
+ action(["closeIfDisabled"]);
178
+ });
179
+ track([() => prop("open")], () => {
180
+ action(["toggleVisibility"]);
181
+ });
182
+ },
183
+ states: {
184
+ closed: {
185
+ entry: ["clearGlobalId"],
186
+ on: {
187
+ "controlled.open": {
188
+ target: "open"
189
+ },
190
+ open: [
191
+ {
192
+ guard: "isOpenControlled",
193
+ actions: ["invokeOnOpen"]
194
+ },
195
+ {
196
+ target: "open",
197
+ actions: ["invokeOnOpen"]
213
198
  }
199
+ ],
200
+ "pointer.leave": {
201
+ actions: ["clearPointerMoveOpened"]
214
202
  },
215
- opening: {
216
- tags: ["closed"],
217
- activities: ["trackScroll", "trackPointerlockChange"],
218
- after: {
219
- OPEN_DELAY: [
220
- {
221
- guard: "isOpenControlled",
222
- actions: ["setPointerMoveOpened", "invokeOnOpen"]
223
- },
224
- {
225
- target: "open",
226
- actions: ["setPointerMoveOpened", "invokeOnOpen"]
227
- }
228
- ]
203
+ "pointer.move": [
204
+ {
205
+ guard: and("noVisibleTooltip", not("hasPointerMoveOpened")),
206
+ target: "opening"
229
207
  },
230
- on: {
231
- "CONTROLLED.OPEN": "open",
232
- "CONTROLLED.CLOSE": "closed",
233
- OPEN: [
234
- {
235
- guard: "isOpenControlled",
236
- actions: ["invokeOnOpen"]
237
- },
238
- {
239
- target: "open",
240
- actions: ["invokeOnOpen"]
241
- }
242
- ],
243
- POINTER_LEAVE: [
244
- {
245
- guard: "isOpenControlled",
246
- // We trigger toggleVisibility manually since the `ctx.open` has not changed yet (at this point)
247
- actions: ["clearPointerMoveOpened", "invokeOnClose", "toggleVisibility"]
248
- },
249
- {
250
- target: "closed",
251
- actions: ["clearPointerMoveOpened", "invokeOnClose"]
252
- }
253
- ],
254
- CLOSE: [
255
- {
256
- guard: "isOpenControlled",
257
- // We trigger toggleVisibility manually since the `ctx.open` has not changed yet (at this point)
258
- actions: ["invokeOnClose", "toggleVisibility"]
259
- },
260
- {
261
- target: "closed",
262
- actions: ["invokeOnClose"]
263
- }
264
- ]
208
+ {
209
+ guard: not("hasPointerMoveOpened"),
210
+ target: "open",
211
+ actions: ["setPointerMoveOpened", "invokeOnOpen"]
265
212
  }
213
+ ]
214
+ }
215
+ },
216
+ opening: {
217
+ effects: ["trackScroll", "trackPointerlockChange", "waitForOpenDelay"],
218
+ on: {
219
+ "after.openDelay": [
220
+ {
221
+ guard: "isOpenControlled",
222
+ actions: ["setPointerMoveOpened", "invokeOnOpen"]
223
+ },
224
+ {
225
+ target: "open",
226
+ actions: ["setPointerMoveOpened", "invokeOnOpen"]
227
+ }
228
+ ],
229
+ "controlled.open": {
230
+ target: "open"
266
231
  },
267
- open: {
268
- tags: ["open"],
269
- activities: ["trackEscapeKey", "trackScroll", "trackPointerlockChange", "trackPositioning"],
270
- entry: ["setGlobalId"],
271
- on: {
272
- "CONTROLLED.CLOSE": "closed",
273
- CLOSE: [
274
- {
275
- guard: "isOpenControlled",
276
- actions: ["invokeOnClose"]
277
- },
278
- {
279
- target: "closed",
280
- actions: ["invokeOnClose"]
281
- }
282
- ],
283
- POINTER_LEAVE: [
284
- {
285
- guard: "isVisible",
286
- target: "closing",
287
- actions: ["clearPointerMoveOpened"]
288
- },
289
- // == group ==
290
- {
291
- guard: "isOpenControlled",
292
- actions: ["clearPointerMoveOpened", "invokeOnClose"]
293
- },
294
- {
295
- target: "closed",
296
- actions: ["clearPointerMoveOpened", "invokeOnClose"]
297
- }
298
- ],
299
- "CONTENT.POINTER_LEAVE": {
300
- guard: "isInteractive",
301
- target: "closing"
302
- },
303
- "POSITIONING.SET": {
304
- actions: "reposition"
305
- }
232
+ "controlled.close": {
233
+ target: "closed"
234
+ },
235
+ open: [
236
+ {
237
+ guard: "isOpenControlled",
238
+ actions: ["invokeOnOpen"]
239
+ },
240
+ {
241
+ target: "open",
242
+ actions: ["invokeOnOpen"]
243
+ }
244
+ ],
245
+ "pointer.leave": [
246
+ {
247
+ guard: "isOpenControlled",
248
+ // We trigger toggleVisibility manually since the `ctx.open` has not changed yet (at this point)
249
+ actions: ["clearPointerMoveOpened", "invokeOnClose", "toggleVisibility"]
250
+ },
251
+ {
252
+ target: "closed",
253
+ actions: ["clearPointerMoveOpened", "invokeOnClose"]
254
+ }
255
+ ],
256
+ close: [
257
+ {
258
+ guard: "isOpenControlled",
259
+ // We trigger toggleVisibility manually since the `ctx.open` has not changed yet (at this point)
260
+ actions: ["invokeOnClose", "toggleVisibility"]
261
+ },
262
+ {
263
+ target: "closed",
264
+ actions: ["invokeOnClose"]
306
265
  }
266
+ ]
267
+ }
268
+ },
269
+ open: {
270
+ effects: ["trackEscapeKey", "trackScroll", "trackPointerlockChange", "trackPositioning"],
271
+ entry: ["setGlobalId"],
272
+ on: {
273
+ "controlled.close": {
274
+ target: "closed"
307
275
  },
308
- closing: {
309
- tags: ["open"],
310
- activities: ["trackStore", "trackPositioning"],
311
- after: {
312
- CLOSE_DELAY: [
313
- {
314
- guard: "isOpenControlled",
315
- actions: ["invokeOnClose"]
316
- },
317
- {
318
- target: "closed",
319
- actions: ["invokeOnClose"]
320
- }
321
- ]
276
+ close: [
277
+ {
278
+ guard: "isOpenControlled",
279
+ actions: ["invokeOnClose"]
322
280
  },
323
- on: {
324
- "CONTROLLED.CLOSE": "closed",
325
- "CONTROLLED.OPEN": "open",
326
- CLOSE: [
327
- {
328
- guard: "isOpenControlled",
329
- actions: ["invokeOnClose"]
330
- },
331
- {
332
- target: "closed",
333
- actions: ["invokeOnClose"]
334
- }
335
- ],
336
- POINTER_MOVE: [
337
- {
338
- guard: "isOpenControlled",
339
- // We trigger toggleVisibility manually since the `ctx.open` has not changed yet (at this point)
340
- actions: ["setPointerMoveOpened", "invokeOnOpen", "toggleVisibility"]
341
- },
342
- {
343
- target: "open",
344
- actions: ["setPointerMoveOpened", "invokeOnOpen"]
345
- }
346
- ],
347
- "CONTENT.POINTER_MOVE": {
348
- guard: "isInteractive",
349
- target: "open"
350
- },
351
- "POSITIONING.SET": {
352
- actions: "reposition"
353
- }
281
+ {
282
+ target: "closed",
283
+ actions: ["invokeOnClose"]
354
284
  }
285
+ ],
286
+ "pointer.leave": [
287
+ {
288
+ guard: "isVisible",
289
+ target: "closing",
290
+ actions: ["clearPointerMoveOpened"]
291
+ },
292
+ // == group ==
293
+ {
294
+ guard: "isOpenControlled",
295
+ actions: ["clearPointerMoveOpened", "invokeOnClose"]
296
+ },
297
+ {
298
+ target: "closed",
299
+ actions: ["clearPointerMoveOpened", "invokeOnClose"]
300
+ }
301
+ ],
302
+ "content.pointer.leave": {
303
+ guard: "isInteractive",
304
+ target: "closing"
305
+ },
306
+ "positioning.set": {
307
+ actions: ["reposition"]
355
308
  }
356
309
  }
357
310
  },
358
- {
359
- activities: {
360
- trackFocusVisible(ctx2) {
361
- return focusVisible.trackFocusVisible({ root: dom.getRootNode(ctx2) });
311
+ closing: {
312
+ effects: ["trackPositioning", "waitForCloseDelay"],
313
+ on: {
314
+ "after.closeDelay": [
315
+ {
316
+ guard: "isOpenControlled",
317
+ actions: ["invokeOnClose"]
318
+ },
319
+ {
320
+ target: "closed",
321
+ actions: ["invokeOnClose"]
322
+ }
323
+ ],
324
+ "controlled.close": {
325
+ target: "closed"
362
326
  },
363
- trackPositioning(ctx2) {
364
- ctx2.currentPlacement || (ctx2.currentPlacement = ctx2.positioning.placement);
365
- const getPositionerEl = () => dom.getPositionerEl(ctx2);
366
- return popper.getPlacement(dom.getTriggerEl(ctx2), getPositionerEl, {
367
- ...ctx2.positioning,
368
- defer: true,
369
- onComplete(data) {
370
- ctx2.currentPlacement = data.placement;
371
- }
372
- });
327
+ "controlled.open": {
328
+ target: "open"
373
329
  },
374
- trackPointerlockChange(ctx2, _evt, { send }) {
375
- const onChange = () => send({ type: "CLOSE", src: "pointerlock:change" });
376
- return domQuery.addDomEvent(dom.getDoc(ctx2), "pointerlockchange", onChange, false);
330
+ close: [
331
+ {
332
+ guard: "isOpenControlled",
333
+ actions: ["invokeOnClose"]
334
+ },
335
+ {
336
+ target: "closed",
337
+ actions: ["invokeOnClose"]
338
+ }
339
+ ],
340
+ "pointer.move": [
341
+ {
342
+ guard: "isOpenControlled",
343
+ // We trigger toggleVisibility manually since the `ctx.open` has not changed yet (at this point)
344
+ actions: ["setPointerMoveOpened", "invokeOnOpen", "toggleVisibility"]
345
+ },
346
+ {
347
+ target: "open",
348
+ actions: ["setPointerMoveOpened", "invokeOnOpen"]
349
+ }
350
+ ],
351
+ "content.pointer.move": {
352
+ guard: "isInteractive",
353
+ target: "open"
377
354
  },
378
- trackScroll(ctx2, _evt, { send }) {
379
- if (!ctx2.closeOnScroll) return;
380
- const triggerEl = dom.getTriggerEl(ctx2);
381
- if (!triggerEl) return;
382
- const overflowParents = domQuery.getOverflowAncestors(triggerEl);
383
- const cleanups = overflowParents.map((overflowParent) => {
384
- const onScroll = () => {
385
- send({ type: "CLOSE", src: "scroll" });
386
- };
387
- return domQuery.addDomEvent(overflowParent, "scroll", onScroll, { passive: true, capture: true });
355
+ "positioning.set": {
356
+ actions: ["reposition"]
357
+ }
358
+ }
359
+ }
360
+ },
361
+ implementations: {
362
+ guards: {
363
+ noVisibleTooltip: () => store.id === null,
364
+ isVisible: ({ prop }) => prop("id") === store.id,
365
+ isInteractive: ({ prop }) => !!prop("interactive"),
366
+ hasPointerMoveOpened: ({ context }) => context.get("hasPointerMoveOpened"),
367
+ isOpenControlled: ({ prop }) => prop("open") !== void 0
368
+ },
369
+ actions: {
370
+ setGlobalId: ({ prop }) => {
371
+ store.id = prop("id");
372
+ },
373
+ clearGlobalId: ({ prop }) => {
374
+ if (prop("id") === store.id) {
375
+ store.id = null;
376
+ }
377
+ },
378
+ invokeOnOpen: ({ prop }) => {
379
+ prop("onOpenChange")?.({ open: true });
380
+ },
381
+ invokeOnClose: ({ prop }) => {
382
+ prop("onOpenChange")?.({ open: false });
383
+ },
384
+ closeIfDisabled: ({ prop, send }) => {
385
+ if (!prop("disabled")) return;
386
+ send({ type: "close", src: "disabled.change" });
387
+ },
388
+ reposition: ({ context, event, prop, scope }) => {
389
+ if (event.type !== "positioning.set") return;
390
+ const getPositionerEl2 = () => getPositionerEl(scope);
391
+ return popper.getPlacement(getTriggerEl(scope), getPositionerEl2, {
392
+ ...prop("positioning"),
393
+ ...event.options,
394
+ defer: true,
395
+ listeners: false,
396
+ onComplete(data) {
397
+ context.set("currentPlacement", data.placement);
398
+ }
399
+ });
400
+ },
401
+ toggleVisibility: ({ prop, event, send }) => {
402
+ queueMicrotask(() => {
403
+ send({
404
+ type: prop("open") ? "controlled.open" : "controlled.close",
405
+ previousEvent: event
388
406
  });
389
- return () => {
390
- cleanups.forEach((fn) => fn?.());
407
+ });
408
+ },
409
+ setPointerMoveOpened: ({ context }) => {
410
+ context.set("hasPointerMoveOpened", true);
411
+ },
412
+ clearPointerMoveOpened: ({ context }) => {
413
+ context.set("hasPointerMoveOpened", false);
414
+ }
415
+ },
416
+ effects: {
417
+ trackFocusVisible: ({ scope }) => {
418
+ return focusVisible.trackFocusVisible({ root: scope.getRootNode?.() });
419
+ },
420
+ trackPositioning: ({ flush, context, prop, scope }) => {
421
+ if (!context.get("currentPlacement")) {
422
+ const positioning = prop("positioning");
423
+ context.set("currentPlacement", positioning.placement);
424
+ }
425
+ const getPositionerEl2 = () => getPositionerEl(scope);
426
+ return popper.getPlacement(getTriggerEl(scope), getPositionerEl2, {
427
+ ...prop("positioning"),
428
+ defer: true,
429
+ onComplete(data) {
430
+ flush(() => {
431
+ context.set("currentPlacement", data.placement);
432
+ });
433
+ }
434
+ });
435
+ },
436
+ trackPointerlockChange: ({ send, scope }) => {
437
+ const doc = scope.getDoc();
438
+ const onChange = () => send({ type: "close", src: "pointerlock:change" });
439
+ return domQuery.addDomEvent(doc, "pointerlockchange", onChange, false);
440
+ },
441
+ trackScroll: ({ send, prop, scope }) => {
442
+ if (!prop("closeOnScroll")) return;
443
+ const triggerEl = getTriggerEl(scope);
444
+ if (!triggerEl) return;
445
+ const overflowParents = domQuery.getOverflowAncestors(triggerEl);
446
+ const cleanups = overflowParents.map((overflowParent) => {
447
+ const onScroll = () => {
448
+ send({ type: "close", src: "scroll" });
391
449
  };
392
- },
393
- trackStore(ctx2, _evt, { send }) {
394
- return core.subscribe(store, () => {
395
- if (store.id !== ctx2.id) {
396
- send({ type: "CLOSE", src: "id.change" });
397
- }
450
+ return domQuery.addDomEvent(overflowParent, "scroll", onScroll, {
451
+ passive: true,
452
+ capture: true
398
453
  });
399
- },
400
- trackEscapeKey(ctx2, _evt, { send }) {
401
- if (!ctx2.closeOnEscape) return;
402
- const onKeyDown = (event) => {
403
- if (domQuery.isComposingEvent(event)) return;
404
- if (event.key !== "Escape") return;
405
- event.stopPropagation();
406
- send({ type: "CLOSE", src: "keydown.escape" });
407
- };
408
- return domQuery.addDomEvent(dom.getDoc(ctx2), "keydown", onKeyDown, true);
409
- }
454
+ });
455
+ return () => {
456
+ cleanups.forEach((fn) => fn?.());
457
+ };
410
458
  },
411
- actions: {
412
- setGlobalId(ctx2) {
413
- store.setId(ctx2.id);
414
- },
415
- clearGlobalId(ctx2) {
416
- if (ctx2.id === store.id) {
417
- store.setId(null);
418
- }
419
- },
420
- invokeOnOpen(ctx2) {
421
- ctx2.onOpenChange?.({ open: true });
422
- },
423
- invokeOnClose(ctx2) {
424
- ctx2.onOpenChange?.({ open: false });
425
- },
426
- closeIfDisabled(ctx2, _evt, { send }) {
427
- if (!ctx2.disabled) return;
428
- send({ type: "CLOSE", src: "disabled.change" });
429
- },
430
- reposition(ctx2, evt) {
431
- const getPositionerEl = () => dom.getPositionerEl(ctx2);
432
- popper.getPlacement(dom.getTriggerEl(ctx2), getPositionerEl, {
433
- ...ctx2.positioning,
434
- ...evt.options,
435
- defer: true,
436
- listeners: false,
437
- onComplete(data) {
438
- ctx2.currentPlacement = data.placement;
459
+ trackStore: ({ prop, send }) => {
460
+ let cleanup;
461
+ queueMicrotask(() => {
462
+ cleanup = store$1.subscribe(store, () => {
463
+ if (store.id !== prop("id")) {
464
+ send({ type: "close", src: "id.change" });
439
465
  }
440
466
  });
441
- },
442
- toggleVisibility(ctx2, evt, { send }) {
443
- queueMicrotask(() => {
444
- send({ type: ctx2.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: evt });
445
- });
446
- },
447
- setPointerMoveOpened(ctx2) {
448
- ctx2.hasPointerMoveOpened = true;
449
- },
450
- clearPointerMoveOpened(ctx2) {
451
- ctx2.hasPointerMoveOpened = false;
452
- }
467
+ });
468
+ return () => cleanup?.();
469
+ },
470
+ trackEscapeKey: ({ send, prop }) => {
471
+ if (!prop("closeOnEscape")) return;
472
+ const onKeyDown = (event) => {
473
+ if (domQuery.isComposingEvent(event)) return;
474
+ if (event.key !== "Escape") return;
475
+ event.stopPropagation();
476
+ send({ type: "close", src: "keydown.escape" });
477
+ };
478
+ return domQuery.addDomEvent(document, "keydown", onKeyDown, true);
453
479
  },
454
- guards: {
455
- noVisibleTooltip: () => store.id === null,
456
- isVisible: (ctx2) => ctx2.id === store.id,
457
- isInteractive: (ctx2) => ctx2.interactive,
458
- hasPointerMoveOpened: (ctx2) => !!ctx2.hasPointerMoveOpened,
459
- isOpenControlled: (ctx2) => !!ctx2["open.controlled"]
480
+ waitForOpenDelay: ({ send, prop }) => {
481
+ const id = setTimeout(() => {
482
+ send({ type: "after.openDelay" });
483
+ }, prop("openDelay"));
484
+ return () => clearTimeout(id);
460
485
  },
461
- delays: {
462
- OPEN_DELAY: (ctx2) => ctx2.openDelay,
463
- CLOSE_DELAY: (ctx2) => ctx2.closeDelay
486
+ waitForCloseDelay: ({ send, prop }) => {
487
+ const id = setTimeout(() => {
488
+ send({ type: "after.closeDelay" });
489
+ }, prop("closeDelay"));
490
+ return () => clearTimeout(id);
464
491
  }
465
492
  }
466
- );
467
- }
493
+ }
494
+ });
468
495
  var props = types.createProps()([
469
496
  "aria-label",
470
497
  "closeDelay",
@@ -479,7 +506,7 @@ var props = types.createProps()([
479
506
  "ids",
480
507
  "interactive",
481
508
  "onOpenChange",
482
- "open.controlled",
509
+ "defaultOpen",
483
510
  "open",
484
511
  "openDelay",
485
512
  "positioning"