@marianmeres/stuic 3.115.0 → 3.116.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.
Files changed (86) hide show
  1. package/API.md +297 -304
  2. package/dist/actions/dim-behind/index.css +4 -1
  3. package/dist/actions/focus-trap.js +3 -1
  4. package/dist/components/Accordion/README.md +17 -17
  5. package/dist/components/Accordion/index.css +4 -2
  6. package/dist/components/AssetsPreview/README.md +7 -7
  7. package/dist/components/AssetsPreview/_internal/assets-preview-types.d.ts +1 -2
  8. package/dist/components/AssetsPreview/_internal/assets-preview-utils.d.ts +1 -1
  9. package/dist/components/AssetsPreview/_internal/assets-preview-utils.js +9 -3
  10. package/dist/components/Avatar/Avatar.svelte +1 -3
  11. package/dist/components/Avatar/README.md +33 -27
  12. package/dist/components/Book/Book.svelte +6 -1
  13. package/dist/components/Book/README.md +22 -20
  14. package/dist/components/Book/index.css +4 -2
  15. package/dist/components/Button/README.md +17 -17
  16. package/dist/components/Card/Card.svelte +25 -8
  17. package/dist/components/Card/README.md +52 -56
  18. package/dist/components/Card/index.css +2 -1
  19. package/dist/components/Carousel/Carousel.svelte +1 -3
  20. package/dist/components/Carousel/README.md +28 -28
  21. package/dist/components/Cart/Cart.svelte +2 -1
  22. package/dist/components/Cart/README.md +25 -25
  23. package/dist/components/Checkout/CheckoutGuestOrLoginForm.svelte +8 -3
  24. package/dist/components/Checkout/CheckoutShippingStep.svelte +1 -2
  25. package/dist/components/Checkout/README.md +143 -130
  26. package/dist/components/CronInput/CronInput.svelte +64 -60
  27. package/dist/components/CronInput/README.md +46 -46
  28. package/dist/components/DataTable/DataTable.svelte +5 -1
  29. package/dist/components/DataTable/README.md +78 -63
  30. package/dist/components/DropdownMenu/DropdownMenu.svelte +6 -2
  31. package/dist/components/DropdownMenu/README.md +33 -27
  32. package/dist/components/EmailVerifyForm/EmailVerifyForm.svelte +2 -9
  33. package/dist/components/EmailVerifyForm/README.md +30 -30
  34. package/dist/components/Header/Header.svelte +161 -165
  35. package/dist/components/Header/README.md +7 -7
  36. package/dist/components/IconSwap/README.md +20 -15
  37. package/dist/components/IconSwap/index.css +2 -1
  38. package/dist/components/ImageCycler/ImageCycler.svelte +19 -5
  39. package/dist/components/ImageCycler/ImageCycler.svelte.d.ts +14 -10
  40. package/dist/components/ImageCycler/README.md +15 -15
  41. package/dist/components/ImageCycler/index.css +26 -20
  42. package/dist/components/Input/FieldFile.svelte +1 -3
  43. package/dist/components/Input/FieldInput.svelte +1 -3
  44. package/dist/components/Input/FieldKeyValues.svelte +2 -6
  45. package/dist/components/Input/FieldObject.svelte +2 -1
  46. package/dist/components/Input/README.md +11 -11
  47. package/dist/components/KbdShortcut/index.css +2 -1
  48. package/dist/components/LoginForm/LoginForm.svelte +1 -7
  49. package/dist/components/LoginForm/README.md +46 -46
  50. package/dist/components/ModalDialog/index.css +2 -1
  51. package/dist/components/Notifications/index.css +24 -6
  52. package/dist/components/OtpInput/OtpInput.svelte +0 -0
  53. package/dist/components/OtpInput/README.md +15 -19
  54. package/dist/components/OtpInput/index.css +1 -4
  55. package/dist/components/OtpInput/index.d.ts +1 -1
  56. package/dist/components/OtpInput/index.js +1 -1
  57. package/dist/components/Pill/README.md +41 -40
  58. package/dist/components/Pill/index.css +3 -6
  59. package/dist/components/PricingTable/README.md +86 -86
  60. package/dist/components/PricingTable/index.css +20 -35
  61. package/dist/components/RegisterForm/README.md +60 -60
  62. package/dist/components/RegisterForm/RegisterForm.svelte +1 -7
  63. package/dist/components/Separator/README.md +7 -7
  64. package/dist/components/TabbedMenu/index.css +6 -3
  65. package/dist/components/Tree/README.md +67 -67
  66. package/dist/components/UserAvatarMenu/UserAvatarMenu.svelte +1 -5
  67. package/dist/components/WithSidePanel/index.css +4 -4
  68. package/dist/index.css +12 -8
  69. package/dist/utils/design-tokens.d.ts +1 -1
  70. package/dist/utils/design-tokens.js +1 -1
  71. package/docs/architecture.md +7 -7
  72. package/docs/component-testing/00-overview-and-roadmap.md +19 -19
  73. package/docs/component-testing/01-framework-setup.md +6 -6
  74. package/docs/component-testing/02-test-conventions.md +6 -5
  75. package/docs/component-testing/03-component-coverage-roadmap.md +27 -27
  76. package/docs/component-testing/04-hard-cases-and-e2e.md +8 -8
  77. package/docs/component-testing/05-ci.md +3 -3
  78. package/docs/component-testing/PROGRESS.md +30 -26
  79. package/docs/component-testing/README.md +8 -8
  80. package/docs/conventions.md +25 -25
  81. package/docs/domains/components.md +386 -385
  82. package/docs/domains/theming.md +24 -24
  83. package/docs/domains/utils.md +22 -25
  84. package/docs/testing.md +2 -2
  85. package/docs/upgrading.md +32 -28
  86. package/package.json +2 -1
@@ -17,8 +17,12 @@
17
17
  minWait?: number;
18
18
  transitionDuration?: number;
19
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 }]>;
20
+ title?: Snippet<
21
+ [{ image: ImageCyclerImage; index: number; onclick: (() => void) | undefined }]
22
+ >;
23
+ description?: Snippet<
24
+ [{ image: ImageCyclerImage; index: number; onclick: (() => void) | undefined }]
25
+ >;
22
26
  unstyled?: boolean;
23
27
  class?: string;
24
28
  el?: HTMLElement;
@@ -47,7 +51,9 @@
47
51
 
48
52
  let _class = $derived(unstyled ? classProp : twMerge("stuic-image-cycler", classProp));
49
53
 
50
- let _onclick = $derived(onclick ? () => onclick(images[currentIndex], currentIndex) : undefined);
54
+ let _onclick = $derived(
55
+ onclick ? () => onclick(images[currentIndex], currentIndex) : undefined
56
+ );
51
57
 
52
58
  $effect(() => {
53
59
  const idx = currentIndex;
@@ -87,10 +93,18 @@
87
93
  out:fade={{ duration: transitionDuration }}
88
94
  >
89
95
  {#if title}
90
- {@render title({ image: images[currentIndex], index: currentIndex, onclick: _onclick })}
96
+ {@render title({
97
+ image: images[currentIndex],
98
+ index: currentIndex,
99
+ onclick: _onclick,
100
+ })}
91
101
  {/if}
92
102
  {#if description}
93
- {@render description({ image: images[currentIndex], index: currentIndex, onclick: _onclick })}
103
+ {@render description({
104
+ image: images[currentIndex],
105
+ index: currentIndex,
106
+ onclick: _onclick,
107
+ })}
94
108
  {/if}
95
109
  </div>
96
110
  {/key}
@@ -13,16 +13,20 @@ export interface Props {
13
13
  minWait?: number;
14
14
  transitionDuration?: number;
15
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
- }]>;
16
+ title?: Snippet<[
17
+ {
18
+ image: ImageCyclerImage;
19
+ index: number;
20
+ onclick: (() => void) | undefined;
21
+ }
22
+ ]>;
23
+ description?: Snippet<[
24
+ {
25
+ image: ImageCyclerImage;
26
+ index: number;
27
+ onclick: (() => void) | undefined;
28
+ }
29
+ ]>;
26
30
  unstyled?: boolean;
27
31
  class?: string;
28
32
  el?: HTMLElement;
@@ -4,18 +4,18 @@ Auto-cycling background-image carousel with fade transitions. Preloads the next
4
4
 
5
5
  ## Props
6
6
 
7
- | Prop | Type | Default | Description |
8
- | -------------------- | ----------------------------------------------------------------- | --------- | ---------------------------------------------------------------------- |
9
- | `images` | `ImageCyclerImage[]` | required | Images to cycle through. |
10
- | `fit` | `"cover" \| "contain" \| "fill"` | `"cover"` | Background-size mode. Set via `data-fit` on the image layer. |
11
- | `minWait` | `number` | `3000` | Minimum wait (ms) on each image before advancing. |
12
- | `transitionDuration` | `number` | `500` | Fade duration in ms (for both the image and the meta layer). |
13
- | `onclick` | `(image, index) => void` | - | Click handler. The snippets receive a forwarded version. |
14
- | `title` | `Snippet<[{ image, index, onclick }]>` | - | Title overlay snippet. |
15
- | `description` | `Snippet<[{ image, index, onclick }]>` | - | Description overlay snippet. |
16
- | `unstyled` | `boolean` | `false` | Skip default styling. |
17
- | `class` | `string` | - | Additional CSS classes. |
18
- | `el` | `HTMLElement` | - | Bindable root element. |
7
+ | Prop | Type | Default | Description |
8
+ | -------------------- | -------------------------------------- | --------- | ------------------------------------------------------------ |
9
+ | `images` | `ImageCyclerImage[]` | required | Images to cycle through. |
10
+ | `fit` | `"cover" \| "contain" \| "fill"` | `"cover"` | Background-size mode. Set via `data-fit` on the image layer. |
11
+ | `minWait` | `number` | `3000` | Minimum wait (ms) on each image before advancing. |
12
+ | `transitionDuration` | `number` | `500` | Fade duration in ms (for both the image and the meta layer). |
13
+ | `onclick` | `(image, index) => void` | - | Click handler. The snippets receive a forwarded version. |
14
+ | `title` | `Snippet<[{ image, index, onclick }]>` | - | Title overlay snippet. |
15
+ | `description` | `Snippet<[{ image, index, onclick }]>` | - | Description overlay snippet. |
16
+ | `unstyled` | `boolean` | `false` | Skip default styling. |
17
+ | `class` | `string` | - | Additional CSS classes. |
18
+ | `el` | `HTMLElement` | - | Bindable root element. |
19
19
 
20
20
  ## `ImageCyclerImage`
21
21
 
@@ -71,9 +71,9 @@ interface ImageCyclerImage {
71
71
 
72
72
  ## CSS Variables
73
73
 
74
- | Variable | Default | Description |
75
- | ------------------------------------------- | ------- | --------------------- |
76
- | `--stuic-image-cycler-transition-duration` | `500ms` | (informational; the active transition duration comes from the `transitionDuration` prop) |
74
+ | Variable | Default | Description |
75
+ | ------------------------------------------ | ------- | ---------------------------------------------------------------------------------------- |
76
+ | `--stuic-image-cycler-transition-duration` | `500ms` | (informational; the active transition duration comes from the `transitionDuration` prop) |
77
77
 
78
78
  ## Notes
79
79
 
@@ -1,28 +1,34 @@
1
1
  :root {
2
- --stuic-image-cycler-transition-duration: 500ms;
2
+ --stuic-image-cycler-transition-duration: 500ms;
3
3
  }
4
4
 
5
5
  @layer components {
6
- .stuic-image-cycler {
7
- position: relative;
8
- width: 100%;
9
- height: 100%;
10
- overflow: hidden;
11
- }
6
+ .stuic-image-cycler {
7
+ position: relative;
8
+ width: 100%;
9
+ height: 100%;
10
+ overflow: hidden;
11
+ }
12
12
 
13
- .stuic-image-cycler-bg {
14
- position: absolute;
15
- inset: 0;
16
- background-position: center;
17
- background-repeat: no-repeat;
18
- }
13
+ .stuic-image-cycler-bg {
14
+ position: absolute;
15
+ inset: 0;
16
+ background-position: center;
17
+ background-repeat: no-repeat;
18
+ }
19
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%; }
20
+ .stuic-image-cycler-bg[data-fit="cover"] {
21
+ background-size: cover;
22
+ }
23
+ .stuic-image-cycler-bg[data-fit="contain"] {
24
+ background-size: contain;
25
+ }
26
+ .stuic-image-cycler-bg[data-fit="fill"] {
27
+ background-size: 100% 100%;
28
+ }
23
29
 
24
- .stuic-image-cycler-meta {
25
- position: absolute;
26
- inset: 0;
27
- }
30
+ .stuic-image-cycler-meta {
31
+ position: absolute;
32
+ inset: 0;
33
+ }
28
34
  }
@@ -8,9 +8,7 @@
8
8
  type SnippetWithId = Snippet<[{ id: string }]>;
9
9
 
10
10
  export interface Props
11
- extends HTMLInputAttributes,
12
- InputWrapClassProps,
13
- Record<string, any> {
11
+ extends HTMLInputAttributes, InputWrapClassProps, Record<string, any> {
14
12
  input?: HTMLInputElement;
15
13
  files?: FileList;
16
14
  multiple?: boolean;
@@ -9,9 +9,7 @@
9
9
  type SnippetWithId = Snippet<[{ id: string }]>;
10
10
 
11
11
  export interface Props
12
- extends HTMLInputAttributes,
13
- InputWrapClassProps,
14
- Record<string, any> {
12
+ extends HTMLInputAttributes, InputWrapClassProps, Record<string, any> {
15
13
  input?: HTMLInputElement;
16
14
  value?: string | number;
17
15
  label?: SnippetWithId | THC;
@@ -445,13 +445,9 @@
445
445
  <span
446
446
  class={twMerge(
447
447
  "pointer-events-none absolute top-1.5 right-1.5",
448
- st === "valid"
449
- ? "opacity-40"
450
- : "text-amber-500 opacity-80"
448
+ st === "valid" ? "opacity-40" : "text-amber-500 opacity-80"
451
449
  )}
452
- title={st === "valid"
453
- ? t("json_detected")
454
- : t("invalid_json_syntax")}
450
+ title={st === "valid" ? t("json_detected") : t("invalid_json_syntax")}
455
451
  aria-hidden="true"
456
452
  >
457
453
  {@html st === "valid"
@@ -354,7 +354,8 @@
354
354
  {value}
355
355
  bind:this={hiddenInputEl}
356
356
  use:validateAction={() => {
357
- const customOpts = typeof validateProp === "object" && validateProp ? validateProp : {};
357
+ const customOpts =
358
+ typeof validateProp === "object" && validateProp ? validateProp : {};
358
359
  const userValidator = customOpts.customValidator;
359
360
  return {
360
361
  enabled: validateProp !== false,
@@ -52,17 +52,17 @@ A comprehensive form input system with multiple field components, validation sup
52
52
 
53
53
  Every `Field*` component that uses the shared label/input/description scaffolding accepts **the same 9 class props**, exported as the `InputWrapClassProps` interface from `@marianmeres/stuic`. Each Field extends that interface in its own `Props`, so the shape stays in sync and new wrapper targets are added in one place.
54
54
 
55
- | Prop | Target |
56
- | --------------------------- | ------------------------------------------------------------------ |
57
- | `classLabel` | `<label>` element |
58
- | `classLabelBox` | Wrapper around the label area |
59
- | `classInputBox` | Wrapper around the whole input area |
60
- | `classInputBoxWrap` | Inner input wrap (sibling to description/validation/below) |
61
- | `classInputBoxWrapInvalid` | Added to `classInputBoxWrap` when validation fails |
62
- | `classDescBox` | Description/help text box |
63
- | `classDescBoxToggle` | Collapsible description's toggle button |
64
- | `classBelowBox` | "Below" slot (rendered under the description) |
65
- | `classValidationBox` | Validation message box |
55
+ | Prop | Target |
56
+ | -------------------------- | ---------------------------------------------------------- |
57
+ | `classLabel` | `<label>` element |
58
+ | `classLabelBox` | Wrapper around the label area |
59
+ | `classInputBox` | Wrapper around the whole input area |
60
+ | `classInputBoxWrap` | Inner input wrap (sibling to description/validation/below) |
61
+ | `classInputBoxWrapInvalid` | Added to `classInputBoxWrap` when validation fails |
62
+ | `classDescBox` | Description/help text box |
63
+ | `classDescBoxToggle` | Collapsible description's toggle button |
64
+ | `classBelowBox` | "Below" slot (rendered under the description) |
65
+ | `classValidationBox` | Validation message box |
66
66
 
67
67
  Component-specific targets (e.g. `classInput` for the inner `<input>`/`<select>`/`<textarea>`, `classFileList` on `FieldFile`, `classOption`/`classOptgroup` on `FieldOptions`, `classPrefixTrigger` on `FieldPhoneNumber`, etc.) live on the component itself alongside these shared props.
68
68
 
@@ -37,7 +37,8 @@
37
37
  /* Box model */
38
38
  padding: var(--stuic-kbd-padding-y) var(--stuic-kbd-padding-x);
39
39
  border-radius: var(--stuic-kbd-radius, var(--stuic-radius));
40
- border: var(--stuic-kbd-border-width, var(--stuic-border-width)) solid var(--stuic-kbd-border-color);
40
+ border: var(--stuic-kbd-border-width, var(--stuic-border-width)) solid
41
+ var(--stuic-kbd-border-color);
41
42
  }
42
43
 
43
44
  /* Symbol styling (⌘, ⇧, ⌥, ⌃, ⊞) */
@@ -247,13 +247,7 @@
247
247
  }
248
248
  </script>
249
249
 
250
- <form
251
- bind:this={formEl}
252
- class={_class}
253
- use:onSubmitValidityCheck
254
- novalidate
255
- {...rest}
256
- >
250
+ <form bind:this={formEl} class={_class} use:onSubmitValidityCheck novalidate {...rest}>
257
251
  <!-- General error alert -->
258
252
  <DismissibleMessage message={error} intent="destructive" />
259
253
 
@@ -6,47 +6,47 @@ Standalone login form with email/password fields, optional social/OAuth buttons,
6
6
 
7
7
  ## Exports
8
8
 
9
- | Export | Kind | Description |
10
- | -------------------------- | --------- | ------------------------------------------------- |
11
- | `LoginForm` | component | Form component |
12
- | `LoginFormModal` | component | Modal-wrapped form with optional trigger snippet |
13
- | `LoginFormProps` | type | Props for `LoginForm` |
14
- | `LoginFormModalProps` | type | Props for `LoginFormModal` |
15
- | `LoginFormData` | type | `{ email, password, rememberMe }` |
16
- | `LoginFormValidationError` | type | `{ field, message }` |
17
- | `createEmptyLoginFormData` | function | Factory for an empty `LoginFormData` |
18
- | `validateLoginForm` | function | `(data, t) => LoginFormValidationError[]` |
9
+ | Export | Kind | Description |
10
+ | -------------------------- | --------- | ------------------------------------------------ |
11
+ | `LoginForm` | component | Form component |
12
+ | `LoginFormModal` | component | Modal-wrapped form with optional trigger snippet |
13
+ | `LoginFormProps` | type | Props for `LoginForm` |
14
+ | `LoginFormModalProps` | type | Props for `LoginFormModal` |
15
+ | `LoginFormData` | type | `{ email, password, rememberMe }` |
16
+ | `LoginFormValidationError` | type | `{ field, message }` |
17
+ | `createEmptyLoginFormData` | function | Factory for an empty `LoginFormData` |
18
+ | `validateLoginForm` | function | `(data, t) => LoginFormValidationError[]` |
19
19
 
20
20
  ## LoginForm — Props
21
21
 
22
- | Prop | Type | Default | Description |
23
- | --------------------- | ------------------------------------------------- | -------- | ------------------------------------------------------------------------------------ |
24
- | `formData` | `LoginFormData` | empty | Bindable form data. |
25
- | `onSubmit` | `(data: LoginFormData) => void` | required | Called when client-side validation passes. |
26
- | `isSubmitting` | `boolean` | `false` | Disables the CTA during submission. |
27
- | `errors` | `LoginFormValidationError[]` | `[]` | Field-specific server errors (merged with internal validation). |
28
- | `error` | `string` | - | General error rendered as a `DismissibleMessage` above the form. |
29
- | `onForgotPassword` | `() => void` | - | Click handler for the "Forgot password?" link. Link is hidden when undefined. |
30
- | `showRememberMe` | `boolean` | `true` | Render the remember-me checkbox. |
31
- | `submitLabel` | `string` | i18n | Override the CTA label. |
32
- | `submittingLabel` | `string` | i18n | Override the CTA label while submitting. |
33
- | `submitButton` | `Snippet<[{ isSubmitting, disabled }]>` | - | Override the entire CTA section. |
34
- | `socialLogins` | `Snippet` | - | Social/OAuth buttons rendered below the form. A divider is shown above when set. |
35
- | `socialDividerLabel` | `string \| false` | i18n | Override (or hide with `false`) the divider above social buttons. |
36
- | `footer` | `Snippet` | - | Content below the form (e.g., sign-up links). |
37
- | `notifications` | `NotificationsStack` | - | When set, general errors are also pushed via `notifications.error()`. |
38
- | `t` | `TranslateFn` | English | i18n function. |
39
- | `unstyled` / `class` | - | - | Standard styling escape hatches. |
40
- | `el` | `HTMLFormElement` | - | Bindable form element. |
22
+ | Prop | Type | Default | Description |
23
+ | -------------------- | --------------------------------------- | -------- | -------------------------------------------------------------------------------- |
24
+ | `formData` | `LoginFormData` | empty | Bindable form data. |
25
+ | `onSubmit` | `(data: LoginFormData) => void` | required | Called when client-side validation passes. |
26
+ | `isSubmitting` | `boolean` | `false` | Disables the CTA during submission. |
27
+ | `errors` | `LoginFormValidationError[]` | `[]` | Field-specific server errors (merged with internal validation). |
28
+ | `error` | `string` | - | General error rendered as a `DismissibleMessage` above the form. |
29
+ | `onForgotPassword` | `() => void` | - | Click handler for the "Forgot password?" link. Link is hidden when undefined. |
30
+ | `showRememberMe` | `boolean` | `true` | Render the remember-me checkbox. |
31
+ | `submitLabel` | `string` | i18n | Override the CTA label. |
32
+ | `submittingLabel` | `string` | i18n | Override the CTA label while submitting. |
33
+ | `submitButton` | `Snippet<[{ isSubmitting, disabled }]>` | - | Override the entire CTA section. |
34
+ | `socialLogins` | `Snippet` | - | Social/OAuth buttons rendered below the form. A divider is shown above when set. |
35
+ | `socialDividerLabel` | `string \| false` | i18n | Override (or hide with `false`) the divider above social buttons. |
36
+ | `footer` | `Snippet` | - | Content below the form (e.g., sign-up links). |
37
+ | `notifications` | `NotificationsStack` | - | When set, general errors are also pushed via `notifications.error()`. |
38
+ | `t` | `TranslateFn` | English | i18n function. |
39
+ | `unstyled` / `class` | - | - | Standard styling escape hatches. |
40
+ | `el` | `HTMLFormElement` | - | Bindable form element. |
41
41
 
42
42
  ### Imperative methods
43
43
 
44
44
  `bind:this` exposes:
45
45
 
46
- | Method | Returns | Purpose |
47
- | ------------------------------------- | --------- | ------------------------------------------------------------------------ |
48
- | `validate()` | `boolean` | Forces every inner field's validator to run. `true` if all valid. |
49
- | `scrollToFirstError(opts?)` | `boolean` | Scrolls + focuses the first invalid field. Call after `validate()`. |
46
+ | Method | Returns | Purpose |
47
+ | --------------------------- | --------- | ------------------------------------------------------------------- |
48
+ | `validate()` | `boolean` | Forces every inner field's validator to run. `true` if all valid. |
49
+ | `scrollToFirstError(opts?)` | `boolean` | Scrolls + focuses the first invalid field. Call after `validate()`. |
50
50
 
51
51
  These are essential for pristine-form errors (server errors set via the `errors` prop won't render until the user touches each field). See [`docs/domains/components.md#imperative-validate-api`](../../../docs/domains/components.md#imperative-validate-api) for the full pattern.
52
52
 
@@ -54,17 +54,17 @@ These are essential for pristine-form errors (server errors set via the `errors`
54
54
 
55
55
  Inherits all `LoginForm` props, plus:
56
56
 
57
- | Prop | Type | Default | Description |
58
- | --------------------- | ----------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------- |
59
- | `title` | `string` | `"Log In"` (i18n) | Modal title. |
60
- | `visible` | `boolean` | `false` | Bindable modal visibility. |
61
- | `trigger` | `Snippet<[{ open }]>` | - | Optional trigger element rendered outside the modal. |
62
- | `classModal` | `string` | - | Class for the Modal box. |
63
- | `classInner` | `string` | - | Class for the Modal inner width container. |
64
- | `classForm` | `string` | - | Class forwarded to the inner `LoginForm`. |
65
- | `noXClose` | `boolean` | `false` | Hide the close (X) button. |
66
- | `onClose` | `() => false \| void` | - | Pre-close hook. Return `false` to prevent close. |
67
- | `noClickOutsideClose` | `boolean` | `true` | Disable backdrop-click close (default-on to protect typed credentials). |
57
+ | Prop | Type | Default | Description |
58
+ | --------------------- | --------------------- | ----------------- | ----------------------------------------------------------------------- |
59
+ | `title` | `string` | `"Log In"` (i18n) | Modal title. |
60
+ | `visible` | `boolean` | `false` | Bindable modal visibility. |
61
+ | `trigger` | `Snippet<[{ open }]>` | - | Optional trigger element rendered outside the modal. |
62
+ | `classModal` | `string` | - | Class for the Modal box. |
63
+ | `classInner` | `string` | - | Class for the Modal inner width container. |
64
+ | `classForm` | `string` | - | Class forwarded to the inner `LoginForm`. |
65
+ | `noXClose` | `boolean` | `false` | Hide the close (X) button. |
66
+ | `onClose` | `() => false \| void` | - | Pre-close hook. Return `false` to prevent close. |
67
+ | `noClickOutsideClose` | `boolean` | `true` | Disable backdrop-click close (default-on to protect typed credentials). |
68
68
 
69
69
  **Methods:** `open(openerOrEvent?)`, `close()` — exposed via `bind:this`.
70
70
 
@@ -137,8 +137,8 @@ Prefix: `--stuic-login-form-*`
137
137
  | `--stuic-login-form-gap-row` | Gap inside multi-column rows |
138
138
  | `--stuic-login-form-forgot-margin-y` | Forgot-password link vertical margin |
139
139
  | `--stuic-login-form-forgot-margin-x` | Forgot-password link horizontal margin |
140
- | `--stuic-login-form-social-margin-top` | Margin above social buttons block |
141
- | `--stuic-login-form-social-gap` | Gap between social buttons |
140
+ | `--stuic-login-form-social-margin-top` | Margin above social buttons block |
141
+ | `--stuic-login-form-social-gap` | Gap between social buttons |
142
142
  | `--stuic-login-form-social-divider-color` | Divider text color |
143
143
  | `--stuic-login-form-social-divider-font-size` | Divider text size |
144
144
  | `--stuic-login-form-social-divider-margin-bottom` | Divider bottom margin |
@@ -42,7 +42,8 @@
42
42
  ============================================================================ */
43
43
 
44
44
  .stuic-modal-dialog[open]::backdrop {
45
- animation: stuic-modal-dialog-fadeIn var(--stuic-modal-dialog-transition, var(--stuic-transition)) ease-out;
45
+ animation: stuic-modal-dialog-fadeIn
46
+ var(--stuic-modal-dialog-transition, var(--stuic-transition)) ease-out;
46
47
  }
47
48
 
48
49
  @keyframes stuic-modal-dialog-fadeIn {
@@ -152,8 +152,14 @@
152
152
  align-items: center;
153
153
  justify-content: center;
154
154
  padding: 0 calc(var(--spacing) * 3);
155
- border-top-right-radius: var(--stuic-notification-radius, var(--stuic-radius-container));
156
- border-bottom-right-radius: var(--stuic-notification-radius, var(--stuic-radius-container));
155
+ border-top-right-radius: var(
156
+ --stuic-notification-radius,
157
+ var(--stuic-radius-container)
158
+ );
159
+ border-bottom-right-radius: var(
160
+ --stuic-notification-radius,
161
+ var(--stuic-radius-container)
162
+ );
157
163
  color: var(--_text);
158
164
  opacity: 0.75;
159
165
  transition: opacity var(--stuic-notification-transition, var(--stuic-transition));
@@ -198,8 +204,14 @@
198
204
  position: absolute;
199
205
  inset: 0;
200
206
  background: transparent;
201
- border-bottom-left-radius: var(--stuic-notification-radius, var(--stuic-radius-container));
202
- border-bottom-right-radius: var(--stuic-notification-radius, var(--stuic-radius-container));
207
+ border-bottom-left-radius: var(
208
+ --stuic-notification-radius,
209
+ var(--stuic-radius-container)
210
+ );
211
+ border-bottom-right-radius: var(
212
+ --stuic-notification-radius,
213
+ var(--stuic-radius-container)
214
+ );
203
215
  overflow: hidden;
204
216
  pointer-events: none;
205
217
  }
@@ -208,7 +220,13 @@
208
220
  width: 100%;
209
221
  height: 100%;
210
222
  /* background: rgb(255 255 255 / 0.5); */
211
- border-bottom-left-radius: var(--stuic-notification-radius, var(--stuic-radius-container));
212
- border-bottom-right-radius: var(--stuic-notification-radius, var(--stuic-radius-container));
223
+ border-bottom-left-radius: var(
224
+ --stuic-notification-radius,
225
+ var(--stuic-radius-container)
226
+ );
227
+ border-bottom-right-radius: var(
228
+ --stuic-notification-radius,
229
+ var(--stuic-radius-container)
230
+ );
213
231
  }
214
232
  }
@@ -11,29 +11,25 @@ Generic N-slot one-time-code input. 6 digits by default, configurable. Building
11
11
  let code = $state("");
12
12
  </script>
13
13
 
14
- <OtpInput
15
- bind:value={code}
16
- length={6}
17
- onComplete={(c) => console.log("Got code:", c)}
18
- />
14
+ <OtpInput bind:value={code} length={6} onComplete={(c) => console.log("Got code:", c)} />
19
15
  ```
20
16
 
21
17
  ## Props
22
18
 
23
- | Prop | Type | Default | Description |
24
- | -------------- | ------------------------------- | ------------------ | ----------------------------------------------------------------- |
25
- | `value` | `string` | `""` | Bindable concatenated value |
26
- | `length` | `number` | `6` | Number of slots |
27
- | `onComplete` | `(code: string) => void` | — | Fired when all slots are filled |
28
- | `oninput` | `(value: string) => void` | — | Fired on every change |
29
- | `error` | `boolean` | `false` | Renders error styling + `aria-invalid` |
30
- | `disabled` | `boolean` | `false` | Disables all slots |
31
- | `autoFocus` | `boolean` | `true` | Auto-focus the first empty slot on mount |
32
- | `mode` | `"numeric" \| "alphanumeric"` | `"numeric"` | Restrict input characters |
33
- | `autocomplete` | `string` | `"one-time-code"` | Pass-through to first slot for browser/iOS auto-fill |
34
- | `unstyled` | `boolean` | `false` | Skip default styling |
35
- | `class` | `string` | — | Additional CSS classes on the root |
36
- | `el` | `HTMLDivElement` | — | Bindable root element ref |
19
+ | Prop | Type | Default | Description |
20
+ | -------------- | ----------------------------- | ----------------- | ---------------------------------------------------- |
21
+ | `value` | `string` | `""` | Bindable concatenated value |
22
+ | `length` | `number` | `6` | Number of slots |
23
+ | `onComplete` | `(code: string) => void` | — | Fired when all slots are filled |
24
+ | `oninput` | `(value: string) => void` | — | Fired on every change |
25
+ | `error` | `boolean` | `false` | Renders error styling + `aria-invalid` |
26
+ | `disabled` | `boolean` | `false` | Disables all slots |
27
+ | `autoFocus` | `boolean` | `true` | Auto-focus the first empty slot on mount |
28
+ | `mode` | `"numeric" \| "alphanumeric"` | `"numeric"` | Restrict input characters |
29
+ | `autocomplete` | `string` | `"one-time-code"` | Pass-through to first slot for browser/iOS auto-fill |
30
+ | `unstyled` | `boolean` | `false` | Skip default styling |
31
+ | `class` | `string` | — | Additional CSS classes on the root |
32
+ | `el` | `HTMLDivElement` | — | Bindable root element ref |
37
33
 
38
34
  ## Behavior
39
35
 
@@ -20,10 +20,7 @@
20
20
  }
21
21
 
22
22
  .stuic-otp-input-slot:focus {
23
- border-color: var(
24
- --stuic-otp-input-border-color-focus,
25
- var(--stuic-color-primary)
26
- );
23
+ border-color: var(--stuic-otp-input-border-color-focus, var(--stuic-color-primary));
27
24
  outline: none;
28
25
  }
29
26
 
@@ -1 +1 @@
1
- export { default as OtpInput, type Props as OtpInputProps, } from "./OtpInput.svelte";
1
+ export { default as OtpInput, type Props as OtpInputProps } from "./OtpInput.svelte";
@@ -1 +1 @@
1
- export { default as OtpInput, } from "./OtpInput.svelte";
1
+ export { default as OtpInput } from "./OtpInput.svelte";