sheer-ui 0.4.2 → 0.4.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.
Files changed (46) hide show
  1. package/package.json +1 -1
  2. package/src/lib/components/avatar/avatar.svelte.ts +34 -37
  3. package/src/lib/components/avatar/components/avatar-fallback.svelte +9 -6
  4. package/src/lib/components/avatar/components/avatar-image.svelte +18 -9
  5. package/src/lib/components/avatar/components/avatar.svelte +20 -16
  6. package/src/lib/components/checkbox/checkbox.svelte.ts +45 -55
  7. package/src/lib/components/checkbox/components/checkbox-group-label.svelte +9 -6
  8. package/src/lib/components/checkbox/components/checkbox-group.svelte +25 -16
  9. package/src/lib/components/checkbox/components/checkbox.svelte +39 -25
  10. package/src/lib/components/dialog/components/dialog-close.svelte +13 -8
  11. package/src/lib/components/dialog/components/dialog-content-headless.svelte +14 -11
  12. package/src/lib/components/dialog/components/dialog-description.svelte +9 -6
  13. package/src/lib/components/dialog/components/dialog-overlay.svelte +10 -7
  14. package/src/lib/components/dialog/components/dialog-title.svelte +12 -7
  15. package/src/lib/components/dialog/components/dialog-trigger.svelte +12 -7
  16. package/src/lib/components/dialog/components/dialog.svelte +10 -4
  17. package/src/lib/components/dialog/components/modal-surface.svelte +11 -8
  18. package/src/lib/components/dialog/dialog.svelte.ts +73 -61
  19. package/src/lib/components/drawer/drawer.svelte +8 -3
  20. package/src/lib/components/link-preview/components/link-preview-content.svelte +15 -8
  21. package/src/lib/components/link-preview/components/link-preview-trigger.svelte +9 -6
  22. package/src/lib/components/link-preview/components/link-preview.svelte +19 -11
  23. package/src/lib/components/link-preview/link-preview.svelte.ts +42 -43
  24. package/src/lib/components/menu/menu.svelte.ts +20 -1
  25. package/src/lib/components/meter/components/meter.svelte +18 -9
  26. package/src/lib/components/meter/meter.svelte.ts +15 -18
  27. package/src/lib/components/popover/components/popover-close.svelte +9 -6
  28. package/src/lib/components/popover/components/popover-content.svelte +12 -7
  29. package/src/lib/components/popover/components/popover-trigger.svelte +21 -10
  30. package/src/lib/components/popover/components/popover.svelte +9 -8
  31. package/src/lib/components/popover/popover.svelte.ts +68 -74
  32. package/src/lib/components/progress/components/progress.svelte +18 -9
  33. package/src/lib/components/progress/progress.svelte.ts +14 -17
  34. package/src/lib/components/separator/components/separator.svelte +15 -8
  35. package/src/lib/components/separator/separator.svelte.ts +12 -15
  36. package/src/lib/components/sidebar/sidebar-mobile-surface.svelte +8 -4
  37. package/src/lib/components/toggle/components/toggle.svelte +19 -14
  38. package/src/lib/components/toggle/toggle.svelte.ts +15 -20
  39. package/src/lib/components/tooltip/components/tooltip-content.svelte +15 -8
  40. package/src/lib/components/tooltip/components/tooltip-provider.svelte +18 -7
  41. package/src/lib/components/tooltip/components/tooltip-trigger.svelte +21 -10
  42. package/src/lib/components/tooltip/components/tooltip.svelte +34 -21
  43. package/src/lib/components/tooltip/tooltip.svelte.ts +96 -99
  44. package/src/lib/internal/escape-layer/use-escape-layer.svelte.ts +13 -29
  45. package/src/lib/internal/group-value.svelte.ts +11 -10
  46. package/src/lib/internal/native-popover.svelte.ts +6 -6
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { join } from 'overrule';
3
3
  import type { ClassValue } from 'svelte/elements';
4
- import { boxWith } from '../../../internal/tools/index.js';
5
4
  import { mergeProps } from '../../../internal/merge-props.js';
6
5
  import type { TooltipContentProps } from '../types.js';
7
6
  import { TooltipContentState } from '../tooltip.svelte.js';
@@ -28,13 +27,21 @@
28
27
  }: TooltipContentProps & { arrowClasses?: ClassValue; portalProps?: unknown } = $props();
29
28
 
30
29
  const contentState = TooltipContentState.create({
31
- id: boxWith(() => id),
32
- ref: boxWith(
33
- () => ref,
34
- (v) => (ref = v),
35
- ),
36
- onInteractOutside: boxWith(() => onInteractOutside),
37
- onEscapeKeydown: boxWith(() => onEscapeKeydown),
30
+ get id() {
31
+ return id;
32
+ },
33
+ get ref() {
34
+ return ref;
35
+ },
36
+ set ref(v) {
37
+ ref = v;
38
+ },
39
+ get onInteractOutside() {
40
+ return onInteractOutside;
41
+ },
42
+ get onEscapeKeydown() {
43
+ return onEscapeKeydown;
44
+ },
38
45
  });
39
46
 
40
47
  const lifecycleProps = useNativePopoverLifecycle(contentState);
@@ -1,5 +1,4 @@
1
1
  <script lang="ts">
2
- import { boxWith } from '../../../internal/tools/index.js';
3
2
  import type { TooltipProviderProps } from '../types.js';
4
3
  import { TooltipProviderState } from '../tooltip.svelte.js';
5
4
 
@@ -14,12 +13,24 @@
14
13
  }: TooltipProviderProps = $props();
15
14
 
16
15
  TooltipProviderState.create({
17
- delayDuration: boxWith(() => delayDuration),
18
- disableCloseOnTriggerClick: boxWith(() => disableCloseOnTriggerClick),
19
- disableHoverableContent: boxWith(() => disableHoverableContent),
20
- disabled: boxWith(() => disabled),
21
- ignoreNonKeyboardFocus: boxWith(() => ignoreNonKeyboardFocus),
22
- skipDelayDuration: boxWith(() => skipDelayDuration),
16
+ get delayDuration() {
17
+ return delayDuration;
18
+ },
19
+ get disableCloseOnTriggerClick() {
20
+ return disableCloseOnTriggerClick;
21
+ },
22
+ get disableHoverableContent() {
23
+ return disableHoverableContent;
24
+ },
25
+ get disabled() {
26
+ return disabled;
27
+ },
28
+ get ignoreNonKeyboardFocus() {
29
+ return ignoreNonKeyboardFocus;
30
+ },
31
+ get skipDelayDuration() {
32
+ return skipDelayDuration;
33
+ },
23
34
  });
24
35
  </script>
25
36
 
@@ -3,7 +3,6 @@
3
3
  </script>
4
4
 
5
5
  <script lang="ts" generics="T = never">
6
- import { boxWith } from '../../../internal/tools/index.js';
7
6
  import { mergeProps } from '../../../internal/merge-props.js';
8
7
  import type { TooltipTriggerProps } from '../types.js';
9
8
  import { TooltipTriggerState } from '../tooltip.svelte.js';
@@ -25,15 +24,27 @@
25
24
  }: TooltipTriggerProps<T> = $props();
26
25
 
27
26
  const triggerState = TooltipTriggerState.create({
28
- id: boxWith(() => id),
29
- disabled: boxWith(() => disabled ?? false),
30
- tabindex: boxWith(() => tabindex ?? 0),
31
- payload: boxWith(() => payload),
32
- tether: boxWith(() => tether),
33
- ref: boxWith(
34
- () => ref,
35
- (v) => (ref = v),
36
- ),
27
+ get id() {
28
+ return id;
29
+ },
30
+ get disabled() {
31
+ return disabled ?? false;
32
+ },
33
+ get tabindex() {
34
+ return tabindex ?? 0;
35
+ },
36
+ get payload() {
37
+ return payload;
38
+ },
39
+ get tether() {
40
+ return tether;
41
+ },
42
+ get ref() {
43
+ return ref;
44
+ },
45
+ set ref(v) {
46
+ ref = v;
47
+ },
37
48
  });
38
49
 
39
50
  const mergedProps = $derived(mergeProps({ 'data-slot': 'tooltip-trigger' }, restProps, triggerState.props, { type }));
@@ -3,7 +3,6 @@
3
3
  </script>
4
4
 
5
5
  <script lang="ts" generics="T = never">
6
- import { boxWith } from '../../../internal/tools/index.js';
7
6
  import { OpenCell } from '../../../internal/open-cell.svelte.js';
8
7
  import type { TooltipRootProps } from '../types.js';
9
8
  import { TooltipRootState } from '../tooltip.svelte.js';
@@ -22,34 +21,48 @@
22
21
  children,
23
22
  }: TooltipRootProps<T> = $props();
24
23
 
25
- // Cell over the source prop; the engine keeps its boxed-open interface (vendored,
26
- // ADR 0006) — the box is a bridge over the cell, so the cell owns `open`.
27
24
  // svelte-ignore state_referenced_locally
28
25
  const cell = givenCell ?? new OpenCell(() => open);
29
26
 
30
27
  const rootState = TooltipRootState.create({
31
- open: boxWith(
32
- () => cell.open,
33
- (v) => (cell.open = v),
34
- ),
35
- triggerId: boxWith(
36
- () => triggerId,
37
- (v) => {
38
- triggerId = v;
39
- },
40
- ),
41
- delayDuration: boxWith(() => delayDuration),
42
- disableCloseOnTriggerClick: boxWith(() => disableCloseOnTriggerClick),
43
- disableHoverableContent: boxWith(() => disableHoverableContent),
44
- ignoreNonKeyboardFocus: boxWith(() => ignoreNonKeyboardFocus),
45
- disabled: boxWith(() => disabled),
46
- onOpenChangeComplete: boxWith(() => onOpenChangeComplete),
47
- tether: boxWith(() => tether),
28
+ get open() {
29
+ return cell.open;
30
+ },
31
+ set open(v) {
32
+ cell.open = v;
33
+ },
34
+ get triggerId() {
35
+ return triggerId;
36
+ },
37
+ set triggerId(v) {
38
+ triggerId = v;
39
+ },
40
+ get delayDuration() {
41
+ return delayDuration;
42
+ },
43
+ get disableCloseOnTriggerClick() {
44
+ return disableCloseOnTriggerClick;
45
+ },
46
+ get disableHoverableContent() {
47
+ return disableHoverableContent;
48
+ },
49
+ get ignoreNonKeyboardFocus() {
50
+ return ignoreNonKeyboardFocus;
51
+ },
52
+ get disabled() {
53
+ return disabled;
54
+ },
55
+ get onOpenChangeComplete() {
56
+ return onOpenChangeComplete;
57
+ },
58
+ get tether() {
59
+ return tether;
60
+ },
48
61
  });
49
62
  </script>
50
63
 
51
64
  {@render children?.({
52
- open: rootState.opts.open.current,
65
+ open: rootState.opts.open,
53
66
  triggerId: rootState.activeTriggerId,
54
67
  payload: rootState.activePayload as [T] extends [never] ? null : T | null,
55
68
  })}
@@ -1,9 +1,9 @@
1
- import { attachRef, DOMContext, type WritableBoxedValues, type ReadableBoxedValues } from '../../internal/tools/index.js';
1
+ import { attachRef, DOMContext } from '../../internal/tools/index.js';
2
2
  import { on } from 'svelte/events';
3
3
  import { createContext, onMount, untrack } from 'svelte';
4
4
  import { isElement } from '../../internal/tools/utils/dom.js';
5
5
  import { createBitsAttrs, boolToEmptyStrOrUndef } from '../../internal/attrs.js';
6
- import type { OnChangeFn, RefAttachment, WithRefOpts } from '../../internal/types.js';
6
+ import type { OnChangeFn, RefAttachment, RefOpts } from '../../internal/types.js';
7
7
  import type { FocusEventHandler, MouseEventHandler, PointerEventHandler } from 'svelte/elements';
8
8
  import { createEffectTimeout } from '../../internal/timeout-fn.svelte.js';
9
9
  import { SafePolygon } from '../../internal/safe-polygon.svelte.js';
@@ -122,7 +122,7 @@ export class TooltipTether<Payload = never> {
122
122
  }
123
123
 
124
124
  get isOpen() {
125
- return this.#state.root?.opts.open.current ?? false;
125
+ return this.#state.root?.opts.open ?? false;
126
126
  }
127
127
  }
128
128
 
@@ -130,14 +130,14 @@ export function createTooltipTether<Payload = never>() {
130
130
  return new TooltipTether<Payload>();
131
131
  }
132
132
 
133
- interface TooltipProviderStateOpts extends ReadableBoxedValues<{
134
- delayDuration: number;
135
- disableHoverableContent: boolean;
136
- disableCloseOnTriggerClick: boolean;
137
- disabled: boolean;
138
- ignoreNonKeyboardFocus: boolean;
139
- skipDelayDuration: number;
140
- }> {}
133
+ interface TooltipProviderStateOpts {
134
+ readonly delayDuration: number;
135
+ readonly disableHoverableContent: boolean;
136
+ readonly disableCloseOnTriggerClick: boolean;
137
+ readonly disabled: boolean;
138
+ readonly ignoreNonKeyboardFocus: boolean;
139
+ readonly skipDelayDuration: number;
140
+ }
141
141
 
142
142
  export class TooltipProviderState {
143
143
  static create(opts: TooltipProviderStateOpts) {
@@ -154,7 +154,7 @@ export class TooltipProviderState {
154
154
  () => {
155
155
  this.isOpenDelayed = true;
156
156
  },
157
- () => this.opts.skipDelayDuration.current,
157
+ () => this.opts.skipDelayDuration,
158
158
  );
159
159
 
160
160
  onMount(() =>
@@ -175,7 +175,7 @@ export class TooltipProviderState {
175
175
  }
176
176
 
177
177
  #startTimer = () => {
178
- const skipDuration = this.opts.skipDelayDuration.current;
178
+ const skipDuration = this.opts.skipDelayDuration;
179
179
 
180
180
  if (skipDuration === 0) {
181
181
  // no grace period — reset immediately so next trigger waits the full delay
@@ -212,21 +212,17 @@ export class TooltipProviderState {
212
212
  };
213
213
  }
214
214
 
215
- interface TooltipRootStateOpts
216
- extends
217
- ReadableBoxedValues<{
218
- delayDuration: number | undefined;
219
- disableHoverableContent: boolean | undefined;
220
- disableCloseOnTriggerClick: boolean | undefined;
221
- disabled: boolean | undefined;
222
- ignoreNonKeyboardFocus: boolean | undefined;
223
- onOpenChangeComplete: OnChangeFn<boolean>;
224
- tether: TooltipTether<unknown> | undefined;
225
- }>,
226
- WritableBoxedValues<{
227
- open: boolean;
228
- triggerId: string | null;
229
- }> {}
215
+ interface TooltipRootStateOpts {
216
+ readonly delayDuration: number | undefined;
217
+ readonly disableHoverableContent: boolean | undefined;
218
+ readonly disableCloseOnTriggerClick: boolean | undefined;
219
+ readonly disabled: boolean | undefined;
220
+ readonly ignoreNonKeyboardFocus: boolean | undefined;
221
+ readonly onOpenChangeComplete: OnChangeFn<boolean>;
222
+ readonly tether: TooltipTether<unknown> | undefined;
223
+ open: boolean;
224
+ triggerId: string | null;
225
+ }
230
226
 
231
227
  export class TooltipRootState {
232
228
  static create(opts: TooltipRootStateOpts) {
@@ -234,16 +230,16 @@ export class TooltipRootState {
234
230
  }
235
231
  readonly opts: TooltipRootStateOpts;
236
232
  readonly provider: TooltipProviderState;
237
- readonly delayDuration = $derived.by(() => this.opts.delayDuration.current ?? this.provider.opts.delayDuration.current);
233
+ readonly delayDuration = $derived.by(() => this.opts.delayDuration ?? this.provider.opts.delayDuration);
238
234
  readonly disableHoverableContent = $derived.by(
239
- () => this.opts.disableHoverableContent.current ?? this.provider.opts.disableHoverableContent.current,
235
+ () => this.opts.disableHoverableContent ?? this.provider.opts.disableHoverableContent,
240
236
  );
241
237
  readonly disableCloseOnTriggerClick = $derived.by(
242
- () => this.opts.disableCloseOnTriggerClick.current ?? this.provider.opts.disableCloseOnTriggerClick.current,
238
+ () => this.opts.disableCloseOnTriggerClick ?? this.provider.opts.disableCloseOnTriggerClick,
243
239
  );
244
- readonly disabled = $derived.by(() => this.opts.disabled.current ?? this.provider.opts.disabled.current);
240
+ readonly disabled = $derived.by(() => this.opts.disabled ?? this.provider.opts.disabled);
245
241
  readonly ignoreNonKeyboardFocus = $derived.by(
246
- () => this.opts.ignoreNonKeyboardFocus.current ?? this.provider.opts.ignoreNonKeyboardFocus.current,
242
+ () => this.opts.ignoreNonKeyboardFocus ?? this.provider.opts.ignoreNonKeyboardFocus,
247
243
  );
248
244
  readonly registry: TooltipTriggerRegistryState;
249
245
  readonly tether: TooltipTetherState | null;
@@ -251,19 +247,19 @@ export class TooltipRootState {
251
247
  #wasOpenDelayed = $state(false);
252
248
  readonly #timerFn: ReturnType<typeof createEffectTimeout<() => void>>;
253
249
  readonly stateAttr = $derived.by(() => {
254
- if (!this.opts.open.current) return 'closed';
250
+ if (!this.opts.open) return 'closed';
255
251
  return this.#wasOpenDelayed ? 'delayed-open' : 'instant-open';
256
252
  });
257
253
 
258
254
  constructor(opts: TooltipRootStateOpts, provider: TooltipProviderState) {
259
255
  this.opts = opts;
260
256
  this.provider = provider;
261
- this.tether = opts.tether.current?.state ?? null;
257
+ this.tether = opts.tether?.state ?? null;
262
258
  this.registry = this.tether?.registry ?? new TooltipTriggerRegistryState();
263
259
  this.#timerFn = createEffectTimeout(
264
260
  () => {
265
261
  this.#wasOpenDelayed = true;
266
- this.opts.open.current = true;
262
+ this.opts.open = true;
267
263
  },
268
264
  () => this.delayDuration ?? 0,
269
265
  );
@@ -281,7 +277,7 @@ export class TooltipRootState {
281
277
 
282
278
  let openStarted = false;
283
279
  $effect(() => {
284
- const isOpen = this.opts.open.current;
280
+ const isOpen = this.opts.open;
285
281
  if (!openStarted) {
286
282
  openStarted = true;
287
283
  return;
@@ -297,7 +293,7 @@ export class TooltipRootState {
297
293
  });
298
294
 
299
295
  $effect(() => {
300
- const triggerId = this.opts.triggerId.current;
296
+ const triggerId = this.opts.triggerId;
301
297
  untrack(() => {
302
298
  if (triggerId === this.registry.activeTriggerId) return;
303
299
  this.registry.setActiveTrigger(triggerId);
@@ -307,8 +303,8 @@ export class TooltipRootState {
307
303
  $effect(() => {
308
304
  const activeTriggerId = this.registry.activeTriggerId;
309
305
  untrack(() => {
310
- if (this.opts.triggerId.current === activeTriggerId) return;
311
- this.opts.triggerId.current = activeTriggerId;
306
+ if (this.opts.triggerId === activeTriggerId) return;
307
+ this.opts.triggerId = activeTriggerId;
312
308
  });
313
309
  });
314
310
  }
@@ -317,12 +313,12 @@ export class TooltipRootState {
317
313
  this.#timerFn.stop();
318
314
  this.#wasOpenDelayed = false;
319
315
  this.ensureActiveTrigger();
320
- this.opts.open.current = true;
316
+ this.opts.open = true;
321
317
  };
322
318
 
323
319
  handleClose = () => {
324
320
  this.#timerFn.stop();
325
- this.opts.open.current = false;
321
+ this.opts.open = false;
326
322
  };
327
323
 
328
324
  #handleDelayedOpen = () => {
@@ -334,7 +330,7 @@ export class TooltipRootState {
334
330
  // if no delay needed (either skip delay active or delay is 0), open immediately
335
331
  if (shouldSkipDelay || delayDuration === 0) {
336
332
  this.#wasOpenDelayed = false;
337
- this.opts.open.current = true;
333
+ this.opts.open = true;
338
334
  } else {
339
335
  // use timer for actual delays
340
336
  this.#timerFn.start();
@@ -359,8 +355,8 @@ export class TooltipRootState {
359
355
  return;
360
356
  }
361
357
 
362
- if (this.opts.triggerId.current !== null && this.registry.has(this.opts.triggerId.current)) {
363
- this.registry.setActiveTrigger(this.opts.triggerId.current);
358
+ if (this.opts.triggerId !== null && this.registry.has(this.opts.triggerId)) {
359
+ this.registry.setActiveTrigger(this.opts.triggerId);
364
360
  return;
365
361
  }
366
362
 
@@ -375,7 +371,7 @@ export class TooltipRootState {
375
371
  registerTrigger = (trigger: TooltipTriggerRecord) => {
376
372
  this.registry.register(trigger);
377
373
 
378
- if (trigger.disabled && this.registry.activeTriggerId === trigger.id && this.opts.open.current) {
374
+ if (trigger.disabled && this.registry.activeTriggerId === trigger.id && this.opts.open) {
379
375
  this.handleClose();
380
376
  }
381
377
  };
@@ -383,7 +379,7 @@ export class TooltipRootState {
383
379
  updateTrigger = (trigger: TooltipTriggerRecord) => {
384
380
  this.registry.update(trigger);
385
381
 
386
- if (trigger.disabled && this.registry.activeTriggerId === trigger.id && this.opts.open.current) {
382
+ if (trigger.disabled && this.registry.activeTriggerId === trigger.id && this.opts.open) {
387
383
  this.handleClose();
388
384
  }
389
385
  };
@@ -392,7 +388,7 @@ export class TooltipRootState {
392
388
  const isActive = this.registry.activeTriggerId === id;
393
389
  this.registry.unregister(id);
394
390
 
395
- if (isActive && this.opts.open.current) {
391
+ if (isActive && this.opts.open) {
396
392
  this.handleClose();
397
393
  }
398
394
  };
@@ -414,20 +410,18 @@ export class TooltipRootState {
414
410
  }
415
411
  }
416
412
 
417
- interface TooltipTriggerStateOpts
418
- extends
419
- WithRefOpts,
420
- ReadableBoxedValues<{
421
- disabled: boolean;
422
- tabindex: number;
423
- payload: unknown;
424
- tether: TooltipTether<unknown> | undefined;
425
- }> {}
413
+ interface TooltipTriggerStateOpts extends RefOpts {
414
+ readonly disabled: boolean;
415
+ readonly tabindex: number;
416
+ readonly payload: unknown;
417
+ readonly tether: TooltipTether<unknown> | undefined;
418
+ }
426
419
 
427
420
  export class TooltipTriggerState {
428
421
  static create(opts: TooltipTriggerStateOpts) {
429
- if (opts.tether.current) {
430
- return new TooltipTriggerState(opts, null, opts.tether.current.state);
422
+ const tether = opts.tether;
423
+ if (tether) {
424
+ return new TooltipTriggerState(opts, null, tether.state);
431
425
  }
432
426
  return new TooltipTriggerState(opts, getTooltipRoot(), null);
433
427
  }
@@ -445,31 +439,34 @@ export class TooltipTriggerState {
445
439
  this.opts = opts;
446
440
  this.root = root;
447
441
  this.tether = tether;
448
- this.domContext = new DOMContext(opts.ref);
449
- this.attachment = attachRef(this.opts.ref, (v) => this.#register(v));
442
+ this.domContext = new DOMContext(() => opts.ref);
443
+ this.attachment = attachRef<HTMLElement>(
444
+ (v) => (opts.ref = v),
445
+ (v) => this.#register(v),
446
+ );
450
447
 
451
448
  $effect(() => {
452
- const _id = this.opts.id.current;
449
+ const _id = this.opts.id;
453
450
  untrack(() => {
454
- this.#register(this.opts.ref.current);
451
+ this.#register(this.opts.ref);
455
452
  });
456
453
  });
457
454
  $effect(() => {
458
- const _payload = this.opts.payload.current;
455
+ const _payload = this.opts.payload;
459
456
  untrack(() => {
460
- this.#register(this.opts.ref.current);
457
+ this.#register(this.opts.ref);
461
458
  });
462
459
  });
463
460
  $effect(() => {
464
- const _disabled = this.opts.disabled.current;
461
+ const _disabled = this.opts.disabled;
465
462
  untrack(() => {
466
- this.#register(this.opts.ref.current);
463
+ this.#register(this.opts.ref);
467
464
  });
468
465
  });
469
466
 
470
467
  onMount(() => {
471
468
  this.#mounted = true;
472
- this.#register(this.opts.ref.current);
469
+ this.#register(this.opts.ref);
473
470
 
474
471
  return () => {
475
472
  const root = this.#getRoot();
@@ -493,14 +490,14 @@ export class TooltipTriggerState {
493
490
 
494
491
  #isDisabled = () => {
495
492
  const root = this.#getRoot();
496
- return this.opts.disabled.current || Boolean(root?.disabled);
493
+ return this.opts.disabled || Boolean(root?.disabled);
497
494
  };
498
495
 
499
496
  #register = (node: HTMLElement | null) => {
500
497
  if (!this.#mounted) return;
501
- const id = this.opts.id.current;
502
- const payload = this.opts.payload.current;
503
- const disabled = this.opts.disabled.current;
498
+ const id = this.opts.id;
499
+ const payload = this.opts.payload;
500
+ const disabled = this.opts.disabled;
504
501
 
505
502
  if (this.#lastRegisteredId && this.#lastRegisteredId !== id) {
506
503
  const root = this.#getRoot();
@@ -526,7 +523,7 @@ export class TooltipTriggerState {
526
523
  this.tether.registry.register(triggerRecord);
527
524
  }
528
525
 
529
- if (disabled && this.tether.registry.activeTriggerId === id && root?.opts.open.current) {
526
+ if (disabled && this.tether.registry.activeTriggerId === id && root?.opts.open) {
530
527
  root.handleClose();
531
528
  }
532
529
  } else {
@@ -567,14 +564,14 @@ export class TooltipTriggerState {
567
564
  const root = this.#getRoot();
568
565
  if (!root) return;
569
566
  if (this.#isDisabled()) {
570
- if (root.opts.open.current) {
567
+ if (root.opts.open) {
571
568
  root.handleClose();
572
569
  }
573
570
  return;
574
571
  }
575
572
  if (e.pointerType === 'touch') return;
576
573
 
577
- root.onTriggerEnter(this.opts.id.current);
574
+ root.onTriggerEnter(this.opts.id);
578
575
  this.#hasPointerMoveOpened = true;
579
576
  };
580
577
 
@@ -582,7 +579,7 @@ export class TooltipTriggerState {
582
579
  const root = this.#getRoot();
583
580
  if (!root) return;
584
581
  if (this.#isDisabled()) {
585
- if (root.opts.open.current) {
582
+ if (root.opts.open) {
586
583
  root.handleClose();
587
584
  }
588
585
  return;
@@ -590,7 +587,7 @@ export class TooltipTriggerState {
590
587
  if (e.pointerType === 'touch') return;
591
588
  if (this.#hasPointerMoveOpened) return;
592
589
 
593
- root.onTriggerEnter(this.opts.id.current);
590
+ root.onTriggerEnter(this.opts.id);
594
591
  this.#hasPointerMoveOpened = true;
595
592
  };
596
593
 
@@ -598,7 +595,7 @@ export class TooltipTriggerState {
598
595
  const root = this.#getRoot();
599
596
  if (!root) return;
600
597
  if (this.#isDisabled()) return;
601
- if (!root.isActiveTrigger(this.opts.id.current)) {
598
+ if (!root.isActiveTrigger(this.opts.id)) {
602
599
  this.#hasPointerMoveOpened = false;
603
600
  return;
604
601
  }
@@ -611,7 +608,7 @@ export class TooltipTriggerState {
611
608
  if (isElement(relatedTarget)) {
612
609
  for (const record of root.registry.triggers.values()) {
613
610
  if (record.node !== relatedTarget) continue;
614
- if (root.provider.opts.skipDelayDuration.current > 0) {
611
+ if (root.provider.opts.skipDelayDuration > 0) {
615
612
  this.#hasPointerMoveOpened = false;
616
613
  return;
617
614
  }
@@ -630,14 +627,14 @@ export class TooltipTriggerState {
630
627
  if (!root) return;
631
628
  if (this.#isPointerDown) return;
632
629
  if (this.#isDisabled()) {
633
- if (root.opts.open.current) {
630
+ if (root.opts.open) {
634
631
  root.handleClose();
635
632
  }
636
633
  return;
637
634
  }
638
635
 
639
636
  if (root.ignoreNonKeyboardFocus && !e.currentTarget.matches(':focus-visible')) return;
640
- root.setActiveTrigger(this.opts.id.current);
637
+ root.setActiveTrigger(this.opts.id);
641
638
  root.handleOpen();
642
639
  };
643
640
 
@@ -655,18 +652,18 @@ export class TooltipTriggerState {
655
652
 
656
653
  readonly props = $derived.by(() => {
657
654
  const root = this.#getRoot();
658
- const isOpenForTrigger = Boolean(root?.opts.open.current && root.isActiveTrigger(this.opts.id.current));
655
+ const isOpenForTrigger = Boolean(root?.opts.open && root.isActiveTrigger(this.opts.id));
659
656
  const isDisabled = this.#isDisabled();
660
657
 
661
658
  return {
662
- id: this.opts.id.current,
659
+ id: this.opts.id,
663
660
  'aria-describedby': isOpenForTrigger ? root?.contentNode?.id : undefined,
664
661
  'data-state': isOpenForTrigger ? root?.stateAttr : 'closed',
665
662
  'data-disabled': boolToEmptyStrOrUndef(isDisabled),
666
663
  'data-delay-duration': `${root?.delayDuration ?? 0}`,
667
664
  [tooltipAttrs.trigger]: '',
668
- tabindex: isDisabled ? undefined : this.opts.tabindex.current,
669
- disabled: this.opts.disabled.current,
665
+ tabindex: isDisabled ? undefined : this.opts.tabindex,
666
+ disabled: this.opts.disabled,
670
667
  onpointerup: this.#onpointerup,
671
668
  onpointerdown: this.#onpointerdown,
672
669
  onpointerenter: this.#onpointerenter,
@@ -680,13 +677,10 @@ export class TooltipTriggerState {
680
677
  });
681
678
  }
682
679
 
683
- interface TooltipContentStateOpts
684
- extends
685
- WithRefOpts,
686
- ReadableBoxedValues<{
687
- onInteractOutside: (e: PointerEvent) => void;
688
- onEscapeKeydown: (e: KeyboardEvent) => void;
689
- }> {}
680
+ interface TooltipContentStateOpts extends RefOpts {
681
+ readonly onInteractOutside: (e: PointerEvent) => void;
682
+ readonly onEscapeKeydown: (e: KeyboardEvent) => void;
683
+ }
690
684
 
691
685
  export class TooltipContentState {
692
686
  static create(opts: TooltipContentStateOpts) {
@@ -698,17 +692,20 @@ export class TooltipContentState {
698
692
  constructor(opts: TooltipContentStateOpts, root: TooltipRootState) {
699
693
  this.opts = opts;
700
694
  this.root = root;
701
- this.attachment = attachRef(this.opts.ref, (v) => (this.root.contentNode = v));
695
+ this.attachment = attachRef<HTMLElement>(
696
+ (v) => (opts.ref = v),
697
+ (v) => (this.root.contentNode = v),
698
+ );
702
699
 
703
700
  new SafePolygon({
704
701
  triggerNode: () => this.root.triggerNode,
705
702
  contentNode: () => this.root.contentNode,
706
- enabled: () => this.root.opts.open.current && !this.root.disableHoverableContent,
703
+ enabled: () => this.root.opts.open && !this.root.disableHoverableContent,
707
704
  transitIntentTimeout: 180,
708
705
  ignoredTargets: () => {
709
706
  // only skip closing for sibling triggers when there's a skip-delay grace period;
710
707
  // with skipDelayDuration=0 the close+reopen is intentional (full delay + re-animation)
711
- if (this.root.provider.opts.skipDelayDuration.current === 0) return [];
708
+ if (this.root.provider.opts.skipDelayDuration === 0) return [];
712
709
  const nodes: HTMLElement[] = [];
713
710
  const activeTriggerNode = this.root.triggerNode;
714
711
  for (const record of this.root.registry.triggers.values()) {
@@ -731,13 +728,13 @@ export class TooltipContentState {
731
728
  e.preventDefault();
732
729
  return;
733
730
  }
734
- this.opts.onInteractOutside.current(e);
731
+ this.opts.onInteractOutside(e);
735
732
  if (e.defaultPrevented) return;
736
733
  this.root.handleClose();
737
734
  };
738
735
 
739
736
  onEscapeKeydown = (e: KeyboardEvent) => {
740
- this.opts.onEscapeKeydown.current?.(e);
737
+ this.opts.onEscapeKeydown?.(e);
741
738
  if (e.defaultPrevented) return;
742
739
  this.root.handleClose();
743
740
  };
@@ -750,12 +747,12 @@ export class TooltipContentState {
750
747
  e.preventDefault();
751
748
  };
752
749
 
753
- readonly snippetProps = $derived.by(() => ({ open: this.root.opts.open.current }));
750
+ readonly snippetProps = $derived.by(() => ({ open: this.root.opts.open }));
754
751
 
755
752
  readonly props = $derived.by(
756
753
  () =>
757
754
  ({
758
- id: this.opts.id.current,
755
+ id: this.opts.id,
759
756
  'data-state': this.root.stateAttr,
760
757
  'data-disabled': boolToEmptyStrOrUndef(this.root.disabled),
761
758
  style: {