sv5ui 1.6.0 → 1.7.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/Calendar/Calendar.svelte +48 -6
- package/dist/Calendar/calendar.types.d.ts +19 -0
- package/dist/Calendar/calendar.variants.js +2 -1
- package/dist/Carousel/Carousel.svelte +279 -0
- package/dist/Carousel/Carousel.svelte.d.ts +26 -0
- package/dist/Carousel/carousel.types.d.ts +242 -0
- package/dist/Carousel/carousel.types.js +1 -0
- package/dist/Carousel/carousel.variants.d.ts +408 -0
- package/dist/Carousel/carousel.variants.js +88 -0
- package/dist/Carousel/index.d.ts +2 -0
- package/dist/Carousel/index.js +1 -0
- package/dist/FileUpload/FileUpload.svelte +81 -10
- package/dist/FileUpload/file-upload.types.d.ts +39 -0
- package/dist/FileUpload/index.d.ts +1 -1
- package/dist/Modal/Modal.svelte +14 -3
- package/dist/Modal/modal.types.d.ts +15 -4
- package/dist/Modal/modal.variants.d.ts +110 -20
- package/dist/Modal/modal.variants.js +27 -9
- package/dist/PinInput/PinInput.svelte +18 -4
- package/dist/PinInput/pin-input.types.d.ts +11 -0
- package/dist/Select/Select.svelte +98 -28
- package/dist/Select/select.types.d.ts +44 -2
- package/dist/SelectMenu/SelectMenu.svelte +210 -25
- package/dist/SelectMenu/select-menu.types.d.ts +62 -1
- package/dist/SelectMenu/select-menu.variants.d.ts +26 -0
- package/dist/SelectMenu/select-menu.variants.js +34 -6
- package/dist/Slideover/Slideover.svelte +13 -2
- package/dist/Slideover/slideover.types.d.ts +14 -3
- package/dist/Slideover/slideover.variants.d.ts +85 -5
- package/dist/Slideover/slideover.variants.js +42 -12
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +6 -1
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import Icon from '../Icon/Icon.svelte'
|
|
17
17
|
import type { DateValue } from '@internationalized/date'
|
|
18
18
|
import type { Month } from 'bits-ui'
|
|
19
|
+
import { useFormField, useFormFieldEmit } from '../hooks/useFormField.svelte.js'
|
|
19
20
|
|
|
20
21
|
const config = getComponentConfig('calendar', calendarDefaults)
|
|
21
22
|
|
|
@@ -25,6 +26,8 @@
|
|
|
25
26
|
onValueChange,
|
|
26
27
|
placeholder = $bindable(),
|
|
27
28
|
onPlaceholderChange,
|
|
29
|
+
id,
|
|
30
|
+
name,
|
|
28
31
|
range = false,
|
|
29
32
|
prevMonthIcon = 'lucide:chevron-left',
|
|
30
33
|
nextMonthIcon = 'lucide:chevron-right',
|
|
@@ -42,6 +45,7 @@
|
|
|
42
45
|
weekdayFormat = 'short',
|
|
43
46
|
isDateDisabled,
|
|
44
47
|
isDateUnavailable,
|
|
48
|
+
isDateHighlightable,
|
|
45
49
|
fixedWeeks = true,
|
|
46
50
|
numberOfMonths = 1,
|
|
47
51
|
calendarLabel,
|
|
@@ -59,11 +63,31 @@
|
|
|
59
63
|
...restProps
|
|
60
64
|
}: Props = $props()
|
|
61
65
|
|
|
66
|
+
const formFieldContext = useFormField()
|
|
67
|
+
const emit = useFormFieldEmit()
|
|
68
|
+
|
|
69
|
+
const hasError = $derived(
|
|
70
|
+
formFieldContext?.error !== undefined && formFieldContext?.error !== false
|
|
71
|
+
)
|
|
72
|
+
const resolvedColor = $derived(hasError ? 'error' : color)
|
|
73
|
+
const resolvedSize = $derived(size ?? formFieldContext?.size)
|
|
74
|
+
const resolvedId = $derived(id ?? formFieldContext?.ariaId)
|
|
75
|
+
const resolvedName = $derived(name ?? formFieldContext?.name)
|
|
76
|
+
const ariaDescribedBy = $derived(
|
|
77
|
+
!formFieldContext
|
|
78
|
+
? undefined
|
|
79
|
+
: hasError
|
|
80
|
+
? `${formFieldContext.ariaId}-error`
|
|
81
|
+
: `${formFieldContext.ariaId}-description ${formFieldContext.ariaId}-help`
|
|
82
|
+
)
|
|
83
|
+
|
|
62
84
|
// Only Cell and Day differ between Calendar & RangeCalendar
|
|
63
85
|
const CalCell = $derived(range ? RangeCalendar.Cell : Calendar.Cell)
|
|
64
86
|
const CalDay = $derived(range ? RangeCalendar.Day : Calendar.Day)
|
|
65
87
|
|
|
66
|
-
const variantSlots = $derived(
|
|
88
|
+
const variantSlots = $derived(
|
|
89
|
+
calendarVariants({ color: resolvedColor, size: resolvedSize, variant, weekNumbers })
|
|
90
|
+
)
|
|
67
91
|
const classes = $derived({
|
|
68
92
|
root: variantSlots.root({ class: [config.slots.root, className, ui?.root] }),
|
|
69
93
|
header: variantSlots.header({ class: [config.slots.header, ui?.header] }),
|
|
@@ -95,6 +119,7 @@
|
|
|
95
119
|
}
|
|
96
120
|
|
|
97
121
|
const commonProps = $derived({
|
|
122
|
+
id: resolvedId,
|
|
98
123
|
placeholder,
|
|
99
124
|
onPlaceholderChange: (val: DateValue) => {
|
|
100
125
|
placeholder = val
|
|
@@ -114,8 +139,18 @@
|
|
|
114
139
|
calendarLabel,
|
|
115
140
|
locale,
|
|
116
141
|
readonly,
|
|
117
|
-
disableDaysOutsideMonth
|
|
142
|
+
disableDaysOutsideMonth,
|
|
143
|
+
'aria-describedby': ariaDescribedBy,
|
|
144
|
+
'aria-invalid': hasError ? true : undefined,
|
|
145
|
+
'data-name': resolvedName,
|
|
146
|
+
onfocusin: () => emit.onFocus(),
|
|
147
|
+
onfocusout: () => emit.onBlur()
|
|
118
148
|
})
|
|
149
|
+
|
|
150
|
+
function handleValueChange(val: unknown) {
|
|
151
|
+
;(onValueChange as ((value: unknown) => void) | undefined)?.(val)
|
|
152
|
+
emit.onChange()
|
|
153
|
+
}
|
|
119
154
|
</script>
|
|
120
155
|
|
|
121
156
|
{#snippet calendarContent(months: Month<DateValue>[], weekdays: string[])}
|
|
@@ -203,7 +238,12 @@
|
|
|
203
238
|
<CalCell {date} month={month.value} class={classes.cell}>
|
|
204
239
|
<CalDay class={classes.cellTrigger}>
|
|
205
240
|
{#snippet child({ props })}
|
|
206
|
-
<span
|
|
241
|
+
<span
|
|
242
|
+
{...props}
|
|
243
|
+
data-marked={isDateHighlightable?.(date)
|
|
244
|
+
? ''
|
|
245
|
+
: undefined}
|
|
246
|
+
>
|
|
207
247
|
{#if daySlot}
|
|
208
248
|
{@render daySlot({ day: date })}
|
|
209
249
|
{:else}
|
|
@@ -248,7 +288,7 @@
|
|
|
248
288
|
<RangeCalendar.Root
|
|
249
289
|
bind:ref
|
|
250
290
|
bind:value={value as CalendarRangeProps['value']}
|
|
251
|
-
onValueChange={
|
|
291
|
+
onValueChange={handleValueChange as CalendarRangeProps['onValueChange']}
|
|
252
292
|
{...commonProps}
|
|
253
293
|
minDays={rp.minDays}
|
|
254
294
|
maxDays={rp.maxDays}
|
|
@@ -265,12 +305,14 @@
|
|
|
265
305
|
{@const calType = (restProps as { type?: 'single' | 'multiple' }).type ?? 'single'}
|
|
266
306
|
{@const calInitialFocus = (restProps as { initialFocus?: boolean }).initialFocus}
|
|
267
307
|
{#if calType === 'multiple'}
|
|
308
|
+
{@const calMaxDays = (restProps as { maxDays?: number }).maxDays}
|
|
268
309
|
<Calendar.Root
|
|
269
310
|
bind:ref
|
|
270
311
|
bind:value={value as CalendarMultipleProps['value']}
|
|
271
|
-
onValueChange={
|
|
312
|
+
onValueChange={handleValueChange as CalendarMultipleProps['onValueChange']}
|
|
272
313
|
{...commonProps}
|
|
273
314
|
type="multiple"
|
|
315
|
+
maxDays={calMaxDays}
|
|
274
316
|
initialFocus={calInitialFocus}
|
|
275
317
|
class={classes.root}
|
|
276
318
|
>
|
|
@@ -282,7 +324,7 @@
|
|
|
282
324
|
<Calendar.Root
|
|
283
325
|
bind:ref
|
|
284
326
|
bind:value={value as CalendarSingleProps['value']}
|
|
285
|
-
onValueChange={
|
|
327
|
+
onValueChange={handleValueChange as CalendarSingleProps['onValueChange']}
|
|
286
328
|
{...commonProps}
|
|
287
329
|
type="single"
|
|
288
330
|
initialFocus={calInitialFocus}
|
|
@@ -31,6 +31,15 @@ type SharedCalendarRootProps = {
|
|
|
31
31
|
weekdayFormat?: Intl.DateTimeFormatOptions['weekday'];
|
|
32
32
|
isDateDisabled?: DateMatcher;
|
|
33
33
|
isDateUnavailable?: DateMatcher;
|
|
34
|
+
/**
|
|
35
|
+
* Predicate that returns `true` for dates that should be visually marked
|
|
36
|
+
* (e.g. holidays, events). Marked dates remain selectable; only their
|
|
37
|
+
* appearance changes. The cell trigger gets a `data-marked` attribute
|
|
38
|
+
* which the variants render as a small dot indicator.
|
|
39
|
+
*
|
|
40
|
+
* Called for every visible cell, so keep it cheap and pure.
|
|
41
|
+
*/
|
|
42
|
+
isDateHighlightable?: DateMatcher;
|
|
34
43
|
/** @default true */
|
|
35
44
|
fixedWeeks?: boolean;
|
|
36
45
|
/** @default 1 */
|
|
@@ -48,6 +57,16 @@ type BaseCalendarProps = {
|
|
|
48
57
|
* Bindable reference to the root DOM element.
|
|
49
58
|
*/
|
|
50
59
|
ref?: HTMLElement | null;
|
|
60
|
+
/**
|
|
61
|
+
* The HTML `id` attribute for the root element. Used by a parent
|
|
62
|
+
* `<FormField>` so the label's `for` attribute can target the calendar.
|
|
63
|
+
*/
|
|
64
|
+
id?: string;
|
|
65
|
+
/**
|
|
66
|
+
* The field name. Used by a parent `<Form>` to look up validation state
|
|
67
|
+
* for this calendar when wrapped in `<FormField>`.
|
|
68
|
+
*/
|
|
69
|
+
name?: string;
|
|
51
70
|
/** @default 'lucide:chevron-left' */
|
|
52
71
|
prevMonthIcon?: string;
|
|
53
72
|
/** @default 'lucide:chevron-right' */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { tv } from 'tailwind-variants';
|
|
2
2
|
export const calendarVariants = tv({
|
|
3
3
|
slots: {
|
|
4
|
-
root: '',
|
|
4
|
+
root: 'w-fit',
|
|
5
5
|
header: 'flex items-center justify-between',
|
|
6
6
|
body: 'flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0',
|
|
7
7
|
heading: 'text-center font-medium truncate mx-auto',
|
|
@@ -19,6 +19,7 @@ export const calendarVariants = tv({
|
|
|
19
19
|
'data-unavailable:line-through data-unavailable:text-on-surface-variant data-unavailable:pointer-events-none',
|
|
20
20
|
'data-today:font-semibold',
|
|
21
21
|
'data-[outside-month]:text-on-surface-variant',
|
|
22
|
+
'data-[marked]:after:content-[""] data-[marked]:after:absolute data-[marked]:after:bottom-0.5 data-[marked]:after:left-1/2 data-[marked]:after:-translate-x-1/2 data-[marked]:after:size-1 data-[marked]:after:rounded-full data-[marked]:after:bg-current',
|
|
22
23
|
'transition'
|
|
23
24
|
],
|
|
24
25
|
cellWeek: 'relative text-center text-on-surface-variant',
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { CarouselAutoplayOptions, CarouselProps } from './carousel.types.js'
|
|
3
|
+
|
|
4
|
+
export type Props<T = unknown> = CarouselProps<T>
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script lang="ts" generics="T = unknown">
|
|
8
|
+
import useEmblaCarousel from 'embla-carousel-svelte'
|
|
9
|
+
import type { EmblaCarouselType, EmblaOptionsType, EmblaPluginType } from 'embla-carousel'
|
|
10
|
+
import Autoplay from 'embla-carousel-autoplay'
|
|
11
|
+
import Fade from 'embla-carousel-fade'
|
|
12
|
+
import ClassNames from 'embla-carousel-class-names'
|
|
13
|
+
import { untrack } from 'svelte'
|
|
14
|
+
import { carouselVariants, carouselDefaults } from './carousel.variants.js'
|
|
15
|
+
import { getComponentConfig } from '../config.js'
|
|
16
|
+
import Button from '../Button/Button.svelte'
|
|
17
|
+
|
|
18
|
+
const config = getComponentConfig('carousel', carouselDefaults)
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
ref = $bindable(null),
|
|
22
|
+
api = $bindable<EmblaCarouselType | undefined>(),
|
|
23
|
+
items,
|
|
24
|
+
index = $bindable(0),
|
|
25
|
+
onIndexChange,
|
|
26
|
+
onSettle,
|
|
27
|
+
slidesToShow = 1,
|
|
28
|
+
loop = false,
|
|
29
|
+
align = 'start',
|
|
30
|
+
orientation = 'horizontal',
|
|
31
|
+
draggable = true,
|
|
32
|
+
dragFree = false,
|
|
33
|
+
slidesToScroll = 1,
|
|
34
|
+
autoplay = false,
|
|
35
|
+
fade = false,
|
|
36
|
+
classNames = false,
|
|
37
|
+
breakpoints,
|
|
38
|
+
plugins: extraPlugins,
|
|
39
|
+
options: optionsOverride,
|
|
40
|
+
arrows = true,
|
|
41
|
+
dots = true,
|
|
42
|
+
prevIcon,
|
|
43
|
+
nextIcon,
|
|
44
|
+
color = config.defaultVariants.color,
|
|
45
|
+
size = config.defaultVariants.size,
|
|
46
|
+
variant = config.defaultVariants.variant,
|
|
47
|
+
class: className,
|
|
48
|
+
ui,
|
|
49
|
+
slide: slideSnippet,
|
|
50
|
+
dot: dotSnippet,
|
|
51
|
+
prevSlot,
|
|
52
|
+
nextSlot,
|
|
53
|
+
children
|
|
54
|
+
}: Props<T> = $props()
|
|
55
|
+
|
|
56
|
+
let selectedIndex = $state(0)
|
|
57
|
+
let scrollSnaps = $state<number[]>([])
|
|
58
|
+
let canScrollPrev = $state(false)
|
|
59
|
+
let canScrollNext = $state(false)
|
|
60
|
+
|
|
61
|
+
const resolvedPrevIcon = $derived(
|
|
62
|
+
prevIcon ?? (orientation === 'vertical' ? 'lucide:chevron-up' : 'lucide:chevron-left')
|
|
63
|
+
)
|
|
64
|
+
const resolvedNextIcon = $derived(
|
|
65
|
+
nextIcon ?? (orientation === 'vertical' ? 'lucide:chevron-down' : 'lucide:chevron-right')
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
function buildAutoplay(opts: CarouselAutoplayOptions) {
|
|
69
|
+
return Autoplay({
|
|
70
|
+
delay: opts.delay ?? 4000,
|
|
71
|
+
stopOnInteraction: opts.stopOnInteraction ?? false,
|
|
72
|
+
stopOnMouseEnter: opts.stopOnMouseEnter ?? true,
|
|
73
|
+
stopOnFocusIn: opts.stopOnFocusIn ?? true,
|
|
74
|
+
stopOnLastSnap: opts.stopOnLastSnap ?? false,
|
|
75
|
+
playOnInit: opts.playOnInit ?? true
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const plugins = $derived.by<EmblaPluginType[]>(() => {
|
|
80
|
+
const list: EmblaPluginType[] = []
|
|
81
|
+
if (autoplay) list.push(buildAutoplay(typeof autoplay === 'object' ? autoplay : {}))
|
|
82
|
+
if (fade) list.push(Fade())
|
|
83
|
+
if (classNames) list.push(ClassNames())
|
|
84
|
+
if (extraPlugins) list.push(...extraPlugins)
|
|
85
|
+
return list
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
const emblaOptions = $derived.by<EmblaOptionsType>(() => ({
|
|
89
|
+
loop,
|
|
90
|
+
align,
|
|
91
|
+
axis: orientation === 'vertical' ? 'y' : 'x',
|
|
92
|
+
watchDrag: draggable,
|
|
93
|
+
dragFree,
|
|
94
|
+
slidesToScroll,
|
|
95
|
+
breakpoints,
|
|
96
|
+
...optionsOverride
|
|
97
|
+
}))
|
|
98
|
+
|
|
99
|
+
const dotIndices = $derived(scrollSnaps.map((_, i) => i))
|
|
100
|
+
|
|
101
|
+
function classListHas(cls: unknown, re: RegExp): boolean {
|
|
102
|
+
if (typeof cls === 'string') return re.test(cls)
|
|
103
|
+
if (Array.isArray(cls)) return cls.some((c) => classListHas(c, re))
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const userOverridesBasis = $derived(classListHas(ui?.slide, /\bbasis-/))
|
|
108
|
+
const containerStyle = $derived(
|
|
109
|
+
orientation === 'vertical'
|
|
110
|
+
? 'display: flex; flex-direction: column; touch-action: pan-x;'
|
|
111
|
+
: 'display: flex; flex-direction: row; touch-action: pan-y;'
|
|
112
|
+
)
|
|
113
|
+
const slideStyle = $derived.by(() => {
|
|
114
|
+
if (userOverridesBasis) return undefined
|
|
115
|
+
const minDim = orientation === 'vertical' ? 'min-height' : 'min-width'
|
|
116
|
+
return `flex: 0 0 calc(100% / ${slidesToShow}); ${minDim}: 0;`
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
const variantSlots = $derived(carouselVariants({ orientation, size, color, variant }))
|
|
120
|
+
const classes = $derived({
|
|
121
|
+
root: variantSlots.root({ class: [config.slots.root, className, ui?.root] }),
|
|
122
|
+
viewport: variantSlots.viewport({ class: [config.slots.viewport, ui?.viewport] }),
|
|
123
|
+
container: variantSlots.container({ class: [config.slots.container, ui?.container] }),
|
|
124
|
+
slide: variantSlots.slide({ class: [config.slots.slide, ui?.slide] }),
|
|
125
|
+
arrow: variantSlots.arrow({ class: [config.slots.arrow, ui?.arrow] }),
|
|
126
|
+
arrowPrev: variantSlots.arrowPrev({ class: [config.slots.arrowPrev, ui?.arrowPrev] }),
|
|
127
|
+
arrowNext: variantSlots.arrowNext({ class: [config.slots.arrowNext, ui?.arrowNext] }),
|
|
128
|
+
dots: variantSlots.dots({ class: [config.slots.dots, ui?.dots] }),
|
|
129
|
+
dot: variantSlots.dot({ class: [config.slots.dot, ui?.dot] })
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
function syncFromApi(embla: EmblaCarouselType) {
|
|
133
|
+
const newIndex = embla.selectedScrollSnap()
|
|
134
|
+
selectedIndex = newIndex
|
|
135
|
+
scrollSnaps = embla.scrollSnapList()
|
|
136
|
+
canScrollPrev = embla.canScrollPrev()
|
|
137
|
+
canScrollNext = embla.canScrollNext()
|
|
138
|
+
if (newIndex !== index) {
|
|
139
|
+
index = newIndex
|
|
140
|
+
onIndexChange?.(newIndex)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function handleEmblaInit(event: CustomEvent<EmblaCarouselType>) {
|
|
145
|
+
const embla = event.detail
|
|
146
|
+
api = embla
|
|
147
|
+
syncFromApi(embla)
|
|
148
|
+
embla.on('select', () => syncFromApi(embla))
|
|
149
|
+
embla.on('reInit', () => syncFromApi(embla))
|
|
150
|
+
if (onSettle) embla.on('settle', () => onSettle(embla))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
$effect(() => {
|
|
154
|
+
if (!api) return
|
|
155
|
+
const desired = index
|
|
156
|
+
if (desired !== untrack(() => selectedIndex)) {
|
|
157
|
+
api.scrollTo(desired)
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
function scrollPrev() {
|
|
162
|
+
if (!api) return
|
|
163
|
+
api.scrollPrev()
|
|
164
|
+
syncFromApi(api)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function scrollNext() {
|
|
168
|
+
if (!api) return
|
|
169
|
+
api.scrollNext()
|
|
170
|
+
syncFromApi(api)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function scrollTo(i: number) {
|
|
174
|
+
if (!api) return
|
|
175
|
+
api.scrollTo(i)
|
|
176
|
+
syncFromApi(api)
|
|
177
|
+
}
|
|
178
|
+
</script>
|
|
179
|
+
|
|
180
|
+
{#snippet defaultPrev()}
|
|
181
|
+
<Button
|
|
182
|
+
{color}
|
|
183
|
+
{size}
|
|
184
|
+
{variant}
|
|
185
|
+
icon={resolvedPrevIcon}
|
|
186
|
+
square
|
|
187
|
+
disabled={!canScrollPrev}
|
|
188
|
+
aria-label="Previous slide"
|
|
189
|
+
class={[classes.arrow, classes.arrowPrev]}
|
|
190
|
+
onclick={scrollPrev}
|
|
191
|
+
/>
|
|
192
|
+
{/snippet}
|
|
193
|
+
|
|
194
|
+
{#snippet defaultNext()}
|
|
195
|
+
<Button
|
|
196
|
+
{color}
|
|
197
|
+
{size}
|
|
198
|
+
{variant}
|
|
199
|
+
icon={resolvedNextIcon}
|
|
200
|
+
square
|
|
201
|
+
disabled={!canScrollNext}
|
|
202
|
+
aria-label="Next slide"
|
|
203
|
+
class={[classes.arrow, classes.arrowNext]}
|
|
204
|
+
onclick={scrollNext}
|
|
205
|
+
/>
|
|
206
|
+
{/snippet}
|
|
207
|
+
|
|
208
|
+
{#snippet defaultDot(i: number, selected: boolean)}
|
|
209
|
+
<button
|
|
210
|
+
type="button"
|
|
211
|
+
class={classes.dot}
|
|
212
|
+
data-selected={selected ? '' : undefined}
|
|
213
|
+
aria-label={`Go to slide ${i + 1}`}
|
|
214
|
+
aria-current={selected ? 'true' : undefined}
|
|
215
|
+
onclick={() => scrollTo(i)}
|
|
216
|
+
></button>
|
|
217
|
+
{/snippet}
|
|
218
|
+
|
|
219
|
+
<div
|
|
220
|
+
bind:this={ref}
|
|
221
|
+
class={classes.root}
|
|
222
|
+
data-orientation={orientation}
|
|
223
|
+
style:--sv-slides={slidesToShow}
|
|
224
|
+
>
|
|
225
|
+
<div
|
|
226
|
+
class={classes.viewport}
|
|
227
|
+
use:useEmblaCarousel={{ options: emblaOptions, plugins }}
|
|
228
|
+
onemblaInit={handleEmblaInit}
|
|
229
|
+
>
|
|
230
|
+
<div class={classes.container} style={containerStyle}>
|
|
231
|
+
{#if items}
|
|
232
|
+
{#each items as item, i (i)}
|
|
233
|
+
<div class={classes.slide} style={slideStyle} data-index={i}>
|
|
234
|
+
{#if slideSnippet}
|
|
235
|
+
{@render slideSnippet({
|
|
236
|
+
item,
|
|
237
|
+
index: i,
|
|
238
|
+
selected: i === selectedIndex
|
|
239
|
+
})}
|
|
240
|
+
{:else}
|
|
241
|
+
{String(item)}
|
|
242
|
+
{/if}
|
|
243
|
+
</div>
|
|
244
|
+
{/each}
|
|
245
|
+
{:else if children}
|
|
246
|
+
{@render children()}
|
|
247
|
+
{/if}
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
{#if arrows}
|
|
252
|
+
{#if prevSlot}
|
|
253
|
+
{@render prevSlot({ canScroll: canScrollPrev, scroll: scrollPrev })}
|
|
254
|
+
{:else}
|
|
255
|
+
{@render defaultPrev()}
|
|
256
|
+
{/if}
|
|
257
|
+
{#if nextSlot}
|
|
258
|
+
{@render nextSlot({ canScroll: canScrollNext, scroll: scrollNext })}
|
|
259
|
+
{:else}
|
|
260
|
+
{@render defaultNext()}
|
|
261
|
+
{/if}
|
|
262
|
+
{/if}
|
|
263
|
+
|
|
264
|
+
{#if dots && scrollSnaps.length > 1}
|
|
265
|
+
<div class={classes.dots} role="tablist">
|
|
266
|
+
{#each dotIndices as i (i)}
|
|
267
|
+
{#if dotSnippet}
|
|
268
|
+
{@render dotSnippet({
|
|
269
|
+
index: i,
|
|
270
|
+
selected: i === selectedIndex,
|
|
271
|
+
select: () => scrollTo(i)
|
|
272
|
+
})}
|
|
273
|
+
{:else}
|
|
274
|
+
{@render defaultDot(i, i === selectedIndex)}
|
|
275
|
+
{/if}
|
|
276
|
+
{/each}
|
|
277
|
+
</div>
|
|
278
|
+
{/if}
|
|
279
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CarouselProps } from './carousel.types.js';
|
|
2
|
+
export type Props<T = unknown> = CarouselProps<T>;
|
|
3
|
+
declare function $$render<T = unknown>(): {
|
|
4
|
+
props: Props<T>;
|
|
5
|
+
exports: {};
|
|
6
|
+
bindings: "ref" | "api" | "index";
|
|
7
|
+
slots: {};
|
|
8
|
+
events: {};
|
|
9
|
+
};
|
|
10
|
+
declare class __sveltets_Render<T = unknown> {
|
|
11
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
12
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
13
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
14
|
+
bindings(): "ref" | "api" | "index";
|
|
15
|
+
exports(): {};
|
|
16
|
+
}
|
|
17
|
+
interface $$IsomorphicComponent {
|
|
18
|
+
new <T = unknown>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
19
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
20
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
21
|
+
<T = unknown>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
22
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
23
|
+
}
|
|
24
|
+
declare const Carousel: $$IsomorphicComponent;
|
|
25
|
+
type Carousel<T = unknown> = InstanceType<typeof Carousel<T>>;
|
|
26
|
+
export default Carousel;
|