@marianmeres/stuic 3.37.0 → 3.38.1
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/AGENTS.md +5 -5
- package/API.md +137 -1
- package/README.md +4 -4
- package/dist/components/ImageCycler/ImageCycler.svelte +98 -0
- package/dist/components/ImageCycler/ImageCycler.svelte.d.ts +32 -0
- package/dist/components/ImageCycler/index.css +28 -0
- package/dist/components/ImageCycler/index.d.ts +1 -0
- package/dist/components/ImageCycler/index.js +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/docs/architecture.md +3 -3
- package/docs/domains/actions.md +25 -1
- package/docs/domains/components.md +12 -7
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
|
|
24
24
|
```
|
|
25
25
|
src/lib/
|
|
26
|
-
├── components/ #
|
|
27
|
-
├── actions/ #
|
|
26
|
+
├── components/ # 46 UI components
|
|
27
|
+
├── actions/ # 15 Svelte actions
|
|
28
28
|
├── utils/ # 43 utility modules
|
|
29
29
|
├── themes/ # 29 theme definitions (.ts) + generated CSS (css/)
|
|
30
30
|
├── icons/ # Icon re-exports
|
|
@@ -74,10 +74,10 @@ src/lib/
|
|
|
74
74
|
|
|
75
75
|
### Domain Docs
|
|
76
76
|
|
|
77
|
-
- [Components](./docs/domains/components.md) —
|
|
77
|
+
- [Components](./docs/domains/components.md) — 46 component directories, Props pattern, snippets
|
|
78
78
|
- [Theming](./docs/domains/theming.md) — CSS tokens, dark mode, themes
|
|
79
|
-
- [Actions](./docs/domains/actions.md) —
|
|
80
|
-
- [Utils](./docs/domains/utils.md) —
|
|
79
|
+
- [Actions](./docs/domains/actions.md) — 15 Svelte directives
|
|
80
|
+
- [Utils](./docs/domains/utils.md) — 43 utility modules
|
|
81
81
|
|
|
82
82
|
### Reference
|
|
83
83
|
|
package/API.md
CHANGED
|
@@ -280,6 +280,25 @@ Multi-language input field.
|
|
|
280
280
|
|
|
281
281
|
Toggle button styled as a "like" action.
|
|
282
282
|
|
|
283
|
+
#### `FieldPhoneNumber`
|
|
284
|
+
|
|
285
|
+
International phone number input with country dial code picker. Parses and composes full phone numbers (e.g. `+421905123456`), handles paste with international prefix detection, supports country filtering and preferred countries.
|
|
286
|
+
|
|
287
|
+
| Prop | Type | Default | Description |
|
|
288
|
+
| -------------------- | ----------------------------------- | ----------- | -------------------------------------------------- |
|
|
289
|
+
| `value` | `string` | `""` | Bindable full phone number (e.g. `"+421905123456"`) |
|
|
290
|
+
| `country` | `string` | `""` | Bindable selected country ISO code (e.g. `"SK"`) |
|
|
291
|
+
| `dialCode` | `string` | `""` | Bindable dial code with `+` (e.g. `"+421"`) |
|
|
292
|
+
| `localNumber` | `string` | `""` | Bindable local number part |
|
|
293
|
+
| `defaultCountry` | `string` | — | ISO code for initial country selection |
|
|
294
|
+
| `flags` | `boolean` | `true` | Show country flag emoji |
|
|
295
|
+
| `countries` | `string[]` | all | Filtered list of country ISO codes to show |
|
|
296
|
+
| `preferredCountries` | `string[]` | — | ISO codes pinned at top of dropdown |
|
|
297
|
+
| `name` | `string` | — | Hidden input name for form submission |
|
|
298
|
+
| `validate` | `boolean \| ValidateOptions` | — | Enable phone validation |
|
|
299
|
+
|
|
300
|
+
Exports: `FieldPhoneNumber`, `FieldPhoneNumberProps`, `validatePhoneNumber`, `Country`.
|
|
301
|
+
|
|
283
302
|
#### `FieldObject`
|
|
284
303
|
|
|
285
304
|
Dual-mode JSON object editor with pretty-print and raw edit modes. Validates JSON syntax, supports recursive depth display, auto-grow textarea, and form submission via hidden input.
|
|
@@ -405,7 +424,43 @@ Progress bar.
|
|
|
405
424
|
|
|
406
425
|
#### `Spinner`
|
|
407
426
|
|
|
408
|
-
Loading spinner indicator.
|
|
427
|
+
Loading spinner indicator (default SVG spinner).
|
|
428
|
+
|
|
429
|
+
#### `SpinnerCircle`
|
|
430
|
+
|
|
431
|
+
CSS-only circular spinner.
|
|
432
|
+
|
|
433
|
+
| Prop | Type | Default | Description |
|
|
434
|
+
| ----------- | --------------------------------- | ---------- | -------------------------- |
|
|
435
|
+
| `duration` | `number` | `750` | One loop duration in ms |
|
|
436
|
+
| `thickness` | `"normal" \| "thin" \| "thick"` | `"normal"` | Border thickness preset |
|
|
437
|
+
| `direction` | `"cw" \| "ccw"` | `"cw"` | Rotation direction |
|
|
438
|
+
|
|
439
|
+
#### `SpinnerCircleOscillate`
|
|
440
|
+
|
|
441
|
+
Animated Circle-based spinner with oscillating arc completeness.
|
|
442
|
+
|
|
443
|
+
| Prop | Type | Default | Description |
|
|
444
|
+
| ---------------- | --------- | ------- | ----------------------------- |
|
|
445
|
+
| `bgStrokeColor` | `string` | — | Background circle stroke |
|
|
446
|
+
| `strokeWidth` | `number` | — | SVG stroke width |
|
|
447
|
+
| `noOscillate` | `boolean` | — | Fixed completeness (no anim) |
|
|
448
|
+
| `rotateDuration` | `string` | — | CSS animation duration |
|
|
449
|
+
|
|
450
|
+
#### `SpinnerUnicode`
|
|
451
|
+
|
|
452
|
+
Unicode character frame animation with 17 built-in variants.
|
|
453
|
+
|
|
454
|
+
| Prop | Type | Default | Description |
|
|
455
|
+
| ---------- | ------------------------ | ------------------- | ---------------------------- |
|
|
456
|
+
| `speed` | `number` | `100` | Frame interval in ms |
|
|
457
|
+
| `variant` | `SpinnerUnicodeVariant` | `"braille_bar_dot"` | Built-in animation variant |
|
|
458
|
+
| `reversed` | `boolean` | `false` | Reverse frame order |
|
|
459
|
+
| `frames` | `string[]` | — | Custom animation frames |
|
|
460
|
+
|
|
461
|
+
Variants: `braille_bar`, `braille_bar_dot`, `braille_dot_circle`, `braille_dot_bounce`, `half_circle`, `quarter_circle`, `ascii`, `bar_v`, `bar_h`, `shade`, `arrows`, `arrows2`, `asterix`, `asterix2`, `asterix3`, `asterix4`, `asterix5`.
|
|
462
|
+
|
|
463
|
+
Helper: `spinnerCreateBackAndForthCharFrames(width, hiChar, loChar, glue?)` — create custom back-and-forth animation frames.
|
|
409
464
|
|
|
410
465
|
#### `Skeleton`
|
|
411
466
|
|
|
@@ -829,6 +884,30 @@ Responsive data table with paging, row selection, batch actions, and mobile card
|
|
|
829
884
|
/>
|
|
830
885
|
```
|
|
831
886
|
|
|
887
|
+
#### `ImageCycler`
|
|
888
|
+
|
|
889
|
+
Auto-cycling image carousel with fade transitions. Preloads next image before displaying. Supports custom title/description snippets.
|
|
890
|
+
|
|
891
|
+
| Prop | Type | Default | Description |
|
|
892
|
+
| -------------------- | ------------------- | --------- | ---------------------------------------- |
|
|
893
|
+
| `images` | `ImageCyclerImage[]`| required | Array of images to cycle through |
|
|
894
|
+
| `fit` | `ImageCyclerFit` | `"cover"` | CSS object-fit: `"cover"`, `"contain"`, `"fill"` |
|
|
895
|
+
| `minWait` | `number` | `3000` | Minimum wait (ms) before next image |
|
|
896
|
+
| `transitionDuration` | `number` | `500` | Fade transition duration (ms) |
|
|
897
|
+
| `onclick` | `(image, index) => void` | — | Click handler |
|
|
898
|
+
| `title` | `Snippet` | — | Custom title snippet `({ image, index, onclick })` |
|
|
899
|
+
| `description` | `Snippet` | — | Custom description snippet |
|
|
900
|
+
|
|
901
|
+
```ts
|
|
902
|
+
interface ImageCyclerImage {
|
|
903
|
+
src: string;
|
|
904
|
+
alt?: string;
|
|
905
|
+
title?: string;
|
|
906
|
+
description?: string;
|
|
907
|
+
[key: string]: unknown;
|
|
908
|
+
}
|
|
909
|
+
```
|
|
910
|
+
|
|
832
911
|
#### `ThemePreview`
|
|
833
912
|
|
|
834
913
|
Theme color swatch preview.
|
|
@@ -1215,6 +1294,63 @@ Tooltip display from `aria-label`.
|
|
|
1215
1294
|
<button use:tooltip aria-label="Save changes"> Save </button>
|
|
1216
1295
|
```
|
|
1217
1296
|
|
|
1297
|
+
### `createTour` / `tourStep` (onboarding)
|
|
1298
|
+
|
|
1299
|
+
Multi-step onboarding tour built on the spotlight primitive. Define steps centrally, attach targets via `use:tourStep`.
|
|
1300
|
+
|
|
1301
|
+
**`createTour(options)`**
|
|
1302
|
+
|
|
1303
|
+
| Option | Type | Default | Description |
|
|
1304
|
+
| ----------------- | ----------------------------- | --------- | ---------------------------------------------------- |
|
|
1305
|
+
| `steps` | `TourStepDef[]` | required | Tour step definitions |
|
|
1306
|
+
| `waitForElement` | `number` | `500` | Max wait (ms) for step element to appear |
|
|
1307
|
+
| `labels` | `TourLabels` | defaults | Default button labels (Next, Back, Skip, Finish) |
|
|
1308
|
+
| `shell` | `Snippet<[TourShellContext]>` | — | Custom shell snippet replacing default UI |
|
|
1309
|
+
| `closeOnEscape` | `boolean` | `true` | Press Escape to skip |
|
|
1310
|
+
| `confirmSkip` | `() => boolean \| Promise<boolean>` | — | Guard before skipping (return `false` to cancel) |
|
|
1311
|
+
| `storageKey` | `string` | — | Persist tour completion (skips on re-run) |
|
|
1312
|
+
| `storage` | `"local" \| "session"` | `"local"` | Storage backend for persistence |
|
|
1313
|
+
| `onStart` | `() => void` | — | Called when tour starts |
|
|
1314
|
+
| `onEnd` | `() => void` | — | Called when tour completes |
|
|
1315
|
+
| `onSkip` | `() => void` | — | Called when tour is skipped |
|
|
1316
|
+
| `onStepChange` | `(step, index) => void` | — | Called on every step change |
|
|
1317
|
+
|
|
1318
|
+
**Returns:** `{ start(), stop(), next(), prev(), skip(), reset(), active, currentStep, currentIndex }`
|
|
1319
|
+
|
|
1320
|
+
**`TourStepDef`:**
|
|
1321
|
+
|
|
1322
|
+
| Field | Type | Description |
|
|
1323
|
+
| ------------- | ------------------- | ----------------------------------------- |
|
|
1324
|
+
| `id` | `string` | Unique ID (must match `use:tourStep`) |
|
|
1325
|
+
| `title` | `string` | Step title |
|
|
1326
|
+
| `content` | `THC` | Step description (string/html/component) |
|
|
1327
|
+
| `position` | `SpotlightPosition` | Annotation placement |
|
|
1328
|
+
| `padding` | `number` | Cutout padding (px) |
|
|
1329
|
+
| `borderRadius`| `number` | Cutout border radius (px) |
|
|
1330
|
+
| `onEnter` | `() => void` | Called when entering step |
|
|
1331
|
+
| `onLeave` | `() => void` | Called when leaving step |
|
|
1332
|
+
|
|
1333
|
+
**`tourStep` action:** `use:tourStep={[tour, stepId]}`
|
|
1334
|
+
|
|
1335
|
+
```svelte
|
|
1336
|
+
<script>
|
|
1337
|
+
import { createTour, tourStep } from "@marianmeres/stuic";
|
|
1338
|
+
|
|
1339
|
+
const tour = createTour({
|
|
1340
|
+
steps: [
|
|
1341
|
+
{ id: "header", title: "Welcome", content: "This is the top." },
|
|
1342
|
+
{ id: "save-btn", title: "Save", content: "Click here to save." },
|
|
1343
|
+
],
|
|
1344
|
+
storageKey: "intro-tour",
|
|
1345
|
+
onEnd: () => console.log("Tour complete!"),
|
|
1346
|
+
});
|
|
1347
|
+
</script>
|
|
1348
|
+
|
|
1349
|
+
<header use:tourStep={[tour, "header"]}>...</header>
|
|
1350
|
+
<button use:tourStep={[tour, "save-btn"]}>Save</button>
|
|
1351
|
+
<button onclick={tour.start}>Start Tour</button>
|
|
1352
|
+
```
|
|
1353
|
+
|
|
1218
1354
|
---
|
|
1219
1355
|
|
|
1220
1356
|
## Utilities
|
package/README.md
CHANGED
|
@@ -127,7 +127,7 @@ AppShell, Accordion, Backdrop, Modal, ModalDialog, Drawer, Collapsible, SlidingP
|
|
|
127
127
|
|
|
128
128
|
### Forms & Inputs
|
|
129
129
|
|
|
130
|
-
FieldInput, FieldTextarea, FieldSelect, FieldCheckbox, FieldRadios, FieldFile, FieldAssets, FieldOptions, FieldKeyValues, FieldObject, FieldSwitch, FieldInputLocalized, FieldLikeButton, Fieldset, LoginForm, LoginFormModal
|
|
130
|
+
FieldInput, FieldTextarea, FieldSelect, FieldCheckbox, FieldRadios, FieldFile, FieldAssets, FieldOptions, FieldKeyValues, FieldObject, FieldSwitch, FieldInputLocalized, FieldLikeButton, FieldPhoneNumber, Fieldset, LoginForm, LoginFormModal
|
|
131
131
|
|
|
132
132
|
### Buttons & Controls
|
|
133
133
|
|
|
@@ -135,7 +135,7 @@ Button, ButtonGroupRadio, Switch, TwCheck, ListItemButton, X
|
|
|
135
135
|
|
|
136
136
|
### Feedback & Notifications
|
|
137
137
|
|
|
138
|
-
Notifications, AlertConfirmPrompt, DismissibleMessage, Progress, Spinner, Skeleton
|
|
138
|
+
Notifications, AlertConfirmPrompt, DismissibleMessage, Progress, Spinner (SpinnerCircle, SpinnerCircleOscillate, SpinnerUnicode), Skeleton
|
|
139
139
|
|
|
140
140
|
### Navigation & Menus
|
|
141
141
|
|
|
@@ -143,7 +143,7 @@ CommandMenu, DropdownMenu, TabbedMenu, TypeaheadInput, KbdShortcut
|
|
|
143
143
|
|
|
144
144
|
### Display & Utility
|
|
145
145
|
|
|
146
|
-
Avatar, Book, BookResponsive, Carousel, Circle, AnimatedElipsis, H, IconSwap, Separator, ThemePreview, ColorScheme, Thc, HoverExpandableWidth, AssetsPreview, AssetsPreviewInline, DataTable
|
|
146
|
+
Avatar, Book, BookResponsive, Carousel, Circle, AnimatedElipsis, H, IconSwap, ImageCycler, Separator, ThemePreview, ColorScheme, Thc, HoverExpandableWidth, AssetsPreview, AssetsPreviewInline, DataTable
|
|
147
147
|
|
|
148
148
|
### E-commerce
|
|
149
149
|
|
|
@@ -160,7 +160,7 @@ Cart, Checkout (CheckoutProgress, CheckoutOrderSummary, CheckoutCartReview, Chec
|
|
|
160
160
|
<div use:fileDropzone={() => ({ onDrop: handleFiles })}>Drop here</div>
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
`autogrow` · `validate` · `focusTrap` · `autoscroll` · `dimBehind` · `fileDropzone` · `highlightDragover` · `resizableWidth` · `spotlight` · `trim` · `typeahead` · `onSubmitValidityCheck` · `popover` · `tooltip`
|
|
163
|
+
`autogrow` · `validate` · `focusTrap` · `autoscroll` · `dimBehind` · `fileDropzone` · `highlightDragover` · `resizableWidth` · `spotlight` · `trim` · `typeahead` · `onSubmitValidityCheck` · `popover` · `tooltip` · `createTour` / `tourStep` (onboarding)
|
|
164
164
|
|
|
165
165
|
## TypeScript
|
|
166
166
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
export interface ImageCyclerImage {
|
|
5
|
+
src: string;
|
|
6
|
+
alt?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ImageCyclerFit = "cover" | "contain" | "fill";
|
|
13
|
+
|
|
14
|
+
export interface Props {
|
|
15
|
+
images: ImageCyclerImage[];
|
|
16
|
+
fit?: ImageCyclerFit;
|
|
17
|
+
minWait?: number;
|
|
18
|
+
transitionDuration?: number;
|
|
19
|
+
onclick?: (image: ImageCyclerImage, index: number) => void;
|
|
20
|
+
title?: Snippet<[{ image: ImageCyclerImage; index: number; onclick: (() => void) | undefined }]>;
|
|
21
|
+
description?: Snippet<[{ image: ImageCyclerImage; index: number; onclick: (() => void) | undefined }]>;
|
|
22
|
+
unstyled?: boolean;
|
|
23
|
+
class?: string;
|
|
24
|
+
el?: HTMLElement;
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<script lang="ts">
|
|
29
|
+
import { fade } from "svelte/transition";
|
|
30
|
+
import { preloadImg } from "../../utils/preload-img.js";
|
|
31
|
+
import { twMerge } from "../../utils/tw-merge.js";
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
images,
|
|
35
|
+
fit = "cover",
|
|
36
|
+
minWait = 3000,
|
|
37
|
+
transitionDuration = 500,
|
|
38
|
+
onclick,
|
|
39
|
+
title,
|
|
40
|
+
description,
|
|
41
|
+
unstyled = false,
|
|
42
|
+
class: classProp,
|
|
43
|
+
el = $bindable(),
|
|
44
|
+
}: Props = $props();
|
|
45
|
+
|
|
46
|
+
let currentIndex = $state(0);
|
|
47
|
+
|
|
48
|
+
let _class = $derived(unstyled ? classProp : twMerge("stuic-image-cycler", classProp));
|
|
49
|
+
|
|
50
|
+
let _onclick = $derived(onclick ? () => onclick(images[currentIndex], currentIndex) : undefined);
|
|
51
|
+
|
|
52
|
+
$effect(() => {
|
|
53
|
+
const idx = currentIndex;
|
|
54
|
+
if (images.length <= 1) return;
|
|
55
|
+
let cancelled = false;
|
|
56
|
+
const nextIndex = (idx + 1) % images.length;
|
|
57
|
+
Promise.all([
|
|
58
|
+
preloadImg({ src: images[nextIndex].src }),
|
|
59
|
+
new Promise<void>((resolve) => setTimeout(resolve, minWait)),
|
|
60
|
+
]).then(() => {
|
|
61
|
+
if (!cancelled) currentIndex = nextIndex;
|
|
62
|
+
});
|
|
63
|
+
return () => {
|
|
64
|
+
cancelled = true;
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<div bind:this={el} class={_class}>
|
|
70
|
+
{#key currentIndex}
|
|
71
|
+
<div
|
|
72
|
+
class="stuic-image-cycler-bg"
|
|
73
|
+
data-fit={!unstyled ? fit : undefined}
|
|
74
|
+
style:background-image="url({images[currentIndex].src})"
|
|
75
|
+
role="img"
|
|
76
|
+
aria-label={images[currentIndex].alt ?? images[currentIndex].title ?? ""}
|
|
77
|
+
in:fade={{ duration: transitionDuration }}
|
|
78
|
+
out:fade={{ duration: transitionDuration }}
|
|
79
|
+
></div>
|
|
80
|
+
{/key}
|
|
81
|
+
|
|
82
|
+
{#if title || description}
|
|
83
|
+
{#key currentIndex}
|
|
84
|
+
<div
|
|
85
|
+
class="stuic-image-cycler-meta"
|
|
86
|
+
in:fade={{ duration: transitionDuration }}
|
|
87
|
+
out:fade={{ duration: transitionDuration }}
|
|
88
|
+
>
|
|
89
|
+
{#if title}
|
|
90
|
+
{@render title({ image: images[currentIndex], index: currentIndex, onclick: _onclick })}
|
|
91
|
+
{/if}
|
|
92
|
+
{#if description}
|
|
93
|
+
{@render description({ image: images[currentIndex], index: currentIndex, onclick: _onclick })}
|
|
94
|
+
{/if}
|
|
95
|
+
</div>
|
|
96
|
+
{/key}
|
|
97
|
+
{/if}
|
|
98
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
export interface ImageCyclerImage {
|
|
3
|
+
src: string;
|
|
4
|
+
alt?: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export type ImageCyclerFit = "cover" | "contain" | "fill";
|
|
10
|
+
export interface Props {
|
|
11
|
+
images: ImageCyclerImage[];
|
|
12
|
+
fit?: ImageCyclerFit;
|
|
13
|
+
minWait?: number;
|
|
14
|
+
transitionDuration?: number;
|
|
15
|
+
onclick?: (image: ImageCyclerImage, index: number) => void;
|
|
16
|
+
title?: Snippet<[{
|
|
17
|
+
image: ImageCyclerImage;
|
|
18
|
+
index: number;
|
|
19
|
+
onclick: (() => void) | undefined;
|
|
20
|
+
}]>;
|
|
21
|
+
description?: Snippet<[{
|
|
22
|
+
image: ImageCyclerImage;
|
|
23
|
+
index: number;
|
|
24
|
+
onclick: (() => void) | undefined;
|
|
25
|
+
}]>;
|
|
26
|
+
unstyled?: boolean;
|
|
27
|
+
class?: string;
|
|
28
|
+
el?: HTMLElement;
|
|
29
|
+
}
|
|
30
|
+
declare const ImageCycler: import("svelte").Component<Props, {}, "el">;
|
|
31
|
+
type ImageCycler = ReturnType<typeof ImageCycler>;
|
|
32
|
+
export default ImageCycler;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--stuic-image-cycler-transition-duration: 500ms;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
@layer components {
|
|
6
|
+
.stuic-image-cycler {
|
|
7
|
+
position: relative;
|
|
8
|
+
width: 100%;
|
|
9
|
+
height: 100%;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.stuic-image-cycler-bg {
|
|
14
|
+
position: absolute;
|
|
15
|
+
inset: 0;
|
|
16
|
+
background-position: center;
|
|
17
|
+
background-repeat: no-repeat;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.stuic-image-cycler-bg[data-fit="cover"] { background-size: cover; }
|
|
21
|
+
.stuic-image-cycler-bg[data-fit="contain"] { background-size: contain; }
|
|
22
|
+
.stuic-image-cycler-bg[data-fit="fill"] { background-size: 100% 100%; }
|
|
23
|
+
|
|
24
|
+
.stuic-image-cycler-meta {
|
|
25
|
+
position: absolute;
|
|
26
|
+
inset: 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as ImageCycler, type Props as ImageCyclerProps, type ImageCyclerImage, type ImageCyclerFit, } from "./ImageCycler.svelte";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as ImageCycler, } from "./ImageCycler.svelte";
|
package/dist/index.css
CHANGED
|
@@ -41,6 +41,7 @@ In practice:
|
|
|
41
41
|
@import "./components/DismissibleMessage/index.css";
|
|
42
42
|
@import "./components/DropdownMenu/index.css";
|
|
43
43
|
@import "./components/H/index.css";
|
|
44
|
+
@import "./components/ImageCycler/index.css";
|
|
44
45
|
@import "./components/IconSwap/index.css";
|
|
45
46
|
@import "./components/Input/index.css";
|
|
46
47
|
@import "./components/KbdShortcut/index.css";
|
package/dist/index.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export * from "./components/DismissibleMessage/index.js";
|
|
|
42
42
|
export * from "./components/Drawer/index.js";
|
|
43
43
|
export * from "./components/DropdownMenu/index.js";
|
|
44
44
|
export * from "./components/H/index.js";
|
|
45
|
+
export * from "./components/ImageCycler/index.js";
|
|
45
46
|
export * from "./components/HoverExpandableWidth/index.js";
|
|
46
47
|
export * from "./components/IconSwap/index.js";
|
|
47
48
|
export * from "./components/Input/index.js";
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,7 @@ export * from "./components/DismissibleMessage/index.js";
|
|
|
43
43
|
export * from "./components/Drawer/index.js";
|
|
44
44
|
export * from "./components/DropdownMenu/index.js";
|
|
45
45
|
export * from "./components/H/index.js";
|
|
46
|
+
export * from "./components/ImageCycler/index.js";
|
|
46
47
|
export * from "./components/HoverExpandableWidth/index.js";
|
|
47
48
|
export * from "./components/IconSwap/index.js";
|
|
48
49
|
export * from "./components/Input/index.js";
|
package/docs/architecture.md
CHANGED
|
@@ -32,19 +32,19 @@ Layer 3: Internal Vars (--_bg, --_text, --_border)
|
|
|
32
32
|
|
|
33
33
|
```
|
|
34
34
|
src/lib/
|
|
35
|
-
├── components/ #
|
|
35
|
+
├── components/ # 46 UI components
|
|
36
36
|
│ └── {Name}/
|
|
37
37
|
│ ├── {Name}.svelte # Main component
|
|
38
38
|
│ ├── index.ts # Exports
|
|
39
39
|
│ ├── index.css # CSS tokens (if styled)
|
|
40
40
|
│ └── README.md # Documentation
|
|
41
41
|
│
|
|
42
|
-
├── actions/ #
|
|
42
|
+
├── actions/ # 15 Svelte actions
|
|
43
43
|
│ ├── *.svelte.ts # Reactive actions
|
|
44
44
|
│ ├── *.ts # Traditional actions
|
|
45
45
|
│ └── index.ts # Barrel export
|
|
46
46
|
│
|
|
47
|
-
├── utils/ #
|
|
47
|
+
├── utils/ # 43 utility modules
|
|
48
48
|
│ ├── *.svelte.ts # Reactive utilities
|
|
49
49
|
│ ├── *.ts # Pure functions
|
|
50
50
|
│ └── index.ts # Barrel export
|
package/docs/domains/actions.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
15 Svelte actions (directives) for reusable DOM behavior.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
| `popover` | Popover positioning | `popover/` |
|
|
25
25
|
| `spotlight` | Spotlight/coach mark overlay with cutout hole | `spotlight/` |
|
|
26
26
|
| `tooltip` | Tooltip positioning and display | `tooltip/` |
|
|
27
|
+
| `createTour` / `tourStep` | Multi-step onboarding tour (built on spotlight) | `onboarding/` |
|
|
27
28
|
|
|
28
29
|
---
|
|
29
30
|
|
|
@@ -115,6 +116,28 @@ Actions using `$effect()` accept a function returning options:
|
|
|
115
116
|
<button use:tooltip={{ content: "Save changes", position: "top" }}> Save </button>
|
|
116
117
|
```
|
|
117
118
|
|
|
119
|
+
### Onboarding Tour
|
|
120
|
+
|
|
121
|
+
```svelte
|
|
122
|
+
<script>
|
|
123
|
+
import { createTour, tourStep } from "@marianmeres/stuic";
|
|
124
|
+
|
|
125
|
+
const tour = createTour({
|
|
126
|
+
steps: [
|
|
127
|
+
{ id: "header", title: "Welcome", content: "This is the top." },
|
|
128
|
+
{ id: "save-btn", title: "Save", content: "Click here to save." },
|
|
129
|
+
],
|
|
130
|
+
onEnd: () => console.log("Tour complete!"),
|
|
131
|
+
});
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<header use:tourStep={[tour, "header"]}>...</header>
|
|
135
|
+
<button use:tourStep={[tour, "save-btn"]}>Save</button>
|
|
136
|
+
<button onclick={tour.start}>Start Tour</button>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Features: step navigation (next/prev/skip), persistent state via `storageKey`, custom shell snippets, `confirmSkip` callback, wait-for-element mechanism, Escape key support, step lifecycle callbacks (`onEnter`/`onLeave`).
|
|
140
|
+
|
|
118
141
|
---
|
|
119
142
|
|
|
120
143
|
## Action File Patterns
|
|
@@ -163,3 +186,4 @@ export function focusTrap(el: HTMLElement, options?: Options) {
|
|
|
163
186
|
| src/lib/actions/dim-behind/ | Simplified spotlight alternative |
|
|
164
187
|
| src/lib/actions/spotlight/ | Spotlight/coach mark action |
|
|
165
188
|
| src/lib/actions/tooltip/ | Multi-file action example |
|
|
189
|
+
| src/lib/actions/onboarding/ | Multi-step onboarding tour |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
46 Svelte 5 component directories with consistent API patterns. All use runes-based reactivity.
|
|
6
6
|
|
|
7
7
|
## Component Categories
|
|
8
8
|
|
|
@@ -39,18 +39,22 @@
|
|
|
39
39
|
|
|
40
40
|
| Component | Purpose |
|
|
41
41
|
| ------------------ | ------------------------------------- |
|
|
42
|
-
| Notifications
|
|
43
|
-
| AlertConfirmPrompt
|
|
44
|
-
| DismissibleMessage
|
|
45
|
-
| Progress
|
|
46
|
-
| Spinner
|
|
47
|
-
|
|
|
42
|
+
| Notifications | Toast notification system |
|
|
43
|
+
| AlertConfirmPrompt | Dialog factory (alert/confirm/prompt) |
|
|
44
|
+
| DismissibleMessage | Closeable message banner |
|
|
45
|
+
| Progress | Progress bar |
|
|
46
|
+
| Spinner | Loading indicator (default SVG spinner) |
|
|
47
|
+
| SpinnerCircle | CSS-only circular spinner with thickness/direction options |
|
|
48
|
+
| SpinnerCircleOscillate | Animated Circle-based spinner with oscillating completeness |
|
|
49
|
+
| SpinnerUnicode | Unicode character frame animation (17 variants) |
|
|
50
|
+
| Skeleton | Loading placeholder |
|
|
48
51
|
|
|
49
52
|
### Form
|
|
50
53
|
|
|
51
54
|
| Component | Purpose |
|
|
52
55
|
| ------------------------------------- | ------------------------------------------------- |
|
|
53
56
|
| Input (FieldInput, FieldSelect, etc.) | Form fields |
|
|
57
|
+
| FieldPhoneNumber | International phone input with country picker |
|
|
54
58
|
| FieldObject | Dual-mode JSON object editor (pretty-print/raw) |
|
|
55
59
|
| Fieldset | Field grouping with legend |
|
|
56
60
|
| FieldKeyValues | Key-value pair editor |
|
|
@@ -78,6 +82,7 @@
|
|
|
78
82
|
| Separator | Horizontal/vertical separator line |
|
|
79
83
|
| Thc | Flexible renderer for text, HTML, components, or snippets |
|
|
80
84
|
| X | Styled close/multiply SVG icon |
|
|
85
|
+
| ImageCycler | Auto-cycling image carousel with fade transitions and preloading |
|
|
81
86
|
|
|
82
87
|
### E-commerce
|
|
83
88
|
|