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,11 +1,5 @@
1
1
  import { createContext, untrack } from 'svelte';
2
- import {
3
- type ReadableBox,
4
- type ReadableBoxedValues,
5
- type WritableBoxedValues,
6
- attachRef,
7
- boxWith,
8
- } from '../../internal/tools/index.js';
2
+ import { attachRef } from '../../internal/tools/index.js';
9
3
  import { kbd } from '../../internal/kbd.js';
10
4
  import { createBitsAttrs, boolToStr, getDataOpenClosed } from '../../internal/attrs.js';
11
5
  import type {
@@ -15,7 +9,7 @@ import type {
15
9
  BitsPointerEvent,
16
10
  OnChangeFn,
17
11
  RefAttachment,
18
- WithRefOpts,
12
+ RefOpts,
19
13
  } from '../../internal/types.js';
20
14
  import { isElement } from '../../internal/tools/utils/dom.js';
21
15
  import type { Measurable } from '../../internal/floating-layer/index.js';
@@ -30,14 +24,10 @@ const popoverAttrs = createBitsAttrs({
30
24
 
31
25
  const [getPopoverRoot, setPopoverRoot] = createContext<PopoverRootState>();
32
26
 
33
- interface PopoverRootStateOpts
34
- extends
35
- WritableBoxedValues<{
36
- open: boolean;
37
- }>,
38
- ReadableBoxedValues<{
39
- onOpenChangeComplete: OnChangeFn<boolean>;
40
- }> {}
27
+ interface PopoverRootStateOpts {
28
+ open: boolean;
29
+ readonly onOpenChangeComplete: OnChangeFn<boolean>;
30
+ }
41
31
 
42
32
  export class PopoverRootState {
43
33
  static create(opts: PopoverRootStateOpts) {
@@ -52,11 +42,11 @@ export class PopoverRootState {
52
42
  openedViaHover = $state(false);
53
43
  hasInteractedWithContent = $state(false);
54
44
  hoverCooldown = $state(false);
55
- #closeDelaySource = $state<ReadableBox<number>>(boxWith(() => 0));
56
- closeDelay = $derived.by(() => this.#closeDelaySource.current);
45
+ // The trigger installs its closeDelay here; a getter so the read tracks the trigger's prop.
46
+ #closeDelaySource: () => number = $state.raw(() => 0);
57
47
  #closeTimer = createEffectTimeout(() => {
58
48
  if (this.openedViaHover && !this.hasInteractedWithContent) {
59
- this.opts.open.current = false;
49
+ this.opts.open = false;
60
50
  }
61
51
  }, () => this.closeDelay);
62
52
 
@@ -64,7 +54,7 @@ export class PopoverRootState {
64
54
  this.opts = opts;
65
55
 
66
56
  $effect(() => {
67
- const isOpen = this.opts.open.current;
57
+ const isOpen = this.opts.open;
68
58
  untrack(() => {
69
59
  if (!isOpen) {
70
60
  this.openedViaHover = false;
@@ -75,43 +65,47 @@ export class PopoverRootState {
75
65
  });
76
66
  }
77
67
 
78
- setCloseDelaySource(source: ReadableBox<number>) {
68
+ get closeDelay() {
69
+ return this.#closeDelaySource();
70
+ }
71
+
72
+ setCloseDelaySource(source: () => number) {
79
73
  this.#closeDelaySource = source;
80
74
  }
81
75
 
82
76
  toggleOpen() {
83
77
  this.#closeTimer.stop();
84
- this.opts.open.current = !this.opts.open.current;
78
+ this.opts.open = !this.opts.open;
85
79
  }
86
80
 
87
81
  handleClose() {
88
82
  this.#closeTimer.stop();
89
- if (!this.opts.open.current) return;
90
- this.opts.open.current = false;
83
+ if (!this.opts.open) return;
84
+ this.opts.open = false;
91
85
  }
92
86
 
93
87
  handleHoverOpen() {
94
88
  this.#closeTimer.stop();
95
- if (this.opts.open.current) return;
89
+ if (this.opts.open) return;
96
90
  this.openedViaHover = true;
97
- this.opts.open.current = true;
91
+ this.opts.open = true;
98
92
  }
99
93
 
100
94
  handleHoverClose() {
101
- if (!this.opts.open.current) return;
95
+ if (!this.opts.open) return;
102
96
  // only close if opened via hover and user hasn't interacted with content
103
97
  if (this.openedViaHover && !this.hasInteractedWithContent) {
104
- this.opts.open.current = false;
98
+ this.opts.open = false;
105
99
  }
106
100
  }
107
101
 
108
102
  handleDelayedHoverClose() {
109
- if (!this.opts.open.current) return;
103
+ if (!this.opts.open) return;
110
104
  if (!this.openedViaHover || this.hasInteractedWithContent) return;
111
105
 
112
106
  if (this.closeDelay <= 0) {
113
107
  this.#closeTimer.stop();
114
- this.opts.open.current = false;
108
+ this.opts.open = false;
115
109
  return;
116
110
  }
117
111
 
@@ -128,15 +122,12 @@ export class PopoverRootState {
128
122
  }
129
123
  }
130
124
 
131
- interface PopoverTriggerStateOpts
132
- extends
133
- WithRefOpts,
134
- ReadableBoxedValues<{
135
- disabled: boolean;
136
- openOnHover: boolean;
137
- openDelay: number;
138
- closeDelay: number;
139
- }> {}
125
+ interface PopoverTriggerStateOpts extends RefOpts {
126
+ readonly disabled: boolean;
127
+ readonly openOnHover: boolean;
128
+ readonly openDelay: number;
129
+ readonly closeDelay: number;
130
+ }
140
131
 
141
132
  export class PopoverTriggerState {
142
133
  static create(opts: PopoverTriggerStateOpts) {
@@ -147,14 +138,17 @@ export class PopoverTriggerState {
147
138
  readonly root: PopoverRootState;
148
139
  readonly attachment: RefAttachment;
149
140
 
150
- #openTimer = createEffectTimeout(() => this.root.handleHoverOpen(), () => this.opts.openDelay.current);
141
+ #openTimer = createEffectTimeout(() => this.root.handleHoverOpen(), () => this.opts.openDelay);
151
142
  #isHovering = $state(false);
152
143
  #wasOpenOnPointerDown = false;
153
144
 
154
145
  constructor(opts: PopoverTriggerStateOpts, root: PopoverRootState) {
155
146
  this.opts = opts;
156
147
  this.root = root;
157
- this.attachment = attachRef(this.opts.ref, (v) => (this.root.triggerNode = v));
148
+ this.attachment = attachRef<HTMLElement>(
149
+ (v) => (opts.ref = v),
150
+ (v) => (this.root.triggerNode = v),
151
+ );
158
152
 
159
153
  this.onclick = this.onclick.bind(this);
160
154
  this.onkeydown = this.onkeydown.bind(this);
@@ -162,20 +156,20 @@ export class PopoverTriggerState {
162
156
  this.onpointerenter = this.onpointerenter.bind(this);
163
157
  this.onpointerleave = this.onpointerleave.bind(this);
164
158
 
165
- this.root.setCloseDelaySource(this.opts.closeDelay);
159
+ this.root.setCloseDelaySource(() => opts.closeDelay);
166
160
  }
167
161
 
168
162
  onpointerenter(e: BitsPointerEvent) {
169
- if (this.opts.disabled.current) return;
170
- if (!this.opts.openOnHover.current) return;
163
+ if (this.opts.disabled) return;
164
+ if (!this.opts.openOnHover) return;
171
165
  if (e.pointerType === 'touch') return;
172
166
 
173
167
  this.#isHovering = true;
174
168
  this.root.cancelDelayedClose();
175
169
 
176
- if (this.root.opts.open.current || this.root.hoverCooldown) return;
170
+ if (this.root.opts.open || this.root.hoverCooldown) return;
177
171
 
178
- if (this.opts.openDelay.current <= 0) {
172
+ if (this.opts.openDelay <= 0) {
179
173
  this.root.handleHoverOpen();
180
174
  return;
181
175
  }
@@ -184,8 +178,8 @@ export class PopoverTriggerState {
184
178
  }
185
179
 
186
180
  onpointerleave(e: BitsPointerEvent) {
187
- if (this.opts.disabled.current) return;
188
- if (!this.opts.openOnHover.current) return;
181
+ if (this.opts.disabled) return;
182
+ if (!this.opts.openOnHover) return;
189
183
  if (e.pointerType === 'touch') return;
190
184
 
191
185
  this.#isHovering = false;
@@ -197,24 +191,24 @@ export class PopoverTriggerState {
197
191
  }
198
192
 
199
193
  onpointerdown(_: BitsPointerEvent) {
200
- this.#wasOpenOnPointerDown = this.root.opts.open.current;
194
+ this.#wasOpenOnPointerDown = this.root.opts.open;
201
195
  }
202
196
 
203
197
  onclick(e: BitsMouseEvent) {
204
- if (this.opts.disabled.current) return;
198
+ if (this.opts.disabled) return;
205
199
  if (e.button !== 0) return;
206
200
 
207
201
  this.#openTimer.stop();
208
202
 
209
203
  // On engines without showPopover({source})'s invoker exemption, the UA light-dismisses the auto
210
204
  // popover at pointerdown — before this click — and the toggle below would instantly reopen it.
211
- if (this.#wasOpenOnPointerDown && !this.root.opts.open.current) {
205
+ if (this.#wasOpenOnPointerDown && !this.root.opts.open) {
212
206
  this.#wasOpenOnPointerDown = false;
213
207
  return;
214
208
  }
215
209
 
216
210
  // if clicked while hovering and popover is open, convert to click-based open
217
- if (this.#isHovering && this.root.opts.open.current && this.root.openedViaHover) {
211
+ if (this.#isHovering && this.root.opts.open && this.root.openedViaHover) {
218
212
  this.root.openedViaHover = false;
219
213
  this.root.hasInteractedWithContent = true;
220
214
  return;
@@ -222,12 +216,12 @@ export class PopoverTriggerState {
222
216
 
223
217
  // if closing while hovering with openOnHover enabled, set cooldown to prevent
224
218
  // immediate re-open via hover
225
- if (this.#isHovering && this.opts.openOnHover.current && this.root.opts.open.current) {
219
+ if (this.#isHovering && this.opts.openOnHover && this.root.opts.open) {
226
220
  this.root.hoverCooldown = true;
227
221
  }
228
222
 
229
223
  // if clicking to open while in cooldown, reset cooldown (explicit open)
230
- if (this.root.hoverCooldown && !this.root.opts.open.current) {
224
+ if (this.root.hoverCooldown && !this.root.opts.open) {
231
225
  this.root.hoverCooldown = false;
232
226
  }
233
227
 
@@ -235,7 +229,7 @@ export class PopoverTriggerState {
235
229
  }
236
230
 
237
231
  onkeydown(e: BitsKeyboardEvent) {
238
- if (this.opts.disabled.current) return;
232
+ if (this.opts.disabled) return;
239
233
  if (!(e.key === kbd.ENTER || e.key === kbd.SPACE)) return;
240
234
  e.preventDefault();
241
235
  this.#openTimer.stop();
@@ -243,7 +237,7 @@ export class PopoverTriggerState {
243
237
  }
244
238
 
245
239
  #getAriaControls(): string | undefined {
246
- if (this.root.opts.open.current && this.root.contentNode?.id) {
240
+ if (this.root.opts.open && this.root.contentNode?.id) {
247
241
  return this.root.contentNode?.id;
248
242
  }
249
243
  }
@@ -251,13 +245,13 @@ export class PopoverTriggerState {
251
245
  readonly props = $derived.by(
252
246
  () =>
253
247
  ({
254
- id: this.opts.id.current,
248
+ id: this.opts.id,
255
249
  'aria-haspopup': 'dialog',
256
- 'aria-expanded': boolToStr(this.root.opts.open.current),
257
- 'data-state': getDataOpenClosed(this.root.opts.open.current),
250
+ 'aria-expanded': boolToStr(this.root.opts.open),
251
+ 'data-state': getDataOpenClosed(this.root.opts.open),
258
252
  'aria-controls': this.#getAriaControls(),
259
253
  [popoverAttrs.trigger]: '',
260
- disabled: this.opts.disabled.current,
254
+ disabled: this.opts.disabled,
261
255
  //
262
256
  onkeydown: this.onkeydown,
263
257
  onclick: this.onclick,
@@ -269,12 +263,9 @@ export class PopoverTriggerState {
269
263
  );
270
264
  }
271
265
 
272
- interface PopoverContentStateOpts
273
- extends
274
- WithRefOpts,
275
- ReadableBoxedValues<{
276
- customAnchor: string | HTMLElement | null | Measurable;
277
- }> {}
266
+ interface PopoverContentStateOpts extends RefOpts {
267
+ readonly customAnchor: string | HTMLElement | null | Measurable;
268
+ }
278
269
 
279
270
  export class PopoverContentState {
280
271
  static create(opts: PopoverContentStateOpts) {
@@ -288,7 +279,10 @@ export class PopoverContentState {
288
279
  constructor(opts: PopoverContentStateOpts, root: PopoverRootState) {
289
280
  this.opts = opts;
290
281
  this.root = root;
291
- this.attachment = attachRef(this.opts.ref, (v) => (this.root.contentNode = v));
282
+ this.attachment = attachRef<HTMLElement>(
283
+ (v) => (opts.ref = v),
284
+ (v) => (this.root.contentNode = v),
285
+ );
292
286
 
293
287
  this.onpointerdown = this.onpointerdown.bind(this);
294
288
  this.onfocusin = this.onfocusin.bind(this);
@@ -298,7 +292,7 @@ export class PopoverContentState {
298
292
  new SafePolygon({
299
293
  triggerNode: () => this.root.triggerNode,
300
294
  contentNode: () => this.root.contentNode,
301
- enabled: () => this.root.opts.open.current && this.root.openedViaHover && !this.root.hasInteractedWithContent,
295
+ enabled: () => this.root.opts.open && this.root.openedViaHover && !this.root.hasInteractedWithContent,
302
296
  onPointerExit: () => {
303
297
  this.root.handleDelayedHoverClose();
304
298
  },
@@ -331,14 +325,14 @@ export class PopoverContentState {
331
325
  this.root.handleClose();
332
326
  };
333
327
 
334
- readonly snippetProps = $derived.by(() => ({ open: this.root.opts.open.current }));
328
+ readonly snippetProps = $derived.by(() => ({ open: this.root.opts.open }));
335
329
 
336
330
  readonly props = $derived.by(
337
331
  () =>
338
332
  ({
339
- id: this.opts.id.current,
333
+ id: this.opts.id,
340
334
  tabindex: -1,
341
- 'data-state': getDataOpenClosed(this.root.opts.open.current),
335
+ 'data-state': getDataOpenClosed(this.root.opts.open),
342
336
  [popoverAttrs.content]: '',
343
337
  onpointerdown: this.onpointerdown,
344
338
  onfocusin: this.onfocusin,
@@ -349,7 +343,7 @@ export class PopoverContentState {
349
343
  );
350
344
  }
351
345
 
352
- interface PopoverCloseStateOpts extends WithRefOpts {}
346
+ interface PopoverCloseStateOpts extends RefOpts {}
353
347
 
354
348
  export class PopoverCloseState {
355
349
  static create(opts: PopoverCloseStateOpts) {
@@ -363,7 +357,7 @@ export class PopoverCloseState {
363
357
  constructor(opts: PopoverCloseStateOpts, root: PopoverRootState) {
364
358
  this.opts = opts;
365
359
  this.root = root;
366
- this.attachment = attachRef(this.opts.ref);
360
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
367
361
  this.onclick = this.onclick.bind(this);
368
362
  this.onkeydown = this.onkeydown.bind(this);
369
363
  }
@@ -381,7 +375,7 @@ export class PopoverCloseState {
381
375
  readonly props = $derived.by(
382
376
  () =>
383
377
  ({
384
- id: this.opts.id.current,
378
+ id: this.opts.id,
385
379
  onclick: this.onclick,
386
380
  onkeydown: this.onkeydown,
387
381
  type: 'button',
@@ -1,5 +1,4 @@
1
1
  <script lang="ts">
2
- import { boxWith } from '../../../internal/tools/index.js';
3
2
  import { mergeProps } from '../../../internal/merge-props.js';
4
3
  import type { ProgressRootProps } from '../types.js';
5
4
  import { getProgressPercent, ProgressRootState } from '../progress.svelte.js';
@@ -19,14 +18,24 @@
19
18
  }: ProgressRootProps = $props();
20
19
 
21
20
  const rootState = ProgressRootState.create({
22
- value: boxWith(() => value),
23
- max: boxWith(() => max),
24
- min: boxWith(() => min),
25
- id: boxWith(() => id),
26
- ref: boxWith(
27
- () => ref,
28
- (v) => (ref = v),
29
- ),
21
+ get value() {
22
+ return value;
23
+ },
24
+ get max() {
25
+ return max;
26
+ },
27
+ get min() {
28
+ return min;
29
+ },
30
+ get id() {
31
+ return id;
32
+ },
33
+ get ref() {
34
+ return ref;
35
+ },
36
+ set ref(v) {
37
+ ref = v;
38
+ },
30
39
  });
31
40
 
32
41
  const mergedProps = $derived(
@@ -1,6 +1,6 @@
1
- import { attachRef, type ReadableBoxedValues } from '../../internal/tools/index.js';
1
+ import { attachRef } from '../../internal/tools/index.js';
2
2
  import { createBitsAttrs } from '../../internal/attrs.js';
3
- import type { RefAttachment, WithRefOpts } from '../../internal/types.js';
3
+ import type { RefAttachment, RefOpts } from '../../internal/types.js';
4
4
 
5
5
  const progressAttrs = createBitsAttrs({
6
6
  component: 'progress',
@@ -14,14 +14,11 @@ export function getProgressPercent(value: number | null, min: number, max: numbe
14
14
  return Math.min(100, Math.max(0, ((value - min) / range) * 100));
15
15
  }
16
16
 
17
- interface ProgressRootStateOpts
18
- extends
19
- WithRefOpts,
20
- ReadableBoxedValues<{
21
- value: number | null;
22
- max: number;
23
- min: number;
24
- }> {}
17
+ interface ProgressRootStateOpts extends RefOpts {
18
+ readonly value: number | null;
19
+ readonly max: number;
20
+ readonly min: number;
21
+ }
25
22
 
26
23
  export class ProgressRootState {
27
24
  static create(opts: ProgressRootStateOpts) {
@@ -33,23 +30,23 @@ export class ProgressRootState {
33
30
 
34
31
  constructor(opts: ProgressRootStateOpts) {
35
32
  this.opts = opts;
36
- this.attachment = attachRef(this.opts.ref);
33
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
37
34
  }
38
35
 
39
36
  readonly props = $derived.by(() => {
40
- const value = this.opts.value.current;
41
- const percent = getProgressPercent(value, this.opts.min.current, this.opts.max.current);
37
+ const { value, min, max } = this.opts;
38
+ const percent = getProgressPercent(value, min, max);
42
39
  const isIndeterminate = value === null;
43
40
  return {
44
41
  role: 'progressbar',
45
42
  value,
46
- 'aria-valuemin': this.opts.min.current,
47
- 'aria-valuemax': this.opts.max.current,
43
+ 'aria-valuemin': min,
44
+ 'aria-valuemax': max,
48
45
  'aria-valuenow': isIndeterminate ? undefined : value,
49
46
  'data-value': isIndeterminate ? undefined : value,
50
47
  'data-state': value === null ? 'indeterminate' : percent === 100 ? 'loaded' : 'loading',
51
- 'data-max': this.opts.max.current,
52
- 'data-min': this.opts.min.current,
48
+ 'data-max': max,
49
+ 'data-min': min,
53
50
  'data-indeterminate': isIndeterminate ? '' : undefined,
54
51
  [progressAttrs.root]: '',
55
52
  ...this.attachment,
@@ -1,5 +1,4 @@
1
1
  <script lang="ts">
2
- import { boxWith } from '../../../internal/tools/index.js';
3
2
  import { mergeProps } from '../../../internal/merge-props.js';
4
3
  import { SeparatorRootState } from '../separator.svelte.js';
5
4
  import type { SeparatorRootProps } from '../types.js';
@@ -18,13 +17,21 @@
18
17
  }: SeparatorRootProps = $props();
19
18
 
20
19
  const rootState = SeparatorRootState.create({
21
- ref: boxWith(
22
- () => ref,
23
- (v) => (ref = v),
24
- ),
25
- id: boxWith(() => id),
26
- decorative: boxWith(() => decorative),
27
- orientation: boxWith(() => orientation),
20
+ get id() {
21
+ return id;
22
+ },
23
+ get decorative() {
24
+ return decorative;
25
+ },
26
+ get orientation() {
27
+ return orientation;
28
+ },
29
+ get ref() {
30
+ return ref;
31
+ },
32
+ set ref(v) {
33
+ ref = v;
34
+ },
28
35
  });
29
36
 
30
37
  const mergedProps = $derived(
@@ -1,6 +1,6 @@
1
- import { attachRef, type ReadableBoxedValues } from '../../internal/tools/index.js';
1
+ import { attachRef } from '../../internal/tools/index.js';
2
2
  import { createBitsAttrs, boolToStrTrueOrUndef } from '../../internal/attrs.js';
3
- import type { RefAttachment, WithRefOpts } from '../../internal/types.js';
3
+ import type { RefAttachment, RefOpts } from '../../internal/types.js';
4
4
  import type { Orientation } from '../../internal/index.js';
5
5
 
6
6
  const separatorAttrs = createBitsAttrs({
@@ -8,13 +8,10 @@ const separatorAttrs = createBitsAttrs({
8
8
  parts: ['root'],
9
9
  });
10
10
 
11
- interface SeparatorRootStateOpts
12
- extends
13
- WithRefOpts,
14
- ReadableBoxedValues<{
15
- orientation: Orientation;
16
- decorative: boolean;
17
- }> {}
11
+ interface SeparatorRootStateOpts extends RefOpts {
12
+ readonly orientation: Orientation;
13
+ readonly decorative: boolean;
14
+ }
18
15
 
19
16
  export class SeparatorRootState {
20
17
  static create(opts: SeparatorRootStateOpts) {
@@ -25,17 +22,17 @@ export class SeparatorRootState {
25
22
 
26
23
  constructor(opts: SeparatorRootStateOpts) {
27
24
  this.opts = opts;
28
- this.attachment = attachRef(opts.ref);
25
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
29
26
  }
30
27
 
31
28
  readonly props = $derived.by(
32
29
  () =>
33
30
  ({
34
- id: this.opts.id.current,
35
- role: this.opts.decorative.current ? 'none' : 'separator',
36
- 'aria-orientation': this.opts.orientation.current,
37
- 'aria-hidden': boolToStrTrueOrUndef(this.opts.decorative.current),
38
- 'data-orientation': this.opts.orientation.current,
31
+ id: this.opts.id,
32
+ role: this.opts.decorative ? 'none' : 'separator',
33
+ 'aria-orientation': this.opts.orientation,
34
+ 'aria-hidden': boolToStrTrueOrUndef(this.opts.decorative),
35
+ 'data-orientation': this.opts.orientation,
39
36
  [separatorAttrs.root]: '',
40
37
  ...this.attachment,
41
38
  }) as const,
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { untrack } from 'svelte';
3
3
  import * as Sheet from '../sheet/index.js';
4
- import { boxWith } from '../../internal/tools/index.js';
5
4
  import { DialogRootState, DialogState } from '../dialog/dialog.svelte.js';
6
5
  import { join } from 'overrule';
7
6
  import { SIDEBAR_WIDTH_MOBILE } from './constants.js';
@@ -32,9 +31,14 @@
32
31
  });
33
32
 
34
33
  DialogRootState.create({
35
- variant: boxWith(() => 'dialog'),
36
- cell: sheetCell,
37
- onOpenChangeComplete: boxWith(() => () => {}),
34
+ variant: 'dialog',
35
+ get open() {
36
+ return sheetCell.open;
37
+ },
38
+ set open(v) {
39
+ sheetCell.open = v;
40
+ },
41
+ onOpenChangeComplete: () => {},
38
42
  });
39
43
  </script>
40
44
 
@@ -1,5 +1,4 @@
1
1
  <script lang="ts">
2
- import { boxWith } from '../../../internal/tools/index.js';
3
2
  import { mergeProps } from '../../../internal/merge-props.js';
4
3
  import type { ToggleRootProps } from '../types.js';
5
4
  import { ToggleRootState } from '../toggle.svelte.js';
@@ -26,19 +25,25 @@
26
25
  } = $props();
27
26
 
28
27
  const toggleState = ToggleRootState.create({
29
- pressed: boxWith(
30
- () => pressed,
31
- (v) => {
32
- pressed = v;
33
- onPressedChange(v);
34
- },
35
- ),
36
- disabled: boxWith(() => disabled ?? false),
37
- id: boxWith(() => id),
38
- ref: boxWith(
39
- () => ref,
40
- (v) => (ref = v),
41
- ),
28
+ get pressed() {
29
+ return pressed;
30
+ },
31
+ set pressed(v) {
32
+ pressed = v;
33
+ onPressedChange(v);
34
+ },
35
+ get disabled() {
36
+ return disabled ?? false;
37
+ },
38
+ get id() {
39
+ return id;
40
+ },
41
+ get ref() {
42
+ return ref;
43
+ },
44
+ set ref(v) {
45
+ ref = v;
46
+ },
42
47
  });
43
48
 
44
49
  const mergedProps = $derived(
@@ -1,21 +1,16 @@
1
- import { attachRef, type ReadableBoxedValues, type WritableBoxedValues } from '../../internal/tools/index.js';
1
+ import { attachRef } from '../../internal/tools/index.js';
2
2
  import { createBitsAttrs, boolToStr, boolToEmptyStrOrUndef, boolToTrueOrUndef } from '../../internal/attrs.js';
3
- import type { BitsMouseEvent, RefAttachment, WithRefOpts } from '../../internal/types.js';
3
+ import type { BitsMouseEvent, RefAttachment, RefOpts } from '../../internal/types.js';
4
4
 
5
5
  export const toggleAttrs = createBitsAttrs({
6
6
  component: 'toggle',
7
7
  parts: ['root'],
8
8
  });
9
9
 
10
- interface ToggleRootStateOpts
11
- extends
12
- WithRefOpts,
13
- ReadableBoxedValues<{
14
- disabled: boolean;
15
- }>,
16
- WritableBoxedValues<{
17
- pressed: boolean;
18
- }> {}
10
+ interface ToggleRootStateOpts extends RefOpts {
11
+ readonly disabled: boolean;
12
+ pressed: boolean;
13
+ }
19
14
 
20
15
  export class ToggleRootState {
21
16
  static create(opts: ToggleRootStateOpts) {
@@ -26,28 +21,28 @@ export class ToggleRootState {
26
21
 
27
22
  constructor(opts: ToggleRootStateOpts) {
28
23
  this.opts = opts;
29
- this.attachment = attachRef(this.opts.ref);
24
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
30
25
  this.onclick = this.onclick.bind(this);
31
26
  }
32
27
 
33
28
  onclick(_: BitsMouseEvent) {
34
- if (this.opts.disabled.current) return;
35
- this.opts.pressed.current = !this.opts.pressed.current;
29
+ if (this.opts.disabled) return;
30
+ this.opts.pressed = !this.opts.pressed;
36
31
  }
37
32
 
38
33
  readonly snippetProps = $derived.by(() => ({
39
- pressed: this.opts.pressed.current,
34
+ pressed: this.opts.pressed,
40
35
  }));
41
36
 
42
37
  readonly props = $derived.by(
43
38
  () =>
44
39
  ({
45
40
  [toggleAttrs.root]: '',
46
- id: this.opts.id.current,
47
- 'data-disabled': boolToEmptyStrOrUndef(this.opts.disabled.current),
48
- 'aria-pressed': boolToStr(this.opts.pressed.current),
49
- 'data-state': getToggleDataState(this.opts.pressed.current),
50
- disabled: boolToTrueOrUndef(this.opts.disabled.current),
41
+ id: this.opts.id,
42
+ 'data-disabled': boolToEmptyStrOrUndef(this.opts.disabled),
43
+ 'aria-pressed': boolToStr(this.opts.pressed),
44
+ 'data-state': getToggleDataState(this.opts.pressed),
45
+ disabled: boolToTrueOrUndef(this.opts.disabled),
51
46
  onclick: this.onclick,
52
47
  ...this.attachment,
53
48
  }) as const,