sv5ui 2.2.0 → 2.3.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/components/Error/Error.svelte +89 -0
- package/dist/components/Error/Error.svelte.d.ts +5 -0
- package/dist/components/Error/error.types.d.ts +87 -0
- package/dist/components/Error/error.types.js +1 -0
- package/dist/components/Error/error.variants.d.ts +66 -0
- package/dist/components/Error/error.variants.js +16 -0
- package/dist/components/Error/index.d.ts +2 -0
- package/dist/components/Error/index.js +1 -0
- package/dist/components/Footer/Footer.svelte +71 -0
- package/dist/components/Footer/Footer.svelte.d.ts +5 -0
- package/dist/components/Footer/FooterColumns.svelte +110 -0
- package/dist/components/Footer/FooterColumns.svelte.d.ts +5 -0
- package/dist/components/Footer/footer-columns.types.d.ts +73 -0
- package/dist/components/Footer/footer-columns.types.js +1 -0
- package/dist/components/Footer/footer-columns.variants.d.ts +108 -0
- package/dist/components/Footer/footer-columns.variants.js +23 -0
- package/dist/components/Footer/footer.types.d.ts +46 -0
- package/dist/components/Footer/footer.types.js +1 -0
- package/dist/components/Footer/footer.variants.d.ts +66 -0
- package/dist/components/Footer/footer.variants.js +16 -0
- package/dist/components/Footer/index.d.ts +4 -0
- package/dist/components/Footer/index.js +2 -0
- package/dist/components/Header/Header.svelte +177 -0
- package/dist/components/Header/Header.svelte.d.ts +5 -0
- package/dist/components/Header/header.types.d.ts +124 -0
- package/dist/components/Header/header.types.js +1 -0
- package/dist/components/Header/header.variants.d.ts +108 -0
- package/dist/components/Header/header.variants.js +32 -0
- package/dist/components/Header/index.d.ts +2 -0
- package/dist/components/Header/index.js +1 -0
- package/dist/components/Main/Main.svelte +20 -0
- package/dist/components/Main/Main.svelte.d.ts +5 -0
- package/dist/components/Main/index.d.ts +2 -0
- package/dist/components/Main/index.js +1 -0
- package/dist/components/Main/main.types.d.ts +27 -0
- package/dist/components/Main/main.types.js +1 -0
- package/dist/components/Main/main.variants.d.ts +30 -0
- package/dist/components/Main/main.variants.js +10 -0
- package/dist/components/Tour/Tour.svelte +459 -0
- package/dist/components/Tour/Tour.svelte.d.ts +5 -0
- package/dist/components/Tour/index.d.ts +2 -0
- package/dist/components/Tour/index.js +1 -0
- package/dist/components/Tour/tour.types.d.ts +457 -0
- package/dist/components/Tour/tour.types.js +1 -0
- package/dist/components/Tour/tour.variants.d.ts +208 -0
- package/dist/components/Tour/tour.variants.js +56 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +2 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useTour/index.d.ts +1 -0
- package/dist/hooks/useTour/index.js +1 -0
- package/dist/hooks/useTour/useTour.svelte.d.ts +29 -0
- package/dist/hooks/useTour/useTour.svelte.js +194 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/theme.css +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const mainVariants: import("tailwind-variants").TVReturnType<{
|
|
2
|
+
[key: string]: {
|
|
3
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
4
|
+
root?: import("tailwind-merge").ClassNameValue;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
} | {
|
|
8
|
+
[x: string]: {
|
|
9
|
+
[x: string]: import("tailwind-merge").ClassNameValue | {
|
|
10
|
+
root?: import("tailwind-merge").ClassNameValue;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
} | {}, {
|
|
14
|
+
root: string;
|
|
15
|
+
}, undefined, {
|
|
16
|
+
[key: string]: {
|
|
17
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
18
|
+
root?: import("tailwind-merge").ClassNameValue;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
} | {}, {
|
|
22
|
+
root: string;
|
|
23
|
+
}, import("tailwind-variants").TVReturnType<unknown, {
|
|
24
|
+
root: string;
|
|
25
|
+
}, undefined, unknown, unknown, undefined>>;
|
|
26
|
+
export type MainSlots = keyof ReturnType<typeof mainVariants>;
|
|
27
|
+
export declare const mainDefaults: {
|
|
28
|
+
defaultVariants: Record<string, never>;
|
|
29
|
+
slots: Partial<Record<MainSlots, string>>;
|
|
30
|
+
};
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
<script lang="ts" module>let uidCounter = 0;
|
|
2
|
+
</script>
|
|
3
|
+
|
|
4
|
+
<script lang="ts">import { untrack } from "svelte";
|
|
5
|
+
import { Portal } from "bits-ui";
|
|
6
|
+
import { computePosition, autoUpdate, offset, flip, shift, arrow } from "@floating-ui/dom";
|
|
7
|
+
import { tourVariants, tourDefaults } from "./tour.variants.js";
|
|
8
|
+
import { getComponentConfig, iconsDefaults } from "../../config.js";
|
|
9
|
+
import { useTour } from "../../hooks/useTour/index.js";
|
|
10
|
+
import { useFocusTrap } from "../../hooks/useFocusTrap/index.js";
|
|
11
|
+
import { useEventListener } from "../../hooks/useEventListener/index.js";
|
|
12
|
+
import { useMediaQuery } from "../../hooks/useMediaQuery/index.js";
|
|
13
|
+
import Button from "../Button/Button.svelte";
|
|
14
|
+
const config = getComponentConfig("tour", tourDefaults);
|
|
15
|
+
const icons = getComponentConfig("icons", iconsDefaults);
|
|
16
|
+
let {
|
|
17
|
+
steps,
|
|
18
|
+
controller,
|
|
19
|
+
api = $bindable(),
|
|
20
|
+
defaultStep = 0,
|
|
21
|
+
onOpenChange,
|
|
22
|
+
onStepChange,
|
|
23
|
+
onStart,
|
|
24
|
+
onComplete,
|
|
25
|
+
onSkip,
|
|
26
|
+
placement = "bottom",
|
|
27
|
+
sideOffset = 12,
|
|
28
|
+
spotlight = true,
|
|
29
|
+
spotlightPadding = 8,
|
|
30
|
+
spotlightRadius = 8,
|
|
31
|
+
spotlightInteractable = false,
|
|
32
|
+
scrollIntoView = true,
|
|
33
|
+
waitForTarget = 2e3,
|
|
34
|
+
dismissible = false,
|
|
35
|
+
arrow: showArrow = true,
|
|
36
|
+
prevLabel = "Back",
|
|
37
|
+
nextLabel = "Next",
|
|
38
|
+
doneLabel = "Done",
|
|
39
|
+
skipLabel = "Skip",
|
|
40
|
+
showProgress = true,
|
|
41
|
+
showSkip = true,
|
|
42
|
+
size = "md",
|
|
43
|
+
transition = config.defaultVariants.transition ?? true,
|
|
44
|
+
portal = true,
|
|
45
|
+
class: className,
|
|
46
|
+
ui,
|
|
47
|
+
header: headerSlot,
|
|
48
|
+
footer: footerSlot,
|
|
49
|
+
content: contentSlot,
|
|
50
|
+
...restProps
|
|
51
|
+
} = $props();
|
|
52
|
+
const ctrl = untrack(() => controller) ?? useTour({
|
|
53
|
+
get steps() {
|
|
54
|
+
return steps;
|
|
55
|
+
},
|
|
56
|
+
get defaultStep() {
|
|
57
|
+
return defaultStep;
|
|
58
|
+
},
|
|
59
|
+
get onStart() {
|
|
60
|
+
return onStart;
|
|
61
|
+
},
|
|
62
|
+
get onComplete() {
|
|
63
|
+
return onComplete;
|
|
64
|
+
},
|
|
65
|
+
get onSkip() {
|
|
66
|
+
return onSkip;
|
|
67
|
+
},
|
|
68
|
+
get onStepChange() {
|
|
69
|
+
return onStepChange;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
$effect(() => {
|
|
73
|
+
api = ctrl;
|
|
74
|
+
});
|
|
75
|
+
const reduceMotion = useMediaQuery("(prefers-reduced-motion: reduce)");
|
|
76
|
+
const animate = $derived(transition && !reduceMotion.matches);
|
|
77
|
+
const active = $derived(ctrl.isActive);
|
|
78
|
+
const index = $derived(ctrl.currentIndex);
|
|
79
|
+
const step = $derived(index >= 0 ? steps[index] : void 0);
|
|
80
|
+
const uid = `sv5ui-tour-${++uidCounter}`;
|
|
81
|
+
const titleId = `${uid}-title`;
|
|
82
|
+
const descId = `${uid}-desc`;
|
|
83
|
+
let panelEl = $state(null);
|
|
84
|
+
let arrowEl = $state(null);
|
|
85
|
+
let targetEl = $state(null);
|
|
86
|
+
let rect = $state(null);
|
|
87
|
+
let panelPos = $state({ x: 0, y: 0 });
|
|
88
|
+
let arrowPos = $state({});
|
|
89
|
+
let resolvedPlacement = $state(untrack(() => placement));
|
|
90
|
+
let ready = $state(false);
|
|
91
|
+
const side = $derived(resolvedPlacement.split("-")[0]);
|
|
92
|
+
const stepPadding = $derived(step?.spotlightPadding ?? spotlightPadding);
|
|
93
|
+
const stepRadius = $derived(step?.spotlightRadius ?? spotlightRadius);
|
|
94
|
+
const stepInteractable = $derived(step?.spotlightInteractable ?? spotlightInteractable);
|
|
95
|
+
const showSpotlight = $derived(spotlight && !step?.disableSpotlight && !!targetEl && !!rect);
|
|
96
|
+
const isDialog = $derived(!step?.target || !targetEl);
|
|
97
|
+
const variantSlots = $derived(tourVariants({ size, transition: animate }));
|
|
98
|
+
const classes = $derived({
|
|
99
|
+
overlay: variantSlots.overlay({ class: [config.slots.overlay, ui?.overlay] }),
|
|
100
|
+
spotlight: variantSlots.spotlight({ class: [config.slots.spotlight, ui?.spotlight] }),
|
|
101
|
+
panel: variantSlots.panel({
|
|
102
|
+
class: [config.slots.panel, ui?.panel, className, step?.class]
|
|
103
|
+
}),
|
|
104
|
+
arrow: variantSlots.arrow({ class: [config.slots.arrow, ui?.arrow] }),
|
|
105
|
+
header: variantSlots.header({ class: [config.slots.header, ui?.header] }),
|
|
106
|
+
title: variantSlots.title({ class: [config.slots.title, ui?.title] }),
|
|
107
|
+
description: variantSlots.description({
|
|
108
|
+
class: [config.slots.description, ui?.description]
|
|
109
|
+
}),
|
|
110
|
+
body: variantSlots.body({ class: [config.slots.body, ui?.body] }),
|
|
111
|
+
footer: variantSlots.footer({ class: [config.slots.footer, ui?.footer] }),
|
|
112
|
+
progress: variantSlots.progress({ class: [config.slots.progress, ui?.progress] }),
|
|
113
|
+
nav: variantSlots.nav({ class: [config.slots.nav, ui?.nav] }),
|
|
114
|
+
skipButton: variantSlots.skipButton({ class: [config.slots.skipButton, ui?.skipButton] }),
|
|
115
|
+
closeButton: variantSlots.closeButton({
|
|
116
|
+
class: [config.slots.closeButton, ui?.closeButton]
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
function normalizeWait(value) {
|
|
120
|
+
if (value === void 0)
|
|
121
|
+
return typeof waitForTarget === "number" ? waitForTarget : waitForTarget ? 2e3 : 0;
|
|
122
|
+
if (value === true) return 2e3;
|
|
123
|
+
if (value === false) return 0;
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
async function resolveTarget(target, waitMs) {
|
|
127
|
+
if (target === null || target === void 0) return null;
|
|
128
|
+
if (target instanceof HTMLElement) return target;
|
|
129
|
+
const get = typeof target === "function" ? target : () => document.querySelector(target);
|
|
130
|
+
const first = get();
|
|
131
|
+
if (first || waitMs <= 0) return first;
|
|
132
|
+
return new Promise((resolve) => {
|
|
133
|
+
const start = performance.now();
|
|
134
|
+
const tick = () => {
|
|
135
|
+
const el = get();
|
|
136
|
+
if (el) return resolve(el);
|
|
137
|
+
if (performance.now() - start >= waitMs) return resolve(null);
|
|
138
|
+
requestAnimationFrame(tick);
|
|
139
|
+
};
|
|
140
|
+
requestAnimationFrame(tick);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const effectivePlacement = $derived(step?.placement ?? placement);
|
|
144
|
+
const effectiveOffset = $derived((step?.sideOffset ?? sideOffset) + (showArrow ? 6 : 0));
|
|
145
|
+
async function position() {
|
|
146
|
+
if (!targetEl || !panelEl) return;
|
|
147
|
+
const middleware = [
|
|
148
|
+
offset(effectiveOffset),
|
|
149
|
+
flip({ padding: 8, fallbackAxisSideDirection: "start" }),
|
|
150
|
+
shift({ padding: 8 })
|
|
151
|
+
];
|
|
152
|
+
if (showArrow && arrowEl) middleware.push(arrow({ element: arrowEl, padding: 8 }));
|
|
153
|
+
const result = await computePosition(targetEl, panelEl, {
|
|
154
|
+
strategy: "fixed",
|
|
155
|
+
placement: effectivePlacement,
|
|
156
|
+
middleware
|
|
157
|
+
});
|
|
158
|
+
panelPos = { x: result.x, y: result.y };
|
|
159
|
+
resolvedPlacement = result.placement;
|
|
160
|
+
arrowPos = result.middlewareData.arrow ?? {};
|
|
161
|
+
const r = targetEl.getBoundingClientRect();
|
|
162
|
+
rect = { x: r.left, y: r.top, width: r.width, height: r.height };
|
|
163
|
+
ready = true;
|
|
164
|
+
}
|
|
165
|
+
$effect(() => {
|
|
166
|
+
if (!active || !step) {
|
|
167
|
+
ready = false;
|
|
168
|
+
targetEl = null;
|
|
169
|
+
rect = null;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const current = step;
|
|
173
|
+
void index;
|
|
174
|
+
let cancelled = false;
|
|
175
|
+
let stopAuto;
|
|
176
|
+
ready = false;
|
|
177
|
+
untrack(() => {
|
|
178
|
+
;
|
|
179
|
+
(async () => {
|
|
180
|
+
await current.onEnter?.();
|
|
181
|
+
if (cancelled) return;
|
|
182
|
+
const el = await resolveTarget(current.target, normalizeWait(current.waitForTarget));
|
|
183
|
+
if (cancelled) return;
|
|
184
|
+
targetEl = el;
|
|
185
|
+
const scroll = current.scrollIntoView ?? scrollIntoView;
|
|
186
|
+
if (el && scroll) {
|
|
187
|
+
const opts = typeof scroll === "object" ? scroll : { behavior: "smooth", block: "center" };
|
|
188
|
+
el.scrollIntoView(opts);
|
|
189
|
+
}
|
|
190
|
+
if (el && panelEl) {
|
|
191
|
+
stopAuto = autoUpdate(el, panelEl, position);
|
|
192
|
+
} else {
|
|
193
|
+
rect = null;
|
|
194
|
+
ready = true;
|
|
195
|
+
}
|
|
196
|
+
})();
|
|
197
|
+
});
|
|
198
|
+
return () => {
|
|
199
|
+
cancelled = true;
|
|
200
|
+
stopAuto?.();
|
|
201
|
+
};
|
|
202
|
+
});
|
|
203
|
+
useFocusTrap(() => panelEl, { active: () => active && ready });
|
|
204
|
+
let busy = $state(false);
|
|
205
|
+
async function runGuard(guard) {
|
|
206
|
+
if (!guard) return true;
|
|
207
|
+
busy = true;
|
|
208
|
+
try {
|
|
209
|
+
return await guard();
|
|
210
|
+
} finally {
|
|
211
|
+
busy = false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async function handleNext() {
|
|
215
|
+
if (busy) return;
|
|
216
|
+
if (!await runGuard(step?.onBeforeNext)) return;
|
|
217
|
+
ctrl.next();
|
|
218
|
+
}
|
|
219
|
+
async function handlePrev() {
|
|
220
|
+
if (busy) return;
|
|
221
|
+
if (!await runGuard(step?.onBeforePrev)) return;
|
|
222
|
+
ctrl.prev();
|
|
223
|
+
}
|
|
224
|
+
function handleStop() {
|
|
225
|
+
ctrl.stop();
|
|
226
|
+
}
|
|
227
|
+
function isInteractiveTarget(el) {
|
|
228
|
+
const tag = el?.tagName;
|
|
229
|
+
return tag === "BUTTON" || tag === "A" || tag === "INPUT" || tag === "TEXTAREA";
|
|
230
|
+
}
|
|
231
|
+
useEventListener(
|
|
232
|
+
() => active ? document : null,
|
|
233
|
+
"keydown",
|
|
234
|
+
(event) => {
|
|
235
|
+
const advance = event.key === "ArrowRight" || event.key === "Enter" && !isInteractiveTarget(document.activeElement);
|
|
236
|
+
if (advance) {
|
|
237
|
+
event.preventDefault();
|
|
238
|
+
handleNext();
|
|
239
|
+
} else if (event.key === "ArrowLeft") {
|
|
240
|
+
event.preventDefault();
|
|
241
|
+
handlePrev();
|
|
242
|
+
} else if (event.key === "Escape" && dismissible) {
|
|
243
|
+
handleStop();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
let prevActive = false;
|
|
248
|
+
$effect(() => {
|
|
249
|
+
if (active !== prevActive) {
|
|
250
|
+
prevActive = active;
|
|
251
|
+
onOpenChange?.(active);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
const slotProps = $derived({
|
|
255
|
+
step,
|
|
256
|
+
index,
|
|
257
|
+
number: index + 1,
|
|
258
|
+
total: steps.length,
|
|
259
|
+
isFirst: ctrl.isFirst,
|
|
260
|
+
isLast: ctrl.isLast,
|
|
261
|
+
controller: ctrl,
|
|
262
|
+
next: handleNext,
|
|
263
|
+
prev: handlePrev,
|
|
264
|
+
stop: handleStop
|
|
265
|
+
});
|
|
266
|
+
const showPrevButton = $derived(step?.showPrev ?? !ctrl.isFirst);
|
|
267
|
+
const showSkipButton = $derived((step?.showSkip ?? showSkip) && !ctrl.isLast);
|
|
268
|
+
const nextButtonLabel = $derived(step?.nextLabel ?? (ctrl.isLast ? doneLabel : nextLabel));
|
|
269
|
+
const prevButtonLabel = $derived(step?.prevLabel ?? prevLabel);
|
|
270
|
+
const staticSide = $derived(
|
|
271
|
+
{ top: "bottom", right: "left", bottom: "top", left: "right" }[side]
|
|
272
|
+
);
|
|
273
|
+
const arrowBorder = $derived(
|
|
274
|
+
{
|
|
275
|
+
top: "border-b border-r",
|
|
276
|
+
bottom: "border-t border-l",
|
|
277
|
+
left: "border-t border-r",
|
|
278
|
+
right: "border-b border-l"
|
|
279
|
+
}[side]
|
|
280
|
+
);
|
|
281
|
+
const arrowStyle = $derived.by(() => {
|
|
282
|
+
const parts = [`${staticSide}: -6px`];
|
|
283
|
+
if (arrowPos.x !== void 0) parts.push(`left: ${arrowPos.x}px`);
|
|
284
|
+
if (arrowPos.y !== void 0) parts.push(`top: ${arrowPos.y}px`);
|
|
285
|
+
return parts.join("; ");
|
|
286
|
+
});
|
|
287
|
+
const dotIndices = $derived(steps.map((_, i) => i));
|
|
288
|
+
</script>
|
|
289
|
+
|
|
290
|
+
{#snippet defaultHeader(p: TourStepSlotProps)}
|
|
291
|
+
<div class={classes.header}>
|
|
292
|
+
<div class="min-w-0">
|
|
293
|
+
{#if p.step.title}
|
|
294
|
+
<p id={titleId} class={classes.title}>{p.step.title}</p>
|
|
295
|
+
{/if}
|
|
296
|
+
</div>
|
|
297
|
+
{#if dismissible}
|
|
298
|
+
<Button
|
|
299
|
+
class={classes.closeButton}
|
|
300
|
+
size="xs"
|
|
301
|
+
variant="ghost"
|
|
302
|
+
color="surface"
|
|
303
|
+
square
|
|
304
|
+
icon={icons.close}
|
|
305
|
+
aria-label="Close tour"
|
|
306
|
+
onclick={handleStop}
|
|
307
|
+
/>
|
|
308
|
+
{/if}
|
|
309
|
+
</div>
|
|
310
|
+
{/snippet}
|
|
311
|
+
|
|
312
|
+
{#snippet defaultBody(p: TourStepSlotProps)}
|
|
313
|
+
<div class={classes.body}>
|
|
314
|
+
{#if p.step.content}
|
|
315
|
+
{@render p.step.content(p)}
|
|
316
|
+
{:else if p.step.description}
|
|
317
|
+
<p id={descId}>{p.step.description}</p>
|
|
318
|
+
{/if}
|
|
319
|
+
</div>
|
|
320
|
+
{/snippet}
|
|
321
|
+
|
|
322
|
+
{#snippet defaultFooter()}
|
|
323
|
+
<div class={classes.footer}>
|
|
324
|
+
{#if showProgress}
|
|
325
|
+
<div class={classes.progress}>
|
|
326
|
+
{#each dotIndices as i (i)}
|
|
327
|
+
<span
|
|
328
|
+
class={variantSlots.progressDot({
|
|
329
|
+
active: i === index,
|
|
330
|
+
class: [config.slots.progressDot, ui?.progressDot]
|
|
331
|
+
})}
|
|
332
|
+
></span>
|
|
333
|
+
{/each}
|
|
334
|
+
</div>
|
|
335
|
+
{:else}
|
|
336
|
+
<span></span>
|
|
337
|
+
{/if}
|
|
338
|
+
|
|
339
|
+
<div class={classes.nav}>
|
|
340
|
+
{#if showSkipButton}
|
|
341
|
+
<Button
|
|
342
|
+
class={classes.skipButton}
|
|
343
|
+
size="sm"
|
|
344
|
+
variant="ghost"
|
|
345
|
+
color="surface"
|
|
346
|
+
label={skipLabel}
|
|
347
|
+
onclick={handleStop}
|
|
348
|
+
/>
|
|
349
|
+
{/if}
|
|
350
|
+
{#if showPrevButton}
|
|
351
|
+
<Button
|
|
352
|
+
class={variantSlots.prevButton({
|
|
353
|
+
class: [config.slots.prevButton, ui?.prevButton]
|
|
354
|
+
})}
|
|
355
|
+
size="sm"
|
|
356
|
+
variant="soft"
|
|
357
|
+
color="surface"
|
|
358
|
+
label={prevButtonLabel}
|
|
359
|
+
disabled={busy}
|
|
360
|
+
onclick={handlePrev}
|
|
361
|
+
/>
|
|
362
|
+
{/if}
|
|
363
|
+
<Button
|
|
364
|
+
class={variantSlots.nextButton({
|
|
365
|
+
class: [config.slots.nextButton, ui?.nextButton]
|
|
366
|
+
})}
|
|
367
|
+
size="sm"
|
|
368
|
+
variant="solid"
|
|
369
|
+
color="primary"
|
|
370
|
+
label={nextButtonLabel}
|
|
371
|
+
loading={busy}
|
|
372
|
+
onclick={handleNext}
|
|
373
|
+
/>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
{/snippet}
|
|
377
|
+
|
|
378
|
+
{#snippet tourPanel()}
|
|
379
|
+
{#if active && step}
|
|
380
|
+
{#if showSpotlight}
|
|
381
|
+
{#if !stepInteractable}
|
|
382
|
+
<div
|
|
383
|
+
class={classes.overlay}
|
|
384
|
+
onclick={dismissible ? handleStop : undefined}
|
|
385
|
+
role="presentation"
|
|
386
|
+
></div>
|
|
387
|
+
{/if}
|
|
388
|
+
<div
|
|
389
|
+
class={classes.spotlight}
|
|
390
|
+
style:width="{(rect?.width ?? 0) + stepPadding * 2}px"
|
|
391
|
+
style:height="{(rect?.height ?? 0) + stepPadding * 2}px"
|
|
392
|
+
style:border-radius="{stepRadius}px"
|
|
393
|
+
style:transform="translate({(rect?.x ?? 0) - stepPadding}px, {(rect?.y ?? 0) -
|
|
394
|
+
stepPadding}px)"
|
|
395
|
+
></div>
|
|
396
|
+
{:else}
|
|
397
|
+
<div
|
|
398
|
+
class={classes.overlay}
|
|
399
|
+
style:background-color="rgba(0,0,0,0.5)"
|
|
400
|
+
onclick={dismissible ? handleStop : undefined}
|
|
401
|
+
role="presentation"
|
|
402
|
+
></div>
|
|
403
|
+
{/if}
|
|
404
|
+
|
|
405
|
+
<div
|
|
406
|
+
bind:this={panelEl}
|
|
407
|
+
class={classes.panel}
|
|
408
|
+
role="dialog"
|
|
409
|
+
aria-modal="false"
|
|
410
|
+
aria-labelledby={step.title ? titleId : undefined}
|
|
411
|
+
aria-describedby={step.description ? descId : undefined}
|
|
412
|
+
data-state={ready ? 'open' : 'closed'}
|
|
413
|
+
style:position="fixed"
|
|
414
|
+
style:left={isDialog ? '50%' : `${panelPos.x}px`}
|
|
415
|
+
style:top={isDialog ? '50%' : `${panelPos.y}px`}
|
|
416
|
+
style:transform={isDialog ? 'translate(-50%, -50%)' : undefined}
|
|
417
|
+
style:opacity={ready ? undefined : '0'}
|
|
418
|
+
{...restProps}
|
|
419
|
+
>
|
|
420
|
+
{#if showArrow && !isDialog}
|
|
421
|
+
<div
|
|
422
|
+
bind:this={arrowEl}
|
|
423
|
+
class="absolute size-3 rotate-45 {arrowBorder} {classes.arrow}"
|
|
424
|
+
style={arrowStyle}
|
|
425
|
+
></div>
|
|
426
|
+
{/if}
|
|
427
|
+
|
|
428
|
+
<div class="sr-only" aria-live="polite">
|
|
429
|
+
Step {index + 1} of {steps.length}
|
|
430
|
+
</div>
|
|
431
|
+
|
|
432
|
+
{#if contentSlot}
|
|
433
|
+
{@render contentSlot(slotProps)}
|
|
434
|
+
{:else}
|
|
435
|
+
{#if headerSlot}
|
|
436
|
+
{@render headerSlot(slotProps)}
|
|
437
|
+
{:else}
|
|
438
|
+
{@render defaultHeader(slotProps)}
|
|
439
|
+
{/if}
|
|
440
|
+
|
|
441
|
+
{@render defaultBody(slotProps)}
|
|
442
|
+
|
|
443
|
+
{#if footerSlot}
|
|
444
|
+
{@render footerSlot(slotProps)}
|
|
445
|
+
{:else}
|
|
446
|
+
{@render defaultFooter()}
|
|
447
|
+
{/if}
|
|
448
|
+
{/if}
|
|
449
|
+
</div>
|
|
450
|
+
{/if}
|
|
451
|
+
{/snippet}
|
|
452
|
+
|
|
453
|
+
{#if portal}
|
|
454
|
+
<Portal>
|
|
455
|
+
{@render tourPanel()}
|
|
456
|
+
</Portal>
|
|
457
|
+
{:else}
|
|
458
|
+
{@render tourPanel()}
|
|
459
|
+
{/if}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Tour } from './Tour.svelte';
|