sheer-ui 0.4.0 → 0.4.2

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 (55) 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/checkbox/components/checkbox-group.svelte +7 -5
  6. package/src/lib/components/checkbox/components/checkbox.svelte +12 -8
  7. package/src/lib/components/combobox/components/combobox.svelte +2 -2
  8. package/src/lib/components/combobox/select/components/select.svelte +2 -2
  9. package/src/lib/components/context-menu/components/context-menu-trigger.svelte +1 -1
  10. package/src/lib/components/date-field/date-field.svelte.ts +2 -3
  11. package/src/lib/components/menu/components/menu-checkbox-group.svelte +6 -4
  12. package/src/lib/components/menu/components/menu-checkbox-item.svelte +11 -7
  13. package/src/lib/components/menu/menu.svelte.ts +9 -18
  14. package/src/lib/components/menubar/menubar.svelte.ts +7 -6
  15. package/src/lib/components/navigation-menu/components/navigation-menu-content.svelte +1 -1
  16. package/src/lib/components/navigation-menu/components/navigation-menu-indicator.svelte +2 -2
  17. package/src/lib/components/navigation-menu/components/navigation-menu-trigger.svelte +1 -1
  18. package/src/lib/components/navigation-menu/navigation-menu.svelte.ts +57 -60
  19. package/src/lib/components/pagination/components/pagination-next-button.svelte +12 -7
  20. package/src/lib/components/pagination/components/pagination-page.svelte +15 -8
  21. package/src/lib/components/pagination/components/pagination-prev-button.svelte +12 -7
  22. package/src/lib/components/pagination/components/pagination.svelte +31 -18
  23. package/src/lib/components/pagination/pagination.svelte.ts +48 -64
  24. package/src/lib/components/pin-input/pin-input.svelte.ts +7 -8
  25. package/src/lib/components/pin-input/usePasswordManager.svelte.ts +2 -2
  26. package/src/lib/components/scroll-area/scroll-area.svelte.ts +9 -10
  27. package/src/lib/components/slider/components/slider.svelte +2 -1
  28. package/src/lib/components/tabs/components/tabs-content.svelte +12 -7
  29. package/src/lib/components/tabs/components/tabs-list.svelte +9 -6
  30. package/src/lib/components/tabs/components/tabs-trigger.svelte +15 -8
  31. package/src/lib/components/tabs/components/tabs.svelte +28 -17
  32. package/src/lib/components/tabs/tabs.svelte.ts +51 -67
  33. package/src/lib/components/time-field/time-field.svelte.ts +2 -2
  34. package/src/lib/components/toggle-group/components/toggle-group-item.svelte +15 -8
  35. package/src/lib/components/toggle-group/components/toggle-group.svelte +28 -16
  36. package/src/lib/components/toggle-group/toggle-group.svelte.ts +33 -35
  37. package/src/lib/components/toolbar/components/toolbar-group-item.svelte +15 -8
  38. package/src/lib/components/toolbar/components/toolbar-group.svelte +19 -14
  39. package/src/lib/components/toolbar/toolbar.svelte.ts +28 -30
  40. package/src/lib/components/tooltip/tooltip.svelte.ts +6 -27
  41. package/src/lib/internal/dismissible-layer/use-dismissable-layer.svelte.ts +3 -4
  42. package/src/lib/internal/floating-layer/use-floating-layer.svelte.ts +26 -30
  43. package/src/lib/internal/{roving-focus-group.ts → roving-focus-group.svelte.ts} +17 -19
  44. package/src/lib/internal/roving-focus-item.svelte.ts +12 -17
  45. package/src/lib/internal/selection.svelte.ts +55 -41
  46. package/src/lib/internal/{state-machine.ts → state-machine.svelte.ts} +6 -8
  47. package/src/lib/internal/timeout-fn.svelte.ts +6 -4
  48. package/src/lib/internal/tools/box.svelte.ts +5 -114
  49. package/src/lib/internal/tools/index.ts +1 -11
  50. package/src/lib/internal/tools/types.ts +0 -3
  51. package/src/lib/internal/typeahead.svelte.ts +9 -13
  52. package/src/lib/internal/types.ts +6 -0
  53. package/src/lib/internal/vaul/use-drawer-content.svelte.ts +2 -2
  54. package/src/lib/internal/vaul/use-drawer-root.svelte.ts +12 -7
  55. package/src/lib/components/accordion/accordion.svelte.ts +0 -43
@@ -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 { 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(
@@ -1,16 +1,10 @@
1
1
  import { createContext } from 'svelte';
2
- import { type ReadableBox, type ReadableBoxedValues, type WritableBox, attachRef } from '../../internal/tools/index.js';
2
+ import { attachRef } from '../../internal/tools/index.js';
3
3
  import { createBitsAttrs, boolToEmptyStrOrUndef } from '../../internal/attrs.js';
4
4
  import type { Orientation } from '../../internal/index.js';
5
- import type { RefAttachment, WithRefOpts } from '../../internal/types.js';
6
- import { RovingFocusGroup } from '../../internal/roving-focus-group.js';
7
- import {
8
- type SelectionGroup,
9
- type SelectionItemOpts,
10
- type SelectionType,
11
- SelectionItemState,
12
- SelectionValue,
13
- } from '../../internal/selection.svelte.js';
5
+ import type { RefAttachment } from '../../internal/types.js';
6
+ import { RovingFocusGroup } from '../../internal/roving-focus-group.svelte.js';
7
+ import { type SelectionGroup, type SelectionItemOpts, SelectionItemState, SelectionValue } from '../../internal/selection.svelte.js';
14
8
 
15
9
  export const toggleGroupAttrs = createBitsAttrs({
16
10
  component: 'toggle-group',
@@ -19,17 +13,15 @@ export const toggleGroupAttrs = createBitsAttrs({
19
13
 
20
14
  const [getToggleGroupRoot, setToggleGroupRoot] = createContext<ToggleGroupRootState>();
21
15
 
22
- interface ToggleGroupRootStateOpts
23
- extends
24
- WithRefOpts,
25
- ReadableBoxedValues<{
26
- disabled: boolean;
27
- rovingFocus: boolean;
28
- loop: boolean;
29
- orientation: Orientation;
30
- }> {
31
- type: SelectionType;
32
- value: WritableBox<string | string[]>;
16
+ /** The root component's props as accessors over its `$props()`; `ref` writes back to its bindable. */
17
+ interface ToggleGroupRootStateOpts {
18
+ readonly id: string;
19
+ readonly disabled: boolean;
20
+ readonly rovingFocus: boolean;
21
+ readonly loop: boolean;
22
+ readonly orientation: Orientation;
23
+ ref: HTMLElement | null;
24
+ selection: SelectionValue;
33
25
  }
34
26
 
35
27
  export class ToggleGroupRootState implements SelectionGroup {
@@ -38,36 +30,42 @@ export class ToggleGroupRootState implements SelectionGroup {
38
30
  }
39
31
  readonly opts: ToggleGroupRootStateOpts;
40
32
  readonly selection: SelectionValue;
41
- readonly disabled: ReadableBox<boolean>;
42
- readonly orientation: ReadableBox<Orientation>;
43
- readonly rovingFocus: ReadableBox<boolean>;
44
33
  readonly rovingFocusGroup: RovingFocusGroup;
45
34
  readonly selectionTakesTabStop = true;
46
35
  readonly attachment: RefAttachment;
47
36
 
48
37
  constructor(opts: ToggleGroupRootStateOpts) {
49
38
  this.opts = opts;
50
- this.selection = new SelectionValue(opts.type, opts.value);
51
- this.disabled = opts.disabled;
52
- this.orientation = opts.orientation;
53
- this.rovingFocus = opts.rovingFocus;
54
- this.attachment = attachRef(opts.ref);
39
+ this.selection = opts.selection;
40
+ this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
55
41
  this.rovingFocusGroup = new RovingFocusGroup({
56
42
  candidateAttr: toggleGroupAttrs.item,
57
- rootNode: opts.ref,
58
- loop: opts.loop,
59
- orientation: opts.orientation,
43
+ rootNode: () => opts.ref,
44
+ loop: () => opts.loop,
45
+ orientation: () => opts.orientation,
60
46
  });
61
47
  }
62
48
 
49
+ get disabled() {
50
+ return this.opts.disabled;
51
+ }
52
+
53
+ get orientation() {
54
+ return this.opts.orientation;
55
+ }
56
+
57
+ get rovingFocus() {
58
+ return this.opts.rovingFocus;
59
+ }
60
+
63
61
  readonly props = $derived.by(
64
62
  () =>
65
63
  ({
66
- id: this.opts.id.current,
64
+ id: this.opts.id,
67
65
  [toggleGroupAttrs.root]: '',
68
66
  role: 'group',
69
- 'data-orientation': this.opts.orientation.current,
70
- 'data-disabled': boolToEmptyStrOrUndef(this.opts.disabled.current),
67
+ 'data-orientation': this.opts.orientation,
68
+ 'data-disabled': boolToEmptyStrOrUndef(this.opts.disabled),
71
69
  ...this.attachment,
72
70
  }) as const,
73
71
  );
@@ -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 { ToolbarGroupItemProps } from '../types.js';
5
4
  import { createToolbarGroupItem } from '../toolbar.svelte.js';
@@ -25,13 +24,21 @@
25
24
  } = $props();
26
25
 
27
26
  const groupItemState = createToolbarGroupItem({
28
- id: boxWith(() => id),
29
- value: boxWith(() => value),
30
- disabled: boxWith(() => disabled ?? false),
31
- ref: boxWith(
32
- () => ref,
33
- (v) => (ref = v),
34
- ),
27
+ get id() {
28
+ return id;
29
+ },
30
+ get value() {
31
+ return value;
32
+ },
33
+ get disabled() {
34
+ return disabled ?? false;
35
+ },
36
+ get ref() {
37
+ return ref;
38
+ },
39
+ set ref(v) {
40
+ ref = v;
41
+ },
35
42
  });
36
43
 
37
44
  const mergedProps = $derived(
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
- import { untrack } from 'svelte';
3
- import { boxWith, repairBindable } from '../../../internal/tools/index.js';
4
- import { emptySelection } from '../../../internal/selection.svelte.js';
2
+ import { repairBindable } from '../../../internal/tools/index.js';
3
+ import { SelectionValue, emptySelection } from '../../../internal/selection.svelte.js';
5
4
  import { mergeProps } from '../../../internal/merge-props.js';
6
5
  import type { ToolbarGroupProps } from '../types.js';
7
6
  import { ToolbarGroupState } from '../toolbar.svelte.js';
@@ -21,10 +20,10 @@
21
20
  ...restProps
22
21
  }: ToolbarGroupProps = $props();
23
22
 
24
- // Mode is construction-static: the selection stays single or multiple for the group's life.
25
- const valueType = untrack(() => type);
23
+ // Mode is fixed at mount: `value` keeps the shape it was declared with.
24
+ // svelte-ignore state_referenced_locally
25
+ const valueType = type;
26
26
 
27
- // The group owns a mode-specific controlled value.
28
27
  repairBindable(
29
28
  () => value,
30
29
  () => {
@@ -33,10 +32,20 @@
33
32
  );
34
33
 
35
34
  const groupState = ToolbarGroupState.create({
36
- id: boxWith(() => id),
37
- disabled: boxWith(() => disabled),
38
- type: valueType,
39
- value: boxWith(
35
+ get id() {
36
+ return id;
37
+ },
38
+ get disabled() {
39
+ return disabled;
40
+ },
41
+ get ref() {
42
+ return ref;
43
+ },
44
+ set ref(v) {
45
+ ref = v;
46
+ },
47
+ selection: new SelectionValue(
48
+ valueType,
40
49
  () => value ?? emptySelection(valueType),
41
50
  (v) => {
42
51
  value = v;
@@ -44,10 +53,6 @@
44
53
  onValueChange(v as any);
45
54
  },
46
55
  ),
47
- ref: boxWith(
48
- () => ref,
49
- (v) => (ref = v),
50
- ),
51
56
  });
52
57
 
53
58
  const mergedProps = $derived(mergeProps({ 'data-slot': 'toolbar-group', class: 'flex items-center gap-1' }, restProps, groupState.props));