sheer-ui 0.4.0 → 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 (96) hide show
  1. package/package.json +1 -1
  2. package/src/lib/components/accordion/components/accordion-item.svelte +3 -3
  3. package/src/lib/components/accordion/components/accordion.svelte +29 -13
  4. package/src/lib/components/accordion/types.ts +3 -3
  5. package/src/lib/components/avatar/avatar.svelte.ts +34 -37
  6. package/src/lib/components/avatar/components/avatar-fallback.svelte +9 -6
  7. package/src/lib/components/avatar/components/avatar-image.svelte +18 -9
  8. package/src/lib/components/avatar/components/avatar.svelte +20 -16
  9. package/src/lib/components/checkbox/checkbox.svelte.ts +45 -55
  10. package/src/lib/components/checkbox/components/checkbox-group-label.svelte +9 -6
  11. package/src/lib/components/checkbox/components/checkbox-group.svelte +25 -14
  12. package/src/lib/components/checkbox/components/checkbox.svelte +39 -21
  13. package/src/lib/components/combobox/components/combobox.svelte +2 -2
  14. package/src/lib/components/combobox/select/components/select.svelte +2 -2
  15. package/src/lib/components/context-menu/components/context-menu-trigger.svelte +1 -1
  16. package/src/lib/components/date-field/date-field.svelte.ts +2 -3
  17. package/src/lib/components/dialog/components/dialog-close.svelte +13 -8
  18. package/src/lib/components/dialog/components/dialog-content-headless.svelte +14 -11
  19. package/src/lib/components/dialog/components/dialog-description.svelte +9 -6
  20. package/src/lib/components/dialog/components/dialog-overlay.svelte +10 -7
  21. package/src/lib/components/dialog/components/dialog-title.svelte +12 -7
  22. package/src/lib/components/dialog/components/dialog-trigger.svelte +12 -7
  23. package/src/lib/components/dialog/components/dialog.svelte +10 -4
  24. package/src/lib/components/dialog/components/modal-surface.svelte +11 -8
  25. package/src/lib/components/dialog/dialog.svelte.ts +73 -61
  26. package/src/lib/components/drawer/drawer.svelte +8 -3
  27. package/src/lib/components/link-preview/components/link-preview-content.svelte +15 -8
  28. package/src/lib/components/link-preview/components/link-preview-trigger.svelte +9 -6
  29. package/src/lib/components/link-preview/components/link-preview.svelte +19 -11
  30. package/src/lib/components/link-preview/link-preview.svelte.ts +42 -43
  31. package/src/lib/components/menu/components/menu-checkbox-group.svelte +6 -4
  32. package/src/lib/components/menu/components/menu-checkbox-item.svelte +11 -7
  33. package/src/lib/components/menu/menu.svelte.ts +29 -19
  34. package/src/lib/components/menubar/menubar.svelte.ts +7 -6
  35. package/src/lib/components/meter/components/meter.svelte +18 -9
  36. package/src/lib/components/meter/meter.svelte.ts +15 -18
  37. package/src/lib/components/navigation-menu/components/navigation-menu-content.svelte +1 -1
  38. package/src/lib/components/navigation-menu/components/navigation-menu-indicator.svelte +2 -2
  39. package/src/lib/components/navigation-menu/components/navigation-menu-trigger.svelte +1 -1
  40. package/src/lib/components/navigation-menu/navigation-menu.svelte.ts +57 -60
  41. package/src/lib/components/pagination/components/pagination-next-button.svelte +12 -7
  42. package/src/lib/components/pagination/components/pagination-page.svelte +15 -8
  43. package/src/lib/components/pagination/components/pagination-prev-button.svelte +12 -7
  44. package/src/lib/components/pagination/components/pagination.svelte +31 -18
  45. package/src/lib/components/pagination/pagination.svelte.ts +48 -64
  46. package/src/lib/components/pin-input/pin-input.svelte.ts +7 -8
  47. package/src/lib/components/pin-input/usePasswordManager.svelte.ts +2 -2
  48. package/src/lib/components/popover/components/popover-close.svelte +9 -6
  49. package/src/lib/components/popover/components/popover-content.svelte +12 -7
  50. package/src/lib/components/popover/components/popover-trigger.svelte +21 -10
  51. package/src/lib/components/popover/components/popover.svelte +9 -8
  52. package/src/lib/components/popover/popover.svelte.ts +68 -74
  53. package/src/lib/components/progress/components/progress.svelte +18 -9
  54. package/src/lib/components/progress/progress.svelte.ts +14 -17
  55. package/src/lib/components/scroll-area/scroll-area.svelte.ts +9 -10
  56. package/src/lib/components/separator/components/separator.svelte +15 -8
  57. package/src/lib/components/separator/separator.svelte.ts +12 -15
  58. package/src/lib/components/sidebar/sidebar-mobile-surface.svelte +8 -4
  59. package/src/lib/components/slider/components/slider.svelte +2 -1
  60. package/src/lib/components/tabs/components/tabs-content.svelte +12 -7
  61. package/src/lib/components/tabs/components/tabs-list.svelte +9 -6
  62. package/src/lib/components/tabs/components/tabs-trigger.svelte +15 -8
  63. package/src/lib/components/tabs/components/tabs.svelte +28 -17
  64. package/src/lib/components/tabs/tabs.svelte.ts +51 -67
  65. package/src/lib/components/time-field/time-field.svelte.ts +2 -2
  66. package/src/lib/components/toggle/components/toggle.svelte +19 -14
  67. package/src/lib/components/toggle/toggle.svelte.ts +15 -20
  68. package/src/lib/components/toggle-group/components/toggle-group-item.svelte +15 -8
  69. package/src/lib/components/toggle-group/components/toggle-group.svelte +28 -16
  70. package/src/lib/components/toggle-group/toggle-group.svelte.ts +33 -35
  71. package/src/lib/components/toolbar/components/toolbar-group-item.svelte +15 -8
  72. package/src/lib/components/toolbar/components/toolbar-group.svelte +19 -14
  73. package/src/lib/components/toolbar/toolbar.svelte.ts +28 -30
  74. package/src/lib/components/tooltip/components/tooltip-content.svelte +15 -8
  75. package/src/lib/components/tooltip/components/tooltip-provider.svelte +18 -7
  76. package/src/lib/components/tooltip/components/tooltip-trigger.svelte +21 -10
  77. package/src/lib/components/tooltip/components/tooltip.svelte +34 -21
  78. package/src/lib/components/tooltip/tooltip.svelte.ts +101 -125
  79. package/src/lib/internal/dismissible-layer/use-dismissable-layer.svelte.ts +3 -4
  80. package/src/lib/internal/escape-layer/use-escape-layer.svelte.ts +13 -29
  81. package/src/lib/internal/floating-layer/use-floating-layer.svelte.ts +26 -30
  82. package/src/lib/internal/group-value.svelte.ts +11 -10
  83. package/src/lib/internal/native-popover.svelte.ts +6 -6
  84. package/src/lib/internal/{roving-focus-group.ts → roving-focus-group.svelte.ts} +17 -19
  85. package/src/lib/internal/roving-focus-item.svelte.ts +12 -17
  86. package/src/lib/internal/selection.svelte.ts +55 -41
  87. package/src/lib/internal/{state-machine.ts → state-machine.svelte.ts} +6 -8
  88. package/src/lib/internal/timeout-fn.svelte.ts +6 -4
  89. package/src/lib/internal/tools/box.svelte.ts +5 -114
  90. package/src/lib/internal/tools/index.ts +1 -11
  91. package/src/lib/internal/tools/types.ts +0 -3
  92. package/src/lib/internal/typeahead.svelte.ts +9 -13
  93. package/src/lib/internal/types.ts +6 -0
  94. package/src/lib/internal/vaul/use-drawer-content.svelte.ts +2 -2
  95. package/src/lib/internal/vaul/use-drawer-root.svelte.ts +12 -7
  96. package/src/lib/components/accordion/accordion.svelte.ts +0 -43
@@ -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 { TabsListProps } from '../types.js';
5
4
  import { TabsListState } from '../tabs.svelte.js';
@@ -10,11 +9,15 @@
10
9
  let { child, children, id = createId(uid), ref = $bindable(null), ...restProps }: TabsListProps = $props();
11
10
 
12
11
  const listState = TabsListState.create({
13
- id: boxWith(() => id),
14
- ref: boxWith(
15
- () => ref,
16
- (v) => (ref = v),
17
- ),
12
+ get id() {
13
+ return id;
14
+ },
15
+ get ref() {
16
+ return ref;
17
+ },
18
+ set ref(v) {
19
+ ref = v;
20
+ },
18
21
  });
19
22
 
20
23
  const mergedProps = $derived(
@@ -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 { TabsTriggerProps } from '../types.js';
5
4
  import { TabsTriggerState } from '../tabs.svelte.js';
@@ -19,13 +18,21 @@
19
18
  }: TabsTriggerProps = $props();
20
19
 
21
20
  const triggerState = TabsTriggerState.create({
22
- id: boxWith(() => id),
23
- disabled: boxWith(() => disabled ?? false),
24
- value: boxWith(() => value),
25
- ref: boxWith(
26
- () => ref,
27
- (v) => (ref = v),
28
- ),
21
+ get id() {
22
+ return id;
23
+ },
24
+ get disabled() {
25
+ return disabled ?? false;
26
+ },
27
+ get value() {
28
+ return value;
29
+ },
30
+ get ref() {
31
+ return ref;
32
+ },
33
+ set ref(v) {
34
+ ref = v;
35
+ },
29
36
  });
30
37
 
31
38
  const mergedProps = $derived(
@@ -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 { TabsRootProps } from '../types.js';
5
4
  import { TabsRootState } from '../tabs.svelte.js';
@@ -22,22 +21,34 @@
22
21
  }: TabsRootProps = $props();
23
22
 
24
23
  const rootState = TabsRootState.create({
25
- id: boxWith(() => id),
26
- value: boxWith(
27
- () => value,
28
- (v) => {
29
- value = v;
30
- onValueChange(v);
31
- },
32
- ),
33
- orientation: boxWith(() => orientation),
34
- loop: boxWith(() => loop),
35
- activationMode: boxWith(() => activationMode),
36
- disabled: boxWith(() => disabled),
37
- ref: boxWith(
38
- () => ref,
39
- (v) => (ref = v),
40
- ),
24
+ get id() {
25
+ return id;
26
+ },
27
+ get value() {
28
+ return value;
29
+ },
30
+ set value(v) {
31
+ value = v;
32
+ onValueChange(v);
33
+ },
34
+ get orientation() {
35
+ return orientation;
36
+ },
37
+ get loop() {
38
+ return loop;
39
+ },
40
+ get activationMode() {
41
+ return activationMode;
42
+ },
43
+ get disabled() {
44
+ return disabled;
45
+ },
46
+ get ref() {
47
+ return ref;
48
+ },
49
+ set ref(v) {
50
+ ref = v;
51
+ },
41
52
  });
42
53
 
43
54
  const mergedProps = $derived(mergeProps({ 'data-slot': 'tabs', class: 'flex flex-col gap-2' }, restProps, rootState.props));
@@ -1,12 +1,12 @@
1
1
  import { createContext, untrack } from 'svelte';
2
2
  import { SvelteMap } from 'svelte/reactivity';
3
- import { attachRef, type ReadableBoxedValues, type WritableBoxedValues } from '../../internal/tools/index.js';
3
+ import { attachRef } from '../../internal/tools/index.js';
4
4
  import type { TabsActivationMode } from './types.js';
5
5
  import { createBitsAttrs, boolToStr, boolToEmptyStrOrUndef, boolToTrueOrUndef } from '../../internal/attrs.js';
6
6
  import { kbd } from '../../internal/kbd.js';
7
- import type { BitsFocusEvent, BitsKeyboardEvent, BitsMouseEvent, RefAttachment, WithRefOpts } from '../../internal/types.js';
7
+ import type { BitsFocusEvent, BitsKeyboardEvent, BitsMouseEvent, RefAttachment, RefOpts } from '../../internal/types.js';
8
8
  import type { Orientation } from '../../internal/index.js';
9
- import { RovingFocusGroup } from '../../internal/roving-focus-group.js';
9
+ import { RovingFocusGroup } from '../../internal/roving-focus-group.svelte.js';
10
10
 
11
11
  const tabsAttrs = createBitsAttrs({
12
12
  component: 'tabs',
@@ -15,18 +15,13 @@ const tabsAttrs = createBitsAttrs({
15
15
 
16
16
  const [getTabsRoot, setTabsRoot] = createContext<TabsRootState>();
17
17
 
18
- interface TabsRootStateOpts
19
- extends
20
- WithRefOpts,
21
- ReadableBoxedValues<{
22
- orientation: Orientation;
23
- loop: boolean;
24
- activationMode: TabsActivationMode;
25
- disabled: boolean;
26
- }>,
27
- WritableBoxedValues<{
28
- value: string;
29
- }> {}
18
+ interface TabsRootStateOpts extends RefOpts {
19
+ readonly orientation: Orientation;
20
+ readonly loop: boolean;
21
+ readonly activationMode: TabsActivationMode;
22
+ readonly disabled: boolean;
23
+ value: string;
24
+ }
30
25
 
31
26
  export class TabsRootState {
32
27
  static create(opts: TabsRootStateOpts) {
@@ -43,12 +38,12 @@ export class TabsRootState {
43
38
 
44
39
  constructor(opts: TabsRootStateOpts) {
45
40
  this.opts = opts;
46
- this.attachment = attachRef(opts.ref);
41
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
47
42
  this.rovingFocusGroup = new RovingFocusGroup({
48
43
  candidateAttr: tabsAttrs.trigger,
49
- rootNode: this.opts.ref,
50
- loop: this.opts.loop,
51
- orientation: this.opts.orientation,
44
+ rootNode: () => opts.ref,
45
+ loop: () => opts.loop,
46
+ orientation: () => opts.orientation,
52
47
  });
53
48
  }
54
49
 
@@ -72,22 +67,18 @@ export class TabsRootState {
72
67
  };
73
68
  }
74
69
 
75
- setValue(v: string) {
76
- this.opts.value.current = v;
77
- }
78
-
79
70
  readonly props = $derived.by(
80
71
  () =>
81
72
  ({
82
- id: this.opts.id.current,
83
- 'data-orientation': this.opts.orientation.current,
73
+ id: this.opts.id,
74
+ 'data-orientation': this.opts.orientation,
84
75
  [tabsAttrs.root]: '',
85
76
  ...this.attachment,
86
77
  }) as const,
87
78
  );
88
79
  }
89
80
 
90
- interface TabsListStateOpts extends WithRefOpts {}
81
+ interface TabsListStateOpts extends RefOpts {}
91
82
 
92
83
  export class TabsListState {
93
84
  static create(opts: TabsListStateOpts) {
@@ -96,35 +87,31 @@ export class TabsListState {
96
87
  readonly opts: TabsListStateOpts;
97
88
  readonly root: TabsRootState;
98
89
  readonly attachment: RefAttachment;
99
- readonly #isDisabled = $derived.by(() => this.root.opts.disabled.current);
100
90
 
101
91
  constructor(opts: TabsListStateOpts, root: TabsRootState) {
102
92
  this.opts = opts;
103
93
  this.root = root;
104
- this.attachment = attachRef(opts.ref);
94
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
105
95
  }
106
96
 
107
97
  readonly props = $derived.by(
108
98
  () =>
109
99
  ({
110
- id: this.opts.id.current,
100
+ id: this.opts.id,
111
101
  role: 'tablist',
112
- 'aria-orientation': this.root.opts.orientation.current,
113
- 'data-orientation': this.root.opts.orientation.current,
102
+ 'aria-orientation': this.root.opts.orientation,
103
+ 'data-orientation': this.root.opts.orientation,
114
104
  [tabsAttrs.list]: '',
115
- 'data-disabled': boolToEmptyStrOrUndef(this.#isDisabled),
105
+ 'data-disabled': boolToEmptyStrOrUndef(this.root.opts.disabled),
116
106
  ...this.attachment,
117
107
  }) as const,
118
108
  );
119
109
  }
120
110
 
121
- interface TabsTriggerStateOpts
122
- extends
123
- WithRefOpts,
124
- ReadableBoxedValues<{
125
- value: string;
126
- disabled: boolean;
127
- }> {}
111
+ interface TabsTriggerStateOpts extends RefOpts {
112
+ readonly value: string;
113
+ readonly disabled: boolean;
114
+ }
128
115
 
129
116
  export class TabsTriggerState {
130
117
  static create(opts: TabsTriggerStateOpts) {
@@ -133,18 +120,18 @@ export class TabsTriggerState {
133
120
  readonly opts: TabsTriggerStateOpts;
134
121
  readonly root: TabsRootState;
135
122
  readonly attachment: RefAttachment;
136
- readonly #isActive = $derived.by(() => this.root.opts.value.current === this.opts.value.current);
137
- readonly #tabIndex = $derived.by(() => (this.#isActive || !this.root.opts.value.current ? 0 : -1));
138
- readonly #isDisabled = $derived.by(() => this.opts.disabled.current || this.root.opts.disabled.current);
139
- readonly #ariaControls = $derived.by(() => this.root.valueToContentId.get(this.opts.value.current));
123
+ readonly #isActive = $derived.by(() => this.root.opts.value === this.opts.value);
124
+ readonly #tabIndex = $derived.by(() => (this.#isActive || !this.root.opts.value ? 0 : -1));
125
+ readonly #isDisabled = $derived.by(() => this.opts.disabled || this.root.opts.disabled);
126
+ readonly #ariaControls = $derived.by(() => this.root.valueToContentId.get(this.opts.value));
140
127
 
141
128
  constructor(opts: TabsTriggerStateOpts, root: TabsRootState) {
142
129
  this.opts = opts;
143
130
  this.root = root;
144
- this.attachment = attachRef(opts.ref);
131
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
145
132
  $effect(() => {
146
- const id = this.opts.id.current;
147
- const value = this.opts.value.current;
133
+ const id = this.opts.id;
134
+ const value = this.opts.value;
148
135
  return untrack(() => {
149
136
  return this.root.registerTrigger(id, value);
150
137
  });
@@ -156,12 +143,12 @@ export class TabsTriggerState {
156
143
  }
157
144
 
158
145
  #activate() {
159
- if (this.root.opts.value.current === this.opts.value.current) return;
160
- this.root.setValue(this.opts.value.current);
146
+ if (this.root.opts.value === this.opts.value) return;
147
+ this.root.opts.value = this.opts.value;
161
148
  }
162
149
 
163
150
  onfocus(_: BitsFocusEvent) {
164
- if (this.root.opts.activationMode.current !== 'automatic' || this.#isDisabled) return;
151
+ if (this.root.opts.activationMode !== 'automatic' || this.#isDisabled) return;
165
152
  this.#activate();
166
153
  }
167
154
 
@@ -177,17 +164,17 @@ export class TabsTriggerState {
177
164
  this.#activate();
178
165
  return;
179
166
  }
180
- this.root.rovingFocusGroup.handleKeydown(this.opts.ref.current, e);
167
+ this.root.rovingFocusGroup.handleKeydown(this.opts.ref, e);
181
168
  }
182
169
 
183
170
  readonly props = $derived.by(
184
171
  () =>
185
172
  ({
186
- id: this.opts.id.current,
173
+ id: this.opts.id,
187
174
  role: 'tab',
188
175
  'data-state': getTabDataState(this.#isActive),
189
- 'data-value': this.opts.value.current,
190
- 'data-orientation': this.root.opts.orientation.current,
176
+ 'data-value': this.opts.value,
177
+ 'data-orientation': this.root.opts.orientation,
191
178
  'data-disabled': boolToEmptyStrOrUndef(this.#isDisabled),
192
179
  'aria-selected': boolToStr(this.#isActive),
193
180
  'aria-controls': this.#ariaControls,
@@ -203,12 +190,9 @@ export class TabsTriggerState {
203
190
  );
204
191
  }
205
192
 
206
- interface TabsContentStateOpts
207
- extends
208
- WithRefOpts,
209
- ReadableBoxedValues<{
210
- value: string;
211
- }> {}
193
+ interface TabsContentStateOpts extends RefOpts {
194
+ readonly value: string;
195
+ }
212
196
 
213
197
  export class TabsContentState {
214
198
  static create(opts: TabsContentStateOpts) {
@@ -217,16 +201,16 @@ export class TabsContentState {
217
201
  readonly opts: TabsContentStateOpts;
218
202
  readonly root: TabsRootState;
219
203
  readonly attachment: RefAttachment;
220
- readonly #isActive = $derived.by(() => this.root.opts.value.current === this.opts.value.current);
221
- readonly #ariaLabelledBy = $derived.by(() => this.root.valueToTriggerId.get(this.opts.value.current));
204
+ readonly #isActive = $derived.by(() => this.root.opts.value === this.opts.value);
205
+ readonly #ariaLabelledBy = $derived.by(() => this.root.valueToTriggerId.get(this.opts.value));
222
206
 
223
207
  constructor(opts: TabsContentStateOpts, root: TabsRootState) {
224
208
  this.opts = opts;
225
209
  this.root = root;
226
- this.attachment = attachRef(opts.ref);
210
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
227
211
  $effect(() => {
228
- const id = this.opts.id.current;
229
- const value = this.opts.value.current;
212
+ const id = this.opts.id;
213
+ const value = this.opts.value;
230
214
  return untrack(() => {
231
215
  return this.root.registerContent(id, value);
232
216
  });
@@ -236,14 +220,14 @@ export class TabsContentState {
236
220
  readonly props = $derived.by(
237
221
  () =>
238
222
  ({
239
- id: this.opts.id.current,
223
+ id: this.opts.id,
240
224
  role: 'tabpanel',
241
225
  hidden: boolToTrueOrUndef(!this.#isActive),
242
226
  tabindex: 0,
243
- 'data-value': this.opts.value.current,
227
+ 'data-value': this.opts.value,
244
228
  'data-state': getTabDataState(this.#isActive),
245
229
  'aria-labelledby': this.#ariaLabelledBy,
246
- 'data-orientation': this.root.opts.orientation.current,
230
+ 'data-orientation': this.root.opts.orientation,
247
231
  [tabsAttrs.content]: '',
248
232
  ...this.attachment,
249
233
  }) as const,
@@ -6,7 +6,7 @@ import {
6
6
  DOMContext,
7
7
  type ReadableBoxedValues,
8
8
  type WritableBoxedValues,
9
- simpleBox,
9
+ boxWith,
10
10
  } from '../../internal/tools/index.js';
11
11
  import { createContext, onMount, untrack } from 'svelte';
12
12
  import type { BitsFocusEvent, BitsInputEvent, BitsKeyboardEvent, BitsMouseEvent, RefAttachment, WithRefOpts } from '../../internal/types.js';
@@ -196,7 +196,7 @@ export class TimeFieldRootState<T extends TimeValue = Time> {
196
196
  */
197
197
  this.value = props.value;
198
198
  this.placeholder = rangeRoot ? rangeRoot.opts.placeholder : props.placeholder;
199
- this.validate = rangeRoot ? simpleBox(undefined) : props.validate;
199
+ this.validate = rangeRoot ? boxWith(() => undefined) : props.validate;
200
200
  this.minValue = rangeRoot ? rangeRoot.opts.minValue : props.minValue;
201
201
  this.maxValue = rangeRoot ? rangeRoot.opts.maxValue : props.maxValue;
202
202
  this.disabled = rangeRoot ? rangeRoot.opts.disabled : props.disabled;
@@ -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,
@@ -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 { ToggleGroupItemProps } from '../types.js';
5
4
  import { createToggleGroupItem } from '../toggle-group.svelte.js';
@@ -28,13 +27,21 @@
28
27
  const ctx = getToggleGroupCtx();
29
28
 
30
29
  const itemState = createToggleGroupItem({
31
- id: boxWith(() => id),
32
- value: boxWith(() => value),
33
- disabled: boxWith(() => disabled ?? false),
34
- ref: boxWith(
35
- () => ref,
36
- (v) => (ref = v),
37
- ),
30
+ get id() {
31
+ return id;
32
+ },
33
+ get value() {
34
+ return value;
35
+ },
36
+ get disabled() {
37
+ return disabled ?? false;
38
+ },
39
+ get ref() {
40
+ return ref;
41
+ },
42
+ set ref(v) {
43
+ ref = v;
44
+ },
38
45
  });
39
46
 
40
47
  const mergedProps = $derived(
@@ -14,8 +14,8 @@
14
14
 
15
15
  <script lang="ts">
16
16
  import { untrack } from 'svelte';
17
- import { boxWith, repairBindable } from '../../../internal/tools/index.js';
18
- import { emptySelection } from '../../../internal/selection.svelte.js';
17
+ import { repairBindable } from '../../../internal/tools/index.js';
18
+ import { SelectionValue, emptySelection } from '../../../internal/selection.svelte.js';
19
19
  import { mergeProps } from '../../../internal/merge-props.js';
20
20
  import type { ToggleGroupRootProps } from '../types.js';
21
21
  import { ToggleGroupRootState } from '../toggle-group.svelte.js';
@@ -44,10 +44,10 @@
44
44
  // Context for toggle group items (values are stable, no reactivity needed)
45
45
  setToggleGroupCtx(untrack(() => ({ variant, size, spacing })));
46
46
 
47
- // Mode is construction-static: the selection stays single or multiple for the group's life.
48
- const valueType = untrack(() => type);
47
+ // Mode is fixed at mount: `value` keeps the shape it was declared with.
48
+ // svelte-ignore state_referenced_locally
49
+ const valueType = type;
49
50
 
50
- // The group owns a mode-specific controlled value.
51
51
  repairBindable(
52
52
  () => value,
53
53
  () => {
@@ -56,8 +56,29 @@
56
56
  );
57
57
 
58
58
  const rootState = ToggleGroupRootState.create({
59
- id: boxWith(() => id),
60
- value: boxWith(
59
+ get id() {
60
+ return id;
61
+ },
62
+ get disabled() {
63
+ return disabled;
64
+ },
65
+ get loop() {
66
+ return loop;
67
+ },
68
+ get orientation() {
69
+ return orientation;
70
+ },
71
+ get rovingFocus() {
72
+ return rovingFocus;
73
+ },
74
+ get ref() {
75
+ return ref;
76
+ },
77
+ set ref(v) {
78
+ ref = v;
79
+ },
80
+ selection: new SelectionValue(
81
+ valueType,
61
82
  () => value ?? emptySelection(valueType),
62
83
  (v) => {
63
84
  value = v;
@@ -65,15 +86,6 @@
65
86
  onValueChange(v as any);
66
87
  },
67
88
  ),
68
- disabled: boxWith(() => disabled),
69
- loop: boxWith(() => loop),
70
- orientation: boxWith(() => orientation),
71
- rovingFocus: boxWith(() => rovingFocus),
72
- type: valueType,
73
- ref: boxWith(
74
- () => ref,
75
- (v) => (ref = v),
76
- ),
77
89
  });
78
90
 
79
91
  const mergedProps = $derived(