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.
- package/package.json +1 -1
- package/src/lib/components/accordion/components/accordion-item.svelte +3 -3
- package/src/lib/components/accordion/components/accordion.svelte +29 -13
- package/src/lib/components/accordion/types.ts +3 -3
- package/src/lib/components/checkbox/components/checkbox-group.svelte +7 -5
- package/src/lib/components/checkbox/components/checkbox.svelte +12 -8
- package/src/lib/components/combobox/components/combobox.svelte +2 -2
- package/src/lib/components/combobox/select/components/select.svelte +2 -2
- package/src/lib/components/context-menu/components/context-menu-trigger.svelte +1 -1
- package/src/lib/components/date-field/date-field.svelte.ts +2 -3
- package/src/lib/components/menu/components/menu-checkbox-group.svelte +6 -4
- package/src/lib/components/menu/components/menu-checkbox-item.svelte +11 -7
- package/src/lib/components/menu/menu.svelte.ts +9 -18
- package/src/lib/components/menubar/menubar.svelte.ts +7 -6
- package/src/lib/components/navigation-menu/components/navigation-menu-content.svelte +1 -1
- package/src/lib/components/navigation-menu/components/navigation-menu-indicator.svelte +2 -2
- package/src/lib/components/navigation-menu/components/navigation-menu-trigger.svelte +1 -1
- package/src/lib/components/navigation-menu/navigation-menu.svelte.ts +57 -60
- package/src/lib/components/pagination/components/pagination-next-button.svelte +12 -7
- package/src/lib/components/pagination/components/pagination-page.svelte +15 -8
- package/src/lib/components/pagination/components/pagination-prev-button.svelte +12 -7
- package/src/lib/components/pagination/components/pagination.svelte +31 -18
- package/src/lib/components/pagination/pagination.svelte.ts +48 -64
- package/src/lib/components/pin-input/pin-input.svelte.ts +7 -8
- package/src/lib/components/pin-input/usePasswordManager.svelte.ts +2 -2
- package/src/lib/components/scroll-area/scroll-area.svelte.ts +9 -10
- package/src/lib/components/slider/components/slider.svelte +2 -1
- package/src/lib/components/tabs/components/tabs-content.svelte +12 -7
- package/src/lib/components/tabs/components/tabs-list.svelte +9 -6
- package/src/lib/components/tabs/components/tabs-trigger.svelte +15 -8
- package/src/lib/components/tabs/components/tabs.svelte +28 -17
- package/src/lib/components/tabs/tabs.svelte.ts +51 -67
- package/src/lib/components/time-field/time-field.svelte.ts +2 -2
- package/src/lib/components/toggle-group/components/toggle-group-item.svelte +15 -8
- package/src/lib/components/toggle-group/components/toggle-group.svelte +28 -16
- package/src/lib/components/toggle-group/toggle-group.svelte.ts +33 -35
- package/src/lib/components/toolbar/components/toolbar-group-item.svelte +15 -8
- package/src/lib/components/toolbar/components/toolbar-group.svelte +19 -14
- package/src/lib/components/toolbar/toolbar.svelte.ts +28 -30
- package/src/lib/components/tooltip/tooltip.svelte.ts +6 -27
- package/src/lib/internal/dismissible-layer/use-dismissable-layer.svelte.ts +3 -4
- package/src/lib/internal/floating-layer/use-floating-layer.svelte.ts +26 -30
- package/src/lib/internal/{roving-focus-group.ts → roving-focus-group.svelte.ts} +17 -19
- package/src/lib/internal/roving-focus-item.svelte.ts +12 -17
- package/src/lib/internal/selection.svelte.ts +55 -41
- package/src/lib/internal/{state-machine.ts → state-machine.svelte.ts} +6 -8
- package/src/lib/internal/timeout-fn.svelte.ts +6 -4
- package/src/lib/internal/tools/box.svelte.ts +5 -114
- package/src/lib/internal/tools/index.ts +1 -11
- package/src/lib/internal/tools/types.ts +0 -3
- package/src/lib/internal/typeahead.svelte.ts +9 -13
- package/src/lib/internal/types.ts +6 -0
- package/src/lib/internal/vaul/use-drawer-content.svelte.ts +2 -2
- package/src/lib/internal/vaul/use-drawer-root.svelte.ts +12 -7
- 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
|
|
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,
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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:
|
|
50
|
-
loop:
|
|
51
|
-
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
|
|
83
|
-
'data-orientation': this.opts.orientation
|
|
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
|
|
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
|
|
100
|
+
id: this.opts.id,
|
|
111
101
|
role: 'tablist',
|
|
112
|
-
'aria-orientation': this.root.opts.orientation
|
|
113
|
-
'data-orientation': this.root.opts.orientation
|
|
102
|
+
'aria-orientation': this.root.opts.orientation,
|
|
103
|
+
'data-orientation': this.root.opts.orientation,
|
|
114
104
|
[tabsAttrs.list]: '',
|
|
115
|
-
'data-disabled': boolToEmptyStrOrUndef(this
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
|
137
|
-
readonly #tabIndex = $derived.by(() => (this.#isActive || !this.root.opts.value
|
|
138
|
-
readonly #isDisabled = $derived.by(() => this.opts.disabled
|
|
139
|
-
readonly #ariaControls = $derived.by(() => this.root.valueToContentId.get(this.opts.value
|
|
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
|
|
147
|
-
const value = this.opts.value
|
|
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
|
|
160
|
-
this.root.
|
|
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
|
|
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
|
|
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
|
|
173
|
+
id: this.opts.id,
|
|
187
174
|
role: 'tab',
|
|
188
175
|
'data-state': getTabDataState(this.#isActive),
|
|
189
|
-
'data-value': this.opts.value
|
|
190
|
-
'data-orientation': this.root.opts.orientation
|
|
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
|
-
|
|
208
|
-
|
|
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
|
|
221
|
-
readonly #ariaLabelledBy = $derived.by(() => this.root.valueToTriggerId.get(this.opts.value
|
|
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
|
|
229
|
-
const value = this.opts.value
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 ?
|
|
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
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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 {
|
|
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
|
|
48
|
-
|
|
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
|
|
60
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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 =
|
|
51
|
-
this.
|
|
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
|
|
64
|
+
id: this.opts.id,
|
|
67
65
|
[toggleGroupAttrs.root]: '',
|
|
68
66
|
role: 'group',
|
|
69
|
-
'data-orientation': this.opts.orientation
|
|
70
|
-
'data-disabled': boolToEmptyStrOrUndef(this.opts.disabled
|
|
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
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 {
|
|
3
|
-
import {
|
|
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
|
|
25
|
-
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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));
|