@pzerelles/headlessui-svelte 2.1.2-next.7 → 2.1.2-next.8
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/dist/button/Button.svelte +54 -84
- package/dist/checkbox/Checkbox.svelte +120 -174
- package/dist/close-button/CloseButton.svelte +6 -12
- package/dist/combobox/Combobox.svelte +3 -50
- package/dist/data-interactive/DataInteractive.svelte +29 -57
- package/dist/description/Description.svelte +21 -32
- package/dist/dialog/Dialog.svelte +34 -69
- package/dist/dialog/DialogBackdrop.svelte +12 -29
- package/dist/dialog/DialogPanel.svelte +26 -49
- package/dist/dialog/DialogTitle.svelte +23 -38
- package/dist/dialog/InternalDialog.svelte +202 -263
- package/dist/field/Field.svelte +26 -49
- package/dist/fieldset/Fieldset.svelte +29 -50
- package/dist/focus-trap/FocusTrap.svelte +283 -419
- package/dist/input/Input.svelte +53 -84
- package/dist/internal/FocusSentinel.svelte +8 -16
- package/dist/internal/ForcePortalRoot.svelte +3 -7
- package/dist/internal/FormFields.svelte +20 -31
- package/dist/internal/FormResolver.svelte +15 -20
- package/dist/internal/Hidden.svelte +23 -44
- package/dist/internal/HoistFormFields.svelte +4 -7
- package/dist/internal/MainTreeProvider.svelte +36 -89
- package/dist/internal/Portal.svelte +14 -18
- package/dist/label/Label.svelte +57 -91
- package/dist/legend/Legend.svelte +3 -18
- package/dist/listbox/Listbox.svelte +396 -588
- package/dist/listbox/ListboxButton.svelte +127 -176
- package/dist/listbox/ListboxOption.svelte +125 -166
- package/dist/listbox/ListboxOptions.svelte +244 -340
- package/dist/listbox/ListboxSelectedOption.svelte +15 -38
- package/dist/menu/Menu.svelte +218 -307
- package/dist/menu/MenuButton.svelte +115 -157
- package/dist/menu/MenuHeading.svelte +14 -34
- package/dist/menu/MenuItem.svelte +107 -145
- package/dist/menu/MenuItems.svelte +224 -298
- package/dist/menu/MenuSection.svelte +9 -26
- package/dist/menu/MenuSeparator.svelte +4 -20
- package/dist/portal/InternalPortal.svelte +85 -141
- package/dist/portal/Portal.svelte +2 -5
- package/dist/portal/PortalGroup.svelte +9 -30
- package/dist/switch/Switch.svelte +132 -179
- package/dist/switch/SwitchGroup.svelte +31 -44
- package/dist/tabs/Tab.svelte +143 -195
- package/dist/tabs/TabGroup.svelte +205 -292
- package/dist/tabs/TabList.svelte +11 -31
- package/dist/tabs/TabPanel.svelte +43 -68
- package/dist/tabs/TabPanels.svelte +7 -18
- package/dist/textarea/Textarea.svelte +53 -84
- package/dist/transition/InternalTransitionChild.svelte +170 -259
- package/dist/transition/Transition.svelte +66 -96
- package/dist/transition/TransitionChild.svelte +11 -31
- package/dist/utils/ElementOrComponent.svelte +23 -44
- package/dist/utils/Generic.svelte +17 -29
- package/dist/utils/StableCollection.svelte +36 -54
- package/package.json +1 -1
|
@@ -1,312 +1,225 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
type TabsPropsWeControl = never
|
|
13
|
-
|
|
14
|
-
export type TabGroupProps<TTag extends ElementType = typeof DEFAULT_TABS_TAG> = Props<
|
|
15
|
-
TTag,
|
|
16
|
-
TabsRenderPropArg,
|
|
17
|
-
TabsPropsWeControl,
|
|
18
|
-
{
|
|
19
|
-
defaultIndex?: number
|
|
20
|
-
onchange?: (index: number) => void
|
|
21
|
-
selectedIndex?: number
|
|
22
|
-
vertical?: boolean
|
|
23
|
-
manual?: boolean
|
|
24
|
-
}
|
|
25
|
-
>
|
|
26
|
-
|
|
27
|
-
interface StateDefinition {
|
|
28
|
-
info: { isControlled: boolean }
|
|
29
|
-
selectedIndex: number
|
|
30
|
-
|
|
31
|
-
tabs: MutableRefObject<HTMLElement | undefined>[]
|
|
32
|
-
panels: MutableRefObject<HTMLElement | undefined>[]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
type TabsDataContext = StateDefinition & {
|
|
36
|
-
orientation: "horizontal" | "vertical"
|
|
37
|
-
activation: "manual" | "auto"
|
|
1
|
+
<script lang="ts" module>import { sortByDomNode } from "../utils/focus-management.js";
|
|
2
|
+
import { match } from "../utils/match.js";
|
|
3
|
+
import FocusSentinel from "../internal/FocusSentinel.svelte";
|
|
4
|
+
import { setContext, getContext, untrack } from "svelte";
|
|
5
|
+
const DEFAULT_TABS_TAG = "div";
|
|
6
|
+
export function useData(component) {
|
|
7
|
+
const context = getContext("TabsData");
|
|
8
|
+
if (!context) {
|
|
9
|
+
let err = new Error(`<${component} /> is missing a parent <Tab.Group /> component.`);
|
|
10
|
+
if (Error.captureStackTrace) Error.captureStackTrace(err, useData);
|
|
11
|
+
throw err;
|
|
38
12
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return context
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
type TabsActionsContext = {
|
|
51
|
-
registerTab: (tab: MutableRefObject<HTMLElement | undefined>) => () => void
|
|
52
|
-
registerPanel: (panel: MutableRefObject<HTMLElement | undefined>) => () => void
|
|
53
|
-
change: (index: number) => void
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function useActions(component: string) {
|
|
57
|
-
const context = getContext<TabsActionsContext>("TabsActions")
|
|
58
|
-
if (!context) {
|
|
59
|
-
const err = new Error(`<${component} /> is missing a parent <Tab.Group /> component.`)
|
|
60
|
-
if (Error.captureStackTrace) Error.captureStackTrace(err, useActions)
|
|
61
|
-
throw err
|
|
62
|
-
}
|
|
63
|
-
return context
|
|
13
|
+
return context;
|
|
14
|
+
}
|
|
15
|
+
export function useActions(component) {
|
|
16
|
+
const context = getContext("TabsActions");
|
|
17
|
+
if (!context) {
|
|
18
|
+
const err = new Error(`<${component} /> is missing a parent <Tab.Group /> component.`);
|
|
19
|
+
if (Error.captureStackTrace) Error.captureStackTrace(err, useActions);
|
|
20
|
+
throw err;
|
|
64
21
|
}
|
|
22
|
+
return context;
|
|
23
|
+
}
|
|
65
24
|
</script>
|
|
66
25
|
|
|
67
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_TABS_TAG">
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const stateReducer = (initialState: StateDefinition) => {
|
|
84
|
-
let _state = $state(initialState)
|
|
85
|
-
return {
|
|
86
|
-
get info() {
|
|
87
|
-
return _state.info
|
|
88
|
-
},
|
|
89
|
-
get selectedIndex() {
|
|
90
|
-
return _state.selectedIndex
|
|
91
|
-
},
|
|
92
|
-
get tabs() {
|
|
93
|
-
return _state.tabs
|
|
94
|
-
},
|
|
95
|
-
get panels() {
|
|
96
|
-
return _state.panels
|
|
97
|
-
},
|
|
98
|
-
setSelectedIndex(index: number) {
|
|
99
|
-
if (index === _state.selectedIndex) return _state
|
|
100
|
-
let tabs = sortByDomNode(_state.tabs, (tab) => tab.current ?? null)
|
|
101
|
-
let panels = sortByDomNode(_state.panels, (panel) => panel.current ?? null)
|
|
102
|
-
|
|
103
|
-
let focusableTabs = tabs.filter((tab) => !tab?.current?.hasAttribute("disabled"))
|
|
104
|
-
|
|
105
|
-
let nextState = { ..._state, tabs, panels }
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
// Underflow
|
|
109
|
-
index < 0 ||
|
|
110
|
-
// Overflow
|
|
111
|
-
index > tabs.length - 1
|
|
112
|
-
) {
|
|
113
|
-
let direction = match(Math.sign(index - _state.selectedIndex), {
|
|
114
|
-
[Ordering.Less]: () => Direction.Backwards,
|
|
115
|
-
[Ordering.Equal]: () => {
|
|
116
|
-
return match(Math.sign(index), {
|
|
117
|
-
[Ordering.Less]: () => Direction.Forwards,
|
|
118
|
-
[Ordering.Equal]: () => Direction.Forwards,
|
|
119
|
-
[Ordering.Greater]: () => Direction.Backwards,
|
|
120
|
-
})
|
|
121
|
-
},
|
|
122
|
-
[Ordering.Greater]: () => Direction.Forwards,
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
// If there are no focusable tabs then.
|
|
126
|
-
// We won't change the selected index
|
|
127
|
-
// because it's likely the user is
|
|
128
|
-
// lazy loading tabs and there's
|
|
129
|
-
// nothing to focus on yet
|
|
130
|
-
if (focusableTabs.length === 0) {
|
|
131
|
-
_state = nextState
|
|
132
|
-
return _state
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
let nextSelectedIndex = match(direction, {
|
|
136
|
-
[Direction.Forwards]: () => tabs.findIndex((tab) => tab === focusableTabs[0]),
|
|
137
|
-
[Direction.Backwards]: () => tabs.findIndex((tab) => tab === focusableTabs[focusableTabs.length - 1]),
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
_state = {
|
|
141
|
-
...nextState,
|
|
142
|
-
selectedIndex: nextSelectedIndex === -1 ? _state.selectedIndex : nextSelectedIndex,
|
|
143
|
-
}
|
|
144
|
-
return _state
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Middle
|
|
148
|
-
let before = tabs.slice(0, index)
|
|
149
|
-
let after = tabs.slice(index)
|
|
150
|
-
|
|
151
|
-
let next = [...after, ...before].find((tab) => focusableTabs.some((_tab) => _tab === tab))
|
|
152
|
-
if (!next) {
|
|
153
|
-
_state = nextState
|
|
154
|
-
return _state
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
let selectedIndex = tabs.findIndex((tab) => tab === next) ?? _state.selectedIndex
|
|
158
|
-
if (selectedIndex === -1) selectedIndex = _state.selectedIndex
|
|
159
|
-
|
|
160
|
-
_state = { ...nextState, selectedIndex }
|
|
161
|
-
return _state
|
|
162
|
-
},
|
|
163
|
-
registerTab(tab: MutableRefObject<HTMLElement | undefined>) {
|
|
164
|
-
if (_state.tabs.some((_tab) => _tab === tab)) return _state
|
|
165
|
-
|
|
166
|
-
_state.tabs = sortByDomNode([..._state.tabs, tab], (tab) => tab.current ?? null)
|
|
167
|
-
let activeTab = _state.tabs[_state.selectedIndex]
|
|
168
|
-
|
|
169
|
-
// When the component is uncontrolled, then we want to maintain the actively
|
|
170
|
-
// selected tab even if new tabs are inserted or removed before the active
|
|
171
|
-
// tab.
|
|
172
|
-
//
|
|
173
|
-
// When the component is controlled, then we don't want to do this and
|
|
174
|
-
// instead we want to select the tab based on the `selectedIndex` prop.
|
|
175
|
-
if (!_state.info.isControlled) {
|
|
176
|
-
const selectedIndex = _state.tabs.findIndex((tab) => tab === activeTab)
|
|
177
|
-
if (selectedIndex !== _state.selectedIndex) _state.selectedIndex = selectedIndex
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return _state
|
|
181
|
-
},
|
|
182
|
-
unregisterTab(tab: MutableRefObject<HTMLElement | undefined>) {
|
|
183
|
-
_state.tabs = _state.tabs.filter((_tab) => _tab !== tab)
|
|
184
|
-
return _state
|
|
185
|
-
},
|
|
186
|
-
registerPanel(panel: MutableRefObject<HTMLElement | undefined>) {
|
|
187
|
-
if (_state.panels.some((_panel) => _panel === panel)) return _state
|
|
188
|
-
_state.panels = sortByDomNode([..._state.panels, panel], (panel) => panel.current ?? null)
|
|
189
|
-
return _state
|
|
190
|
-
},
|
|
191
|
-
unregisterPanel(panel: MutableRefObject<HTMLElement | undefined>) {
|
|
192
|
-
_state.panels = _state.panels.filter((_panel) => _panel !== panel)
|
|
193
|
-
return _state
|
|
194
|
-
},
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
let {
|
|
199
|
-
ref = $bindable(),
|
|
200
|
-
defaultIndex = 0,
|
|
201
|
-
vertical = false,
|
|
202
|
-
manual = false,
|
|
203
|
-
onchange,
|
|
204
|
-
selectedIndex = undefined,
|
|
205
|
-
...theirProps
|
|
206
|
-
}: { as?: TTag } & TabGroupProps<TTag> = $props()
|
|
207
|
-
const orientation = $derived(vertical ? "vertical" : "horizontal")
|
|
208
|
-
const activation = $derived(manual ? "manual" : "auto")
|
|
209
|
-
|
|
210
|
-
const isControlled = $derived(selectedIndex !== undefined)
|
|
211
|
-
|
|
212
|
-
const _state = stateReducer({
|
|
213
|
-
info: { isControlled: selectedIndex !== undefined },
|
|
214
|
-
selectedIndex: selectedIndex ?? defaultIndex,
|
|
215
|
-
tabs: [],
|
|
216
|
-
panels: [],
|
|
217
|
-
})
|
|
218
|
-
$effect(() => {
|
|
219
|
-
untrack(() => _state.info).isControlled = isControlled
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
const slot = $derived({
|
|
223
|
-
selectedIndex: _state.selectedIndex,
|
|
224
|
-
} satisfies TabsRenderPropArg)
|
|
225
|
-
const stableTabs = $derived(_state.tabs)
|
|
226
|
-
|
|
227
|
-
const tabsData = {
|
|
228
|
-
get orientation() {
|
|
229
|
-
return orientation
|
|
230
|
-
},
|
|
231
|
-
get activation() {
|
|
232
|
-
return activation
|
|
233
|
-
},
|
|
26
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_TABS_TAG">import StableCollection from "../utils/StableCollection.svelte";
|
|
27
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
28
|
+
var Direction = /* @__PURE__ */ ((Direction2) => {
|
|
29
|
+
Direction2[Direction2["Forwards"] = 0] = "Forwards";
|
|
30
|
+
Direction2[Direction2["Backwards"] = 1] = "Backwards";
|
|
31
|
+
return Direction2;
|
|
32
|
+
})(Direction || {});
|
|
33
|
+
var Ordering = /* @__PURE__ */ ((Ordering2) => {
|
|
34
|
+
Ordering2[Ordering2["Less"] = -1] = "Less";
|
|
35
|
+
Ordering2[Ordering2["Equal"] = 0] = "Equal";
|
|
36
|
+
Ordering2[Ordering2["Greater"] = 1] = "Greater";
|
|
37
|
+
return Ordering2;
|
|
38
|
+
})(Ordering || {});
|
|
39
|
+
const stateReducer = (initialState) => {
|
|
40
|
+
let _state2 = $state(initialState);
|
|
41
|
+
return {
|
|
234
42
|
get info() {
|
|
235
|
-
return
|
|
43
|
+
return _state2.info;
|
|
236
44
|
},
|
|
237
45
|
get selectedIndex() {
|
|
238
|
-
return
|
|
46
|
+
return _state2.selectedIndex;
|
|
239
47
|
},
|
|
240
48
|
get tabs() {
|
|
241
|
-
return
|
|
49
|
+
return _state2.tabs;
|
|
242
50
|
},
|
|
243
51
|
get panels() {
|
|
244
|
-
return
|
|
52
|
+
return _state2.panels;
|
|
245
53
|
},
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
54
|
+
setSelectedIndex(index) {
|
|
55
|
+
if (index === _state2.selectedIndex) return _state2;
|
|
56
|
+
let tabs = sortByDomNode(_state2.tabs, (tab) => tab.current ?? null);
|
|
57
|
+
let panels = sortByDomNode(_state2.panels, (panel) => panel.current ?? null);
|
|
58
|
+
let focusableTabs = tabs.filter((tab) => !tab?.current?.hasAttribute("disabled"));
|
|
59
|
+
let nextState = { ..._state2, tabs, panels };
|
|
60
|
+
if (
|
|
61
|
+
// Underflow
|
|
62
|
+
index < 0 || // Overflow
|
|
63
|
+
index > tabs.length - 1
|
|
64
|
+
) {
|
|
65
|
+
let direction = match(Math.sign(index - _state2.selectedIndex), {
|
|
66
|
+
[-1 /* Less */]: () => 1 /* Backwards */,
|
|
67
|
+
[0 /* Equal */]: () => {
|
|
68
|
+
return match(Math.sign(index), {
|
|
69
|
+
[-1 /* Less */]: () => 0 /* Forwards */,
|
|
70
|
+
[0 /* Equal */]: () => 0 /* Forwards */,
|
|
71
|
+
[1 /* Greater */]: () => 1 /* Backwards */
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
[1 /* Greater */]: () => 0 /* Forwards */
|
|
75
|
+
});
|
|
76
|
+
if (focusableTabs.length === 0) {
|
|
77
|
+
_state2 = nextState;
|
|
78
|
+
return _state2;
|
|
79
|
+
}
|
|
80
|
+
let nextSelectedIndex = match(direction, {
|
|
81
|
+
[0 /* Forwards */]: () => tabs.findIndex((tab) => tab === focusableTabs[0]),
|
|
82
|
+
[1 /* Backwards */]: () => tabs.findIndex((tab) => tab === focusableTabs[focusableTabs.length - 1])
|
|
83
|
+
});
|
|
84
|
+
_state2 = {
|
|
85
|
+
...nextState,
|
|
86
|
+
selectedIndex: nextSelectedIndex === -1 ? _state2.selectedIndex : nextSelectedIndex
|
|
87
|
+
};
|
|
88
|
+
return _state2;
|
|
89
|
+
}
|
|
90
|
+
let before = tabs.slice(0, index);
|
|
91
|
+
let after = tabs.slice(index);
|
|
92
|
+
let next = [...after, ...before].find((tab) => focusableTabs.some((_tab) => _tab === tab));
|
|
93
|
+
if (!next) {
|
|
94
|
+
_state2 = nextState;
|
|
95
|
+
return _state2;
|
|
96
|
+
}
|
|
97
|
+
let selectedIndex2 = tabs.findIndex((tab) => tab === next) ?? _state2.selectedIndex;
|
|
98
|
+
if (selectedIndex2 === -1) selectedIndex2 = _state2.selectedIndex;
|
|
99
|
+
_state2 = { ...nextState, selectedIndex: selectedIndex2 };
|
|
100
|
+
return _state2;
|
|
280
101
|
},
|
|
281
|
-
|
|
282
|
-
return
|
|
102
|
+
registerTab(tab) {
|
|
103
|
+
if (_state2.tabs.some((_tab) => _tab === tab)) return _state2;
|
|
104
|
+
_state2.tabs = sortByDomNode([..._state2.tabs, tab], (tab2) => tab2.current ?? null);
|
|
105
|
+
let activeTab = _state2.tabs[_state2.selectedIndex];
|
|
106
|
+
if (!_state2.info.isControlled) {
|
|
107
|
+
const selectedIndex2 = _state2.tabs.findIndex((tab2) => tab2 === activeTab);
|
|
108
|
+
if (selectedIndex2 !== _state2.selectedIndex) _state2.selectedIndex = selectedIndex2;
|
|
109
|
+
}
|
|
110
|
+
return _state2;
|
|
283
111
|
},
|
|
284
|
-
|
|
285
|
-
|
|
112
|
+
unregisterTab(tab) {
|
|
113
|
+
_state2.tabs = _state2.tabs.filter((_tab) => _tab !== tab);
|
|
114
|
+
return _state2;
|
|
286
115
|
},
|
|
287
|
-
|
|
288
|
-
|
|
116
|
+
registerPanel(panel) {
|
|
117
|
+
if (_state2.panels.some((_panel) => _panel === panel)) return _state2;
|
|
118
|
+
_state2.panels = sortByDomNode([..._state2.panels, panel], (panel2) => panel2.current ?? null);
|
|
119
|
+
return _state2;
|
|
289
120
|
},
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const newSelectedIndex = selectedIndex ?? defaultIndex
|
|
294
|
-
untrack(() => _state.setSelectedIndex(newSelectedIndex))
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
$effect(() => {
|
|
298
|
-
if (realSelectedIndex === undefined) return
|
|
299
|
-
if (_state.tabs.length <= 0) return
|
|
300
|
-
|
|
301
|
-
// TODO: Figure out a way to detect this without the slow sort on every render. Might be fine
|
|
302
|
-
// unless you have a lot of tabs.
|
|
303
|
-
let sorted = sortByDomNode(_state.tabs, (tab) => tab.current ?? null)
|
|
304
|
-
let didOrderChange = sorted.some((tab, i) => _state.tabs[i] !== tab)
|
|
305
|
-
|
|
306
|
-
if (didOrderChange) {
|
|
307
|
-
change(sorted.findIndex((tab) => tab === _state.tabs[realSelectedIndex]))
|
|
121
|
+
unregisterPanel(panel) {
|
|
122
|
+
_state2.panels = _state2.panels.filter((_panel) => _panel !== panel);
|
|
123
|
+
return _state2;
|
|
308
124
|
}
|
|
309
|
-
}
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
let {
|
|
128
|
+
ref = $bindable(),
|
|
129
|
+
defaultIndex = 0,
|
|
130
|
+
vertical = false,
|
|
131
|
+
manual = false,
|
|
132
|
+
onchange,
|
|
133
|
+
selectedIndex = void 0,
|
|
134
|
+
...theirProps
|
|
135
|
+
} = $props();
|
|
136
|
+
const orientation = $derived(vertical ? "vertical" : "horizontal");
|
|
137
|
+
const activation = $derived(manual ? "manual" : "auto");
|
|
138
|
+
const isControlled = $derived(selectedIndex !== void 0);
|
|
139
|
+
const _state = stateReducer({
|
|
140
|
+
info: { isControlled: selectedIndex !== void 0 },
|
|
141
|
+
selectedIndex: selectedIndex ?? defaultIndex,
|
|
142
|
+
tabs: [],
|
|
143
|
+
panels: []
|
|
144
|
+
});
|
|
145
|
+
$effect(() => {
|
|
146
|
+
untrack(() => _state.info).isControlled = isControlled;
|
|
147
|
+
});
|
|
148
|
+
const slot = $derived({
|
|
149
|
+
selectedIndex: _state.selectedIndex
|
|
150
|
+
});
|
|
151
|
+
const stableTabs = $derived(_state.tabs);
|
|
152
|
+
const tabsData = {
|
|
153
|
+
get orientation() {
|
|
154
|
+
return orientation;
|
|
155
|
+
},
|
|
156
|
+
get activation() {
|
|
157
|
+
return activation;
|
|
158
|
+
},
|
|
159
|
+
get info() {
|
|
160
|
+
return _state.info;
|
|
161
|
+
},
|
|
162
|
+
get selectedIndex() {
|
|
163
|
+
return _state.selectedIndex;
|
|
164
|
+
},
|
|
165
|
+
get tabs() {
|
|
166
|
+
return _state.tabs;
|
|
167
|
+
},
|
|
168
|
+
get panels() {
|
|
169
|
+
return _state.panels;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const realSelectedIndex = $derived(isControlled ? selectedIndex : _state.selectedIndex);
|
|
173
|
+
const registerTab = (tab) => {
|
|
174
|
+
_state.registerTab(tab);
|
|
175
|
+
return () => _state.unregisterTab(tab);
|
|
176
|
+
};
|
|
177
|
+
const registerPanel = (panel) => {
|
|
178
|
+
_state.registerPanel(panel);
|
|
179
|
+
return () => _state.unregisterPanel(panel);
|
|
180
|
+
};
|
|
181
|
+
const change = (index) => {
|
|
182
|
+
if (realSelectedIndex !== index) {
|
|
183
|
+
onchange?.(index);
|
|
184
|
+
}
|
|
185
|
+
if (!isControlled) {
|
|
186
|
+
_state.setSelectedIndex(index);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
setContext("TabsActions", { registerTab, registerPanel, change });
|
|
190
|
+
setContext("TabsData", {
|
|
191
|
+
get orientation() {
|
|
192
|
+
return orientation;
|
|
193
|
+
},
|
|
194
|
+
get activation() {
|
|
195
|
+
return activation;
|
|
196
|
+
},
|
|
197
|
+
get info() {
|
|
198
|
+
return _state.info;
|
|
199
|
+
},
|
|
200
|
+
get selectedIndex() {
|
|
201
|
+
return _state.selectedIndex;
|
|
202
|
+
},
|
|
203
|
+
get tabs() {
|
|
204
|
+
return _state.tabs;
|
|
205
|
+
},
|
|
206
|
+
get panels() {
|
|
207
|
+
return _state.panels;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
$effect(() => {
|
|
211
|
+
const newSelectedIndex = selectedIndex ?? defaultIndex;
|
|
212
|
+
untrack(() => _state.setSelectedIndex(newSelectedIndex));
|
|
213
|
+
});
|
|
214
|
+
$effect(() => {
|
|
215
|
+
if (realSelectedIndex === void 0) return;
|
|
216
|
+
if (_state.tabs.length <= 0) return;
|
|
217
|
+
let sorted = sortByDomNode(_state.tabs, (tab) => tab.current ?? null);
|
|
218
|
+
let didOrderChange = sorted.some((tab, i) => _state.tabs[i] !== tab);
|
|
219
|
+
if (didOrderChange) {
|
|
220
|
+
change(sorted.findIndex((tab) => tab === _state.tabs[realSelectedIndex]));
|
|
221
|
+
}
|
|
222
|
+
});
|
|
310
223
|
</script>
|
|
311
224
|
|
|
312
225
|
<StableCollection>
|
package/dist/tabs/TabList.svelte
CHANGED
|
@@ -1,36 +1,16 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { ElementType, Props } from "../utils/types.js"
|
|
3
|
-
|
|
4
|
-
const DEFAULT_LIST_TAG = "div" as const
|
|
5
|
-
type ListRenderPropArg = {
|
|
6
|
-
selectedIndex: number
|
|
7
|
-
}
|
|
8
|
-
type ListPropsWeControl = "aria-orientation" | "role"
|
|
9
|
-
|
|
10
|
-
export type TabListProps<TTag extends ElementType = typeof DEFAULT_LIST_TAG> = Props<
|
|
11
|
-
TTag,
|
|
12
|
-
ListRenderPropArg,
|
|
13
|
-
ListPropsWeControl,
|
|
14
|
-
{
|
|
15
|
-
//
|
|
16
|
-
}
|
|
17
|
-
>
|
|
1
|
+
<script lang="ts" module>const DEFAULT_LIST_TAG = "div";
|
|
18
2
|
</script>
|
|
19
3
|
|
|
20
|
-
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_LIST_TAG">
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const ourProps = $derived({
|
|
31
|
-
role: "tablist",
|
|
32
|
-
"aria-orientation": orientation,
|
|
33
|
-
})
|
|
4
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_LIST_TAG">import { useData } from "./TabGroup.svelte";
|
|
5
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
6
|
+
const data = useData("Tab.List");
|
|
7
|
+
const { orientation, selectedIndex } = $derived(data);
|
|
8
|
+
const slot = $derived({ selectedIndex });
|
|
9
|
+
let { ref = $bindable(), ...theirProps } = $props();
|
|
10
|
+
const ourProps = $derived({
|
|
11
|
+
role: "tablist",
|
|
12
|
+
"aria-orientation": orientation
|
|
13
|
+
});
|
|
34
14
|
</script>
|
|
35
15
|
|
|
36
16
|
<ElementOrComponent {ourProps} {theirProps} {slot} defaultTag={DEFAULT_LIST_TAG} name="TabList" bind:ref />
|