sv5ui 1.7.0 → 2.0.0
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/Alert/alert.types.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroup.svelte +5 -3
- package/dist/Banner/Banner.svelte +162 -0
- package/dist/Banner/Banner.svelte.d.ts +5 -0
- package/dist/Banner/banner.types.d.ts +148 -0
- package/dist/Banner/banner.types.js +1 -0
- package/dist/Banner/banner.variants.d.ts +293 -0
- package/dist/Banner/banner.variants.js +86 -0
- package/dist/Banner/index.d.ts +2 -0
- package/dist/Banner/index.js +1 -0
- package/dist/Button/Button.svelte +7 -6
- package/dist/Button/button.types.d.ts +3 -3
- package/dist/Collapsible/collapsible.types.d.ts +4 -2
- package/dist/Drawer/Drawer.svelte +3 -1
- package/dist/DropdownMenu/DropdownMenu.svelte +1 -3
- package/dist/DropdownMenu/DropdownMenuTriggerTestWrapper.svelte +12 -0
- package/dist/DropdownMenu/DropdownMenuTriggerTestWrapper.svelte.d.ts +7 -0
- package/dist/DropdownMenu/dropdown-menu.types.d.ts +17 -9
- package/dist/Editor/Editor.svelte +738 -0
- package/dist/Editor/Editor.svelte.d.ts +6 -0
- package/dist/Editor/EditorUrlPrompt.svelte +111 -0
- package/dist/Editor/EditorUrlPrompt.svelte.d.ts +15 -0
- package/dist/Editor/SlashPopup.svelte +67 -0
- package/dist/Editor/SlashPopup.svelte.d.ts +9 -0
- package/dist/Editor/editor.extensions.d.ts +23 -0
- package/dist/Editor/editor.extensions.js +123 -0
- package/dist/Editor/editor.schemas.d.ts +4 -0
- package/dist/Editor/editor.schemas.js +3 -0
- package/dist/Editor/editor.slash.svelte.d.ts +34 -0
- package/dist/Editor/editor.slash.svelte.js +273 -0
- package/dist/Editor/editor.suggestion.d.ts +7 -0
- package/dist/Editor/editor.suggestion.js +142 -0
- package/dist/Editor/editor.toolbar.d.ts +11 -0
- package/dist/Editor/editor.toolbar.js +212 -0
- package/dist/Editor/editor.types.d.ts +347 -0
- package/dist/Editor/editor.types.js +1 -0
- package/dist/Editor/editor.variants.d.ts +308 -0
- package/dist/Editor/editor.variants.js +150 -0
- package/dist/Editor/index.d.ts +53 -0
- package/dist/Editor/index.js +52 -0
- package/dist/Icon/icon.types.d.ts +4 -1
- package/dist/Input/Input.svelte +22 -16
- package/dist/Input/input.variants.d.ts +0 -15
- package/dist/Input/input.variants.js +1 -20
- package/dist/Link/Link.svelte +4 -3
- package/dist/Link/link.types.d.ts +2 -2
- package/dist/Pagination/Pagination.svelte +7 -1
- package/dist/Pagination/pagination.types.d.ts +4 -1
- package/dist/Pagination/pagination.variants.d.ts +0 -72
- package/dist/Pagination/pagination.variants.js +6 -30
- package/dist/Select/Select.svelte +3 -1
- package/dist/Select/select.types.d.ts +5 -9
- package/dist/SelectMenu/SelectMenu.svelte +6 -5
- package/dist/SelectMenu/SelectMenuFormFieldTestWrapper.svelte +11 -0
- package/dist/SelectMenu/SelectMenuFormFieldTestWrapper.svelte.d.ts +7 -0
- package/dist/SelectMenu/select-menu.types.d.ts +5 -2
- package/dist/SelectMenu/select-menu.variants.d.ts +12 -2
- package/dist/SelectMenu/select-menu.variants.js +10 -1
- package/dist/Separator/Separator.svelte +9 -2
- package/dist/Separator/separator.types.d.ts +5 -0
- package/dist/Separator/separator.variants.d.ts +25 -0
- package/dist/Separator/separator.variants.js +7 -1
- package/dist/Stepper/Stepper.svelte +292 -0
- package/dist/Stepper/Stepper.svelte.d.ts +5 -0
- package/dist/Stepper/index.d.ts +2 -0
- package/dist/Stepper/index.js +1 -0
- package/dist/Stepper/stepper.types.d.ts +223 -0
- package/dist/Stepper/stepper.types.js +1 -0
- package/dist/Stepper/stepper.variants.d.ts +428 -0
- package/dist/Stepper/stepper.variants.js +204 -0
- package/dist/Tabs/Tabs.svelte +4 -2
- package/dist/Tabs/tabs.types.d.ts +4 -6
- package/dist/hooks/HookContextProbe.svelte +7 -0
- package/dist/hooks/HookContextProbe.svelte.d.ts +18 -0
- package/dist/hooks/HookContextProvider.svelte +9 -0
- package/dist/hooks/HookContextProvider.svelte.d.ts +18 -0
- package/dist/hooks/HookEmitProbe.svelte +14 -0
- package/dist/hooks/HookEmitProbe.svelte.d.ts +18 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useFormField.svelte.d.ts +0 -31
- package/dist/hooks/useFormField.svelte.js +0 -21
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +97 -1
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { StepperProps } from './stepper.types.js'
|
|
3
|
+
|
|
4
|
+
export type Props = StepperProps
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import type { ClassNameValue } from 'tailwind-merge'
|
|
9
|
+
import { untrack } from 'svelte'
|
|
10
|
+
import { stepperVariants, stepperDefaults } from './stepper.variants.js'
|
|
11
|
+
import type { StepperItem, StepperItemState, StepperApi } from './stepper.types.js'
|
|
12
|
+
import { getComponentConfig } from '../config.js'
|
|
13
|
+
import Icon from '../Icon/Icon.svelte'
|
|
14
|
+
|
|
15
|
+
const config = getComponentConfig('stepper', stepperDefaults)
|
|
16
|
+
|
|
17
|
+
let {
|
|
18
|
+
ref = $bindable(null),
|
|
19
|
+
as = 'div',
|
|
20
|
+
items = [],
|
|
21
|
+
value = $bindable(),
|
|
22
|
+
defaultValue,
|
|
23
|
+
onValueChange,
|
|
24
|
+
api = $bindable(),
|
|
25
|
+
linear = true,
|
|
26
|
+
disabled = false,
|
|
27
|
+
orientation = config.defaultVariants.orientation ?? 'horizontal',
|
|
28
|
+
size = config.defaultVariants.size ?? 'md',
|
|
29
|
+
color = config.defaultVariants.color ?? 'primary',
|
|
30
|
+
content: showContent = true,
|
|
31
|
+
class: className,
|
|
32
|
+
ui,
|
|
33
|
+
indicator: indicatorSlot,
|
|
34
|
+
titleSlot,
|
|
35
|
+
descriptionSlot,
|
|
36
|
+
body,
|
|
37
|
+
...restProps
|
|
38
|
+
}: Props = $props()
|
|
39
|
+
|
|
40
|
+
if (value === undefined) {
|
|
41
|
+
value = untrack(() => defaultValue ?? items[0]?.value ?? 0)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let triggers: (HTMLButtonElement | null)[] = $state([])
|
|
45
|
+
|
|
46
|
+
function getItemValue(item: StepperItem, index: number): string | number {
|
|
47
|
+
return item.value ?? index
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const activeIndex = $derived(items.findIndex((item, i) => getItemValue(item, i) === value))
|
|
51
|
+
|
|
52
|
+
function getState(index: number): StepperItemState {
|
|
53
|
+
if (activeIndex === -1) return 'pending'
|
|
54
|
+
if (index === activeIndex) return 'active'
|
|
55
|
+
return index < activeIndex ? 'completed' : 'pending'
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function canActivate(index: number): boolean {
|
|
59
|
+
if (disabled || items[index]?.disabled) return false
|
|
60
|
+
if (!linear) return true
|
|
61
|
+
return index <= activeIndex + 1
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function setValue(next: string | number) {
|
|
65
|
+
if (next === value) return
|
|
66
|
+
value = next
|
|
67
|
+
onValueChange?.(next)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function handleClick(item: StepperItem, index: number) {
|
|
71
|
+
if (!canActivate(index)) return
|
|
72
|
+
setValue(getItemValue(item, index))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function findEnabled(start: number, dir: 1 | -1): number {
|
|
76
|
+
for (let i = start; i >= 0 && i < items.length; i += dir) {
|
|
77
|
+
if (!items[i]?.disabled) return i
|
|
78
|
+
}
|
|
79
|
+
return -1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function handleKeydown(e: KeyboardEvent, index: number) {
|
|
83
|
+
const horizontal = orientation === 'horizontal'
|
|
84
|
+
const nextKey = horizontal ? 'ArrowRight' : 'ArrowDown'
|
|
85
|
+
const prevKey = horizontal ? 'ArrowLeft' : 'ArrowUp'
|
|
86
|
+
|
|
87
|
+
let target = -1
|
|
88
|
+
if (e.key === nextKey) target = findEnabled(index + 1, 1)
|
|
89
|
+
else if (e.key === prevKey) target = findEnabled(index - 1, -1)
|
|
90
|
+
else if (e.key === 'Home') target = findEnabled(0, 1)
|
|
91
|
+
else if (e.key === 'End') target = findEnabled(items.length - 1, -1)
|
|
92
|
+
else return
|
|
93
|
+
|
|
94
|
+
e.preventDefault()
|
|
95
|
+
if (target >= 0) triggers[target]?.focus()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const apiInstance: StepperApi = {
|
|
99
|
+
next() {
|
|
100
|
+
if (activeIndex >= items.length - 1) return
|
|
101
|
+
const target = items[activeIndex + 1]
|
|
102
|
+
if (!target) return
|
|
103
|
+
setValue(getItemValue(target, activeIndex + 1))
|
|
104
|
+
},
|
|
105
|
+
prev() {
|
|
106
|
+
if (activeIndex <= 0) return
|
|
107
|
+
const target = items[activeIndex - 1]
|
|
108
|
+
if (!target) return
|
|
109
|
+
setValue(getItemValue(target, activeIndex - 1))
|
|
110
|
+
},
|
|
111
|
+
goTo(next) {
|
|
112
|
+
setValue(next)
|
|
113
|
+
},
|
|
114
|
+
get hasNext() {
|
|
115
|
+
return activeIndex >= 0 && activeIndex < items.length - 1
|
|
116
|
+
},
|
|
117
|
+
get hasPrev() {
|
|
118
|
+
return activeIndex > 0
|
|
119
|
+
},
|
|
120
|
+
get activeIndex() {
|
|
121
|
+
return activeIndex
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
$effect.pre(() => {
|
|
126
|
+
api = apiInstance
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
const variantSlots = $derived(stepperVariants({ orientation, size, color }))
|
|
130
|
+
|
|
131
|
+
type ItemUi = StepperItem['ui']
|
|
132
|
+
|
|
133
|
+
const classes = $derived.by(() => {
|
|
134
|
+
const c = config.slots
|
|
135
|
+
const slots = variantSlots
|
|
136
|
+
const u = ui ?? {}
|
|
137
|
+
|
|
138
|
+
const _item = slots.item({ class: [c.item, u.item] })
|
|
139
|
+
const _trigger = slots.trigger({ class: [c.trigger, u.trigger] })
|
|
140
|
+
const _container = slots.container({ class: [c.container, u.container] })
|
|
141
|
+
const _indicator = slots.indicator({ class: [c.indicator, u.indicator] })
|
|
142
|
+
const _separator = slots.separator({ class: [c.separator, u.separator] })
|
|
143
|
+
const _wrapper = slots.wrapper({ class: [c.wrapper, u.wrapper] })
|
|
144
|
+
const _title = slots.title({ class: [c.title, u.title] })
|
|
145
|
+
const _description = slots.description({ class: [c.description, u.description] })
|
|
146
|
+
const _content = slots.content({ class: [c.content, u.content] })
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
root: slots.root({ class: [c.root, className, u.root] }),
|
|
150
|
+
list: slots.list({ class: [c.list, u.list] }),
|
|
151
|
+
item: (itemClass?: ClassNameValue, itemUi?: ItemUi) =>
|
|
152
|
+
itemClass || itemUi
|
|
153
|
+
? slots.item({ class: [c.item, u.item, itemUi?.item, itemClass] })
|
|
154
|
+
: _item,
|
|
155
|
+
trigger: (itemUi?: ItemUi) =>
|
|
156
|
+
itemUi
|
|
157
|
+
? slots.trigger({ class: [c.trigger, u.trigger, itemUi.trigger] })
|
|
158
|
+
: _trigger,
|
|
159
|
+
container: (itemUi?: ItemUi) =>
|
|
160
|
+
itemUi
|
|
161
|
+
? slots.container({ class: [c.container, u.container, itemUi.container] })
|
|
162
|
+
: _container,
|
|
163
|
+
indicator: (itemUi?: ItemUi) =>
|
|
164
|
+
itemUi
|
|
165
|
+
? slots.indicator({ class: [c.indicator, u.indicator, itemUi.indicator] })
|
|
166
|
+
: _indicator,
|
|
167
|
+
separator: (itemUi?: ItemUi) =>
|
|
168
|
+
itemUi
|
|
169
|
+
? slots.separator({ class: [c.separator, u.separator, itemUi.separator] })
|
|
170
|
+
: _separator,
|
|
171
|
+
wrapper: (itemUi?: ItemUi) =>
|
|
172
|
+
itemUi
|
|
173
|
+
? slots.wrapper({ class: [c.wrapper, u.wrapper, itemUi.wrapper] })
|
|
174
|
+
: _wrapper,
|
|
175
|
+
title: (itemUi?: ItemUi) =>
|
|
176
|
+
itemUi ? slots.title({ class: [c.title, u.title, itemUi.title] }) : _title,
|
|
177
|
+
description: (itemUi?: ItemUi) =>
|
|
178
|
+
itemUi
|
|
179
|
+
? slots.description({
|
|
180
|
+
class: [c.description, u.description, itemUi.description]
|
|
181
|
+
})
|
|
182
|
+
: _description,
|
|
183
|
+
content: (itemUi?: ItemUi) =>
|
|
184
|
+
itemUi ? slots.content({ class: [c.content, u.content, itemUi.content] }) : _content
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
</script>
|
|
188
|
+
|
|
189
|
+
<svelte:element
|
|
190
|
+
this={as}
|
|
191
|
+
bind:this={ref}
|
|
192
|
+
class={classes.root}
|
|
193
|
+
data-orientation={orientation}
|
|
194
|
+
{...restProps}
|
|
195
|
+
>
|
|
196
|
+
<ol class={classes.list}>
|
|
197
|
+
{#each items as item, index (item.value ?? index)}
|
|
198
|
+
{@const state = getState(index)}
|
|
199
|
+
{@const number = index + 1}
|
|
200
|
+
{@const active = state === 'active'}
|
|
201
|
+
{@const itemDisabled = disabled || item.disabled || !canActivate(index)}
|
|
202
|
+
{@const slotProps = { item, index, number, state, active }}
|
|
203
|
+
{@const hasVisibleText = !!(
|
|
204
|
+
titleSlot ||
|
|
205
|
+
descriptionSlot ||
|
|
206
|
+
item.title ||
|
|
207
|
+
item.description
|
|
208
|
+
)}
|
|
209
|
+
<li
|
|
210
|
+
class={classes.item(item.class, item.ui)}
|
|
211
|
+
data-state={state}
|
|
212
|
+
data-orientation={orientation}
|
|
213
|
+
data-stepper-item=""
|
|
214
|
+
>
|
|
215
|
+
<button
|
|
216
|
+
type="button"
|
|
217
|
+
bind:this={triggers[index]}
|
|
218
|
+
class={classes.trigger(item.ui)}
|
|
219
|
+
disabled={itemDisabled}
|
|
220
|
+
aria-current={active ? 'step' : undefined}
|
|
221
|
+
aria-label={hasVisibleText ? undefined : `Step ${number}`}
|
|
222
|
+
tabindex={active ? 0 : -1}
|
|
223
|
+
onclick={() => handleClick(item, index)}
|
|
224
|
+
onkeydown={(e) => handleKeydown(e, index)}
|
|
225
|
+
>
|
|
226
|
+
<span class={classes.container(item.ui)}>
|
|
227
|
+
{#if indicatorSlot}
|
|
228
|
+
{@render indicatorSlot(slotProps)}
|
|
229
|
+
{:else}
|
|
230
|
+
<span
|
|
231
|
+
class={classes.indicator(item.ui)}
|
|
232
|
+
data-stepper-indicator=""
|
|
233
|
+
aria-hidden="true"
|
|
234
|
+
>
|
|
235
|
+
{#if item.icon}
|
|
236
|
+
<Icon name={item.icon} />
|
|
237
|
+
{:else if state === 'completed'}
|
|
238
|
+
<Icon name="lucide:check" />
|
|
239
|
+
{:else}
|
|
240
|
+
{number}
|
|
241
|
+
{/if}
|
|
242
|
+
</span>
|
|
243
|
+
{/if}
|
|
244
|
+
|
|
245
|
+
{#if index < items.length - 1}
|
|
246
|
+
<span
|
|
247
|
+
class={classes.separator(item.ui)}
|
|
248
|
+
data-stepper-separator=""
|
|
249
|
+
aria-hidden="true"
|
|
250
|
+
></span>
|
|
251
|
+
{/if}
|
|
252
|
+
</span>
|
|
253
|
+
|
|
254
|
+
{#if hasVisibleText}
|
|
255
|
+
<span class={classes.wrapper(item.ui)}>
|
|
256
|
+
{#if titleSlot}
|
|
257
|
+
{@render titleSlot(slotProps)}
|
|
258
|
+
{:else if item.title}
|
|
259
|
+
<span class={classes.title(item.ui)}>{item.title}</span>
|
|
260
|
+
{/if}
|
|
261
|
+
|
|
262
|
+
{#if descriptionSlot}
|
|
263
|
+
{@render descriptionSlot(slotProps)}
|
|
264
|
+
{:else if item.description}
|
|
265
|
+
<span class={classes.description(item.ui)}>
|
|
266
|
+
{item.description}
|
|
267
|
+
</span>
|
|
268
|
+
{/if}
|
|
269
|
+
</span>
|
|
270
|
+
{/if}
|
|
271
|
+
</button>
|
|
272
|
+
</li>
|
|
273
|
+
{/each}
|
|
274
|
+
</ol>
|
|
275
|
+
|
|
276
|
+
{#if showContent}
|
|
277
|
+
{#each items as item, index (item.value ?? index)}
|
|
278
|
+
{@const state = getState(index)}
|
|
279
|
+
{#if state === 'active' && (body || item.content !== undefined)}
|
|
280
|
+
{@const number = index + 1}
|
|
281
|
+
{@const slotProps = { item, index, number, state, active: true }}
|
|
282
|
+
<div class={classes.content(item.ui)} role="region" data-stepper-content="">
|
|
283
|
+
{#if body}
|
|
284
|
+
{@render body(slotProps)}
|
|
285
|
+
{:else}
|
|
286
|
+
{item.content}
|
|
287
|
+
{/if}
|
|
288
|
+
</div>
|
|
289
|
+
{/if}
|
|
290
|
+
{/each}
|
|
291
|
+
{/if}
|
|
292
|
+
</svelte:element>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Stepper } from './Stepper.svelte';
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ClassNameValue } from 'tailwind-merge';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import type { StepperSlots, StepperVariantProps } from './stepper.variants.js';
|
|
5
|
+
/** Lifecycle state of a single step relative to the active step. */
|
|
6
|
+
export type StepperItemState = 'pending' | 'active' | 'completed';
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for an individual step inside the Stepper.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const item: StepperItem = {
|
|
13
|
+
* value: 'shipping',
|
|
14
|
+
* title: 'Shipping',
|
|
15
|
+
* description: 'Where to deliver',
|
|
16
|
+
* icon: 'lucide:truck'
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export interface StepperItem {
|
|
21
|
+
/**
|
|
22
|
+
* Unique identifier for this step.
|
|
23
|
+
* Falls back to the item's zero-based index when omitted.
|
|
24
|
+
*/
|
|
25
|
+
value?: string | number;
|
|
26
|
+
/**
|
|
27
|
+
* Title shown next to (or below) the indicator.
|
|
28
|
+
*/
|
|
29
|
+
title?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Sub-text rendered under the title.
|
|
32
|
+
*/
|
|
33
|
+
description?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Iconify icon name rendered inside the indicator.
|
|
36
|
+
* Overrides the default number/check fallback.
|
|
37
|
+
*/
|
|
38
|
+
icon?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Whether this step cannot be activated by the user.
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Plain text body content for the active step's content panel.
|
|
46
|
+
* For complex content, use the `body` snippet instead.
|
|
47
|
+
*/
|
|
48
|
+
content?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Additional CSS classes applied to this step's wrapper element.
|
|
51
|
+
*/
|
|
52
|
+
class?: ClassNameValue;
|
|
53
|
+
/**
|
|
54
|
+
* Per-step overrides for individual slot classes.
|
|
55
|
+
*/
|
|
56
|
+
ui?: Partial<Pick<Record<StepperSlots, ClassNameValue>, 'item' | 'trigger' | 'container' | 'indicator' | 'separator' | 'wrapper' | 'title' | 'description' | 'content'>>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Context passed to every Stepper snippet (`indicator`, `titleSlot`,
|
|
60
|
+
* `descriptionSlot`, `body`).
|
|
61
|
+
*/
|
|
62
|
+
export interface StepperSlotProps {
|
|
63
|
+
/** The current step item data. */
|
|
64
|
+
item: StepperItem;
|
|
65
|
+
/** Zero-based position in the `items` array. */
|
|
66
|
+
index: number;
|
|
67
|
+
/** Human-friendly one-based position (`index + 1`). */
|
|
68
|
+
number: number;
|
|
69
|
+
/** Lifecycle state of this step. */
|
|
70
|
+
state: StepperItemState;
|
|
71
|
+
/** Convenience: whether this step is the active one. */
|
|
72
|
+
active: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Imperative API exposed via `bind:api`. Useful when driving the Stepper from
|
|
76
|
+
* external buttons (e.g. wizard form with Back/Next).
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```svelte
|
|
80
|
+
* <script>
|
|
81
|
+
* let api = $state<StepperApi>()
|
|
82
|
+
* </script>
|
|
83
|
+
*
|
|
84
|
+
* <Stepper bind:api items={steps} bind:value={current} />
|
|
85
|
+
*
|
|
86
|
+
* <Button onclick={() => api?.prev()} disabled={!api?.hasPrev}>Back</Button>
|
|
87
|
+
* <Button onclick={() => api?.next()} disabled={!api?.hasNext}>Next</Button>
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export interface StepperApi {
|
|
91
|
+
/**
|
|
92
|
+
* Advance to the next step. Always bypasses the `linear` gating (the
|
|
93
|
+
* caller is assumed to have validated already).
|
|
94
|
+
*/
|
|
95
|
+
next: () => void;
|
|
96
|
+
/**
|
|
97
|
+
* Move back to the previous step. No-op when already at the first step.
|
|
98
|
+
*/
|
|
99
|
+
prev: () => void;
|
|
100
|
+
/**
|
|
101
|
+
* Jump to a specific step by its `value`. Always bypasses gating.
|
|
102
|
+
*/
|
|
103
|
+
goTo: (value: string | number) => void;
|
|
104
|
+
/** Whether `next()` would move forward. */
|
|
105
|
+
readonly hasNext: boolean;
|
|
106
|
+
/** Whether `prev()` would move back. */
|
|
107
|
+
readonly hasPrev: boolean;
|
|
108
|
+
/** Current active step's zero-based index, or `-1` when none matches. */
|
|
109
|
+
readonly activeIndex: number;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Props for the Stepper component.
|
|
113
|
+
*
|
|
114
|
+
* Renders a horizontal or vertical progression indicator suitable for
|
|
115
|
+
* multi-step wizards and form flows.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```svelte
|
|
119
|
+
* <Stepper
|
|
120
|
+
* items={steps}
|
|
121
|
+
* bind:value={current}
|
|
122
|
+
* bind:api
|
|
123
|
+
* color="primary"
|
|
124
|
+
* />
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export interface StepperProps extends Omit<HTMLAttributes<HTMLElement>, 'class'> {
|
|
128
|
+
/**
|
|
129
|
+
* Bindable reference to the root DOM element.
|
|
130
|
+
*/
|
|
131
|
+
ref?: HTMLElement | null;
|
|
132
|
+
/**
|
|
133
|
+
* The HTML element to render as.
|
|
134
|
+
* @default 'div'
|
|
135
|
+
*/
|
|
136
|
+
as?: keyof HTMLElementTagNameMap;
|
|
137
|
+
/**
|
|
138
|
+
* Array of steps to render.
|
|
139
|
+
*/
|
|
140
|
+
items?: StepperItem[];
|
|
141
|
+
/**
|
|
142
|
+
* The currently active step's value. Use `bind:value` for two-way binding.
|
|
143
|
+
* Falls back to `defaultValue` when omitted.
|
|
144
|
+
*/
|
|
145
|
+
value?: string | number;
|
|
146
|
+
/**
|
|
147
|
+
* Initial active value when uncontrolled. Defaults to the first item's
|
|
148
|
+
* value (or `0` when items have no explicit `value`).
|
|
149
|
+
*/
|
|
150
|
+
defaultValue?: string | number;
|
|
151
|
+
/**
|
|
152
|
+
* Fired whenever the active step changes (via click, keyboard, or `api`).
|
|
153
|
+
*/
|
|
154
|
+
onValueChange?: (value: string | number) => void;
|
|
155
|
+
/**
|
|
156
|
+
* Bindable imperative controller. Useful for wiring up external Back/Next
|
|
157
|
+
* buttons that bypass the `linear` gating.
|
|
158
|
+
*/
|
|
159
|
+
api?: StepperApi;
|
|
160
|
+
/**
|
|
161
|
+
* When `true`, clicking only allows advancing one step at a time. Already
|
|
162
|
+
* completed steps remain freely navigable. The imperative `api.next()`
|
|
163
|
+
* always bypasses this gate.
|
|
164
|
+
* @default true
|
|
165
|
+
*/
|
|
166
|
+
linear?: boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Whether all steps are disabled.
|
|
169
|
+
* @default false
|
|
170
|
+
*/
|
|
171
|
+
disabled?: boolean;
|
|
172
|
+
/**
|
|
173
|
+
* Layout direction.
|
|
174
|
+
* - `'horizontal'`: indicators in a row, title/description below
|
|
175
|
+
* - `'vertical'`: indicators in a column, title/description to the side
|
|
176
|
+
* @default 'horizontal'
|
|
177
|
+
*/
|
|
178
|
+
orientation?: NonNullable<StepperVariantProps['orientation']>;
|
|
179
|
+
/**
|
|
180
|
+
* Size variant controlling indicator dimensions and text sizes.
|
|
181
|
+
* @default 'md'
|
|
182
|
+
*/
|
|
183
|
+
size?: NonNullable<StepperVariantProps['size']>;
|
|
184
|
+
/**
|
|
185
|
+
* Color theme for active/completed indicators and separators.
|
|
186
|
+
* @default 'primary'
|
|
187
|
+
*/
|
|
188
|
+
color?: NonNullable<StepperVariantProps['color']>;
|
|
189
|
+
/**
|
|
190
|
+
* Whether to render the content panel for the active step.
|
|
191
|
+
* Disable when step content lives elsewhere in the layout.
|
|
192
|
+
* @default true
|
|
193
|
+
*/
|
|
194
|
+
content?: boolean;
|
|
195
|
+
/**
|
|
196
|
+
* Additional CSS classes for the root element.
|
|
197
|
+
*/
|
|
198
|
+
class?: ClassNameValue;
|
|
199
|
+
/**
|
|
200
|
+
* Override classes for component slots.
|
|
201
|
+
*/
|
|
202
|
+
ui?: Partial<Record<StepperSlots, ClassNameValue>>;
|
|
203
|
+
/**
|
|
204
|
+
* Custom indicator content. Receives `{ item, index, number, state, active }`.
|
|
205
|
+
* Replaces the default number/check/icon rendering.
|
|
206
|
+
*/
|
|
207
|
+
indicator?: Snippet<[StepperSlotProps]>;
|
|
208
|
+
/**
|
|
209
|
+
* Custom title renderer for every step.
|
|
210
|
+
* Falls back to `item.title` when omitted.
|
|
211
|
+
*/
|
|
212
|
+
titleSlot?: Snippet<[StepperSlotProps]>;
|
|
213
|
+
/**
|
|
214
|
+
* Custom description renderer for every step.
|
|
215
|
+
* Falls back to `item.description` when omitted.
|
|
216
|
+
*/
|
|
217
|
+
descriptionSlot?: Snippet<[StepperSlotProps]>;
|
|
218
|
+
/**
|
|
219
|
+
* Custom body content shown in the active step's content panel.
|
|
220
|
+
* Falls back to `item.content` text when omitted.
|
|
221
|
+
*/
|
|
222
|
+
body?: Snippet<[StepperSlotProps]>;
|
|
223
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|