@marianmeres/stuic 3.70.0 → 3.71.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/AGENTS.md +2 -2
- package/README.md +1 -1
- package/dist/components/EmailVerifyForm/EmailVerifyForm.svelte +269 -0
- package/dist/components/EmailVerifyForm/EmailVerifyForm.svelte.d.ts +47 -0
- package/dist/components/EmailVerifyForm/README.md +76 -0
- package/dist/components/EmailVerifyForm/_internal/email-verify-form-i18n-defaults.d.ts +1 -0
- package/dist/components/EmailVerifyForm/_internal/email-verify-form-i18n-defaults.js +21 -0
- package/dist/components/EmailVerifyForm/index.css +54 -0
- package/dist/components/EmailVerifyForm/index.d.ts +1 -0
- package/dist/components/EmailVerifyForm/index.js +1 -0
- package/dist/components/LoginOrRegisterForm/LoginOrRegisterForm.svelte +70 -21
- package/dist/components/LoginOrRegisterForm/LoginOrRegisterForm.svelte.d.ts +16 -2
- package/dist/components/LoginOrRegisterForm/LoginOrRegisterFormModal.svelte +26 -3
- package/dist/components/LoginOrRegisterForm/LoginOrRegisterFormModal.svelte.d.ts +9 -1
- package/dist/components/LoginOrRegisterForm/_internal/login-or-register-form-i18n-defaults.js +2 -0
- package/dist/components/OtpInput/OtpInput.svelte +0 -0
- package/dist/components/OtpInput/OtpInput.svelte.d.ts +30 -0
- package/dist/components/OtpInput/README.md +55 -0
- package/dist/components/OtpInput/index.css +41 -0
- package/dist/components/OtpInput/index.d.ts +1 -0
- package/dist/components/OtpInput/index.js +1 -0
- package/dist/components/TabbedMenu/TabbedMenu.svelte +27 -3
- package/dist/components/TabbedMenu/TabbedMenu.svelte.d.ts +4 -1
- package/dist/index.css +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/docs/domains/components.md +204 -1
- package/package.json +1 -1
|
@@ -5,8 +5,9 @@ import type { Props as LoginFormProps } from "../LoginForm/LoginForm.svelte";
|
|
|
5
5
|
import type { LoginFormData } from "../LoginForm/_internal/login-form-types.js";
|
|
6
6
|
import type { Props as RegisterFormProps } from "../RegisterForm/RegisterForm.svelte";
|
|
7
7
|
import type { RegisterFormData } from "../RegisterForm/_internal/register-form-types.js";
|
|
8
|
+
import type { Props as EmailVerifyFormProps } from "../EmailVerifyForm/EmailVerifyForm.svelte";
|
|
8
9
|
import type { NotificationsStack } from "../Notifications/notifications-stack.svelte.js";
|
|
9
|
-
export type LoginOrRegisterFormMode = "login" | "register";
|
|
10
|
+
export type LoginOrRegisterFormMode = "login" | "register" | "verify";
|
|
10
11
|
type InnerPropsCommonOmit = "formData" | "onSubmit" | "isSubmitting" | "t" | "notifications" | "socialLogins" | "socialDividerLabel" | "footer";
|
|
11
12
|
export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
12
13
|
/** Bindable active mode. Default: "login" */
|
|
@@ -25,6 +26,19 @@ export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children">
|
|
|
25
26
|
loginProps?: Omit<LoginFormProps, InnerPropsCommonOmit>;
|
|
26
27
|
/** Pass-through props for the inner RegisterForm (spread). */
|
|
27
28
|
registerProps?: Omit<RegisterFormProps, InnerPropsCommonOmit>;
|
|
29
|
+
/**
|
|
30
|
+
* Bindable email used by EmailVerifyForm (typically copied from registerData.email
|
|
31
|
+
* when transitioning to "verify" mode).
|
|
32
|
+
*/
|
|
33
|
+
verifyEmail?: string;
|
|
34
|
+
/** Called when the user submits a code in the verify view. */
|
|
35
|
+
onVerify?: (code: string) => void;
|
|
36
|
+
/** Called when the user clicks "Resend code" in the verify view. */
|
|
37
|
+
onResendCode?: () => Promise<void> | void;
|
|
38
|
+
/** Pass-through props for the inner EmailVerifyForm (spread). */
|
|
39
|
+
verifyProps?: Omit<EmailVerifyFormProps, "email" | "onSubmit" | "onResend" | "isSubmitting" | "t" | "notifications" | "footer">;
|
|
40
|
+
/** Reserved for future use (verify mode is not exposed in the default switcher). */
|
|
41
|
+
verifyModeLabel?: string;
|
|
28
42
|
/** Override the built-in ButtonGroupRadio mode switcher. */
|
|
29
43
|
modeSwitcher?: Snippet<[
|
|
30
44
|
{
|
|
@@ -63,6 +77,6 @@ export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children">
|
|
|
63
77
|
unstyled?: boolean;
|
|
64
78
|
class?: string;
|
|
65
79
|
}
|
|
66
|
-
declare const LoginOrRegisterForm: import("svelte").Component<Props, {}, "mode" | "loginData" | "registerData">;
|
|
80
|
+
declare const LoginOrRegisterForm: import("svelte").Component<Props, {}, "mode" | "loginData" | "registerData" | "verifyEmail">;
|
|
67
81
|
type LoginOrRegisterForm = ReturnType<typeof LoginOrRegisterForm>;
|
|
68
82
|
export default LoginOrRegisterForm;
|
|
@@ -19,18 +19,29 @@
|
|
|
19
19
|
/** Bindable register formData */
|
|
20
20
|
registerData?: RegisterFormData;
|
|
21
21
|
|
|
22
|
+
/** Bindable email used by EmailVerifyForm. */
|
|
23
|
+
verifyEmail?: string;
|
|
24
|
+
|
|
22
25
|
onLogin: (data: LoginFormData) => void;
|
|
23
26
|
onRegister: (data: RegisterFormData) => void;
|
|
24
27
|
|
|
28
|
+
/** Called when the user submits a code in the verify view. */
|
|
29
|
+
onVerify?: (code: string) => void;
|
|
30
|
+
|
|
31
|
+
/** Called when the user clicks "Resend code" in the verify view. */
|
|
32
|
+
onResendCode?: () => Promise<void> | void;
|
|
33
|
+
|
|
25
34
|
isSubmitting?: boolean;
|
|
26
35
|
|
|
27
36
|
loginProps?: InnerProps["loginProps"];
|
|
28
37
|
registerProps?: InnerProps["registerProps"];
|
|
38
|
+
verifyProps?: InnerProps["verifyProps"];
|
|
29
39
|
|
|
30
40
|
modeSwitcher?: InnerProps["modeSwitcher"];
|
|
31
41
|
|
|
32
42
|
loginModeLabel?: string;
|
|
33
43
|
registerModeLabel?: string;
|
|
44
|
+
verifyModeLabel?: string;
|
|
34
45
|
|
|
35
46
|
/** Shared social logins (rendered below the active form). */
|
|
36
47
|
socialLogins?: Snippet;
|
|
@@ -84,14 +95,19 @@
|
|
|
84
95
|
mode = $bindable("login"),
|
|
85
96
|
loginData = $bindable(createEmptyLoginFormData()),
|
|
86
97
|
registerData = $bindable(createEmptyRegisterFormData()),
|
|
98
|
+
verifyEmail = $bindable(""),
|
|
87
99
|
onLogin,
|
|
88
100
|
onRegister,
|
|
101
|
+
onVerify,
|
|
102
|
+
onResendCode,
|
|
89
103
|
isSubmitting = false,
|
|
90
104
|
loginProps,
|
|
91
105
|
registerProps,
|
|
106
|
+
verifyProps,
|
|
92
107
|
modeSwitcher,
|
|
93
108
|
loginModeLabel,
|
|
94
109
|
registerModeLabel,
|
|
110
|
+
verifyModeLabel,
|
|
95
111
|
socialLogins,
|
|
96
112
|
socialDividerLabel,
|
|
97
113
|
footer,
|
|
@@ -112,9 +128,11 @@
|
|
|
112
128
|
|
|
113
129
|
let resolvedTitle = $derived(
|
|
114
130
|
title ??
|
|
115
|
-
(mode === "
|
|
116
|
-
? t("login_or_register_form.
|
|
117
|
-
:
|
|
131
|
+
(mode === "verify"
|
|
132
|
+
? t("login_or_register_form.modal_title_verify")
|
|
133
|
+
: mode === "login"
|
|
134
|
+
? t("login_or_register_form.modal_title_login")
|
|
135
|
+
: t("login_or_register_form.modal_title_register"))
|
|
118
136
|
);
|
|
119
137
|
|
|
120
138
|
let modal: Modal = $state()!;
|
|
@@ -164,14 +182,19 @@
|
|
|
164
182
|
bind:mode
|
|
165
183
|
bind:loginData
|
|
166
184
|
bind:registerData
|
|
185
|
+
bind:verifyEmail
|
|
167
186
|
{onLogin}
|
|
168
187
|
{onRegister}
|
|
188
|
+
{onVerify}
|
|
189
|
+
{onResendCode}
|
|
169
190
|
{isSubmitting}
|
|
170
191
|
{loginProps}
|
|
171
192
|
{registerProps}
|
|
193
|
+
{verifyProps}
|
|
172
194
|
{modeSwitcher}
|
|
173
195
|
{loginModeLabel}
|
|
174
196
|
{registerModeLabel}
|
|
197
|
+
{verifyModeLabel}
|
|
175
198
|
{socialLogins}
|
|
176
199
|
{socialDividerLabel}
|
|
177
200
|
{footer}
|
|
@@ -11,14 +11,22 @@ export interface Props {
|
|
|
11
11
|
loginData?: LoginFormData;
|
|
12
12
|
/** Bindable register formData */
|
|
13
13
|
registerData?: RegisterFormData;
|
|
14
|
+
/** Bindable email used by EmailVerifyForm. */
|
|
15
|
+
verifyEmail?: string;
|
|
14
16
|
onLogin: (data: LoginFormData) => void;
|
|
15
17
|
onRegister: (data: RegisterFormData) => void;
|
|
18
|
+
/** Called when the user submits a code in the verify view. */
|
|
19
|
+
onVerify?: (code: string) => void;
|
|
20
|
+
/** Called when the user clicks "Resend code" in the verify view. */
|
|
21
|
+
onResendCode?: () => Promise<void> | void;
|
|
16
22
|
isSubmitting?: boolean;
|
|
17
23
|
loginProps?: InnerProps["loginProps"];
|
|
18
24
|
registerProps?: InnerProps["registerProps"];
|
|
25
|
+
verifyProps?: InnerProps["verifyProps"];
|
|
19
26
|
modeSwitcher?: InnerProps["modeSwitcher"];
|
|
20
27
|
loginModeLabel?: string;
|
|
21
28
|
registerModeLabel?: string;
|
|
29
|
+
verifyModeLabel?: string;
|
|
22
30
|
/** Shared social logins (rendered below the active form). */
|
|
23
31
|
socialLogins?: Snippet;
|
|
24
32
|
socialDividerLabel?: string | false;
|
|
@@ -50,6 +58,6 @@ export interface Props {
|
|
|
50
58
|
declare const LoginOrRegisterFormModal: import("svelte").Component<Props, {
|
|
51
59
|
open: (openerOrEvent?: null | HTMLElement | MouseEvent) => void;
|
|
52
60
|
close: () => void;
|
|
53
|
-
}, "visible" | "mode" | "loginData" | "registerData">;
|
|
61
|
+
}, "visible" | "mode" | "loginData" | "registerData" | "verifyEmail">;
|
|
54
62
|
type LoginOrRegisterFormModal = ReturnType<typeof LoginOrRegisterFormModal>;
|
|
55
63
|
export default LoginOrRegisterFormModal;
|
package/dist/components/LoginOrRegisterForm/_internal/login-or-register-form-i18n-defaults.js
CHANGED
|
@@ -3,9 +3,11 @@ import { replaceMap } from "../../../utils/replace-map.js";
|
|
|
3
3
|
const DEFAULTS = {
|
|
4
4
|
"login_or_register_form.mode_login": "Log in",
|
|
5
5
|
"login_or_register_form.mode_register": "Sign up",
|
|
6
|
+
"login_or_register_form.mode_verify": "Verify",
|
|
6
7
|
"login_or_register_form.social_divider": "or continue with",
|
|
7
8
|
"login_or_register_form.modal_title_login": "Log In",
|
|
8
9
|
"login_or_register_form.modal_title_register": "Create account",
|
|
10
|
+
"login_or_register_form.modal_title_verify": "Verify your email",
|
|
9
11
|
};
|
|
10
12
|
export function t_default(k, values = null, fallback = "") {
|
|
11
13
|
const out = DEFAULTS[k] ?? (typeof fallback === "string" ? fallback : "") ?? k;
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { HTMLAttributes, HTMLInputAttributes } from "svelte/elements";
|
|
2
|
+
export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children" | "oninput"> {
|
|
3
|
+
/** Bindable concatenated value (e.g., "123456"). Length always equals `length` or shorter. */
|
|
4
|
+
value?: string;
|
|
5
|
+
/** Number of slots. Default: 6. Sensible range: 4..8. */
|
|
6
|
+
length?: number;
|
|
7
|
+
/** Fired when all slots are filled. Receives the concatenated string. */
|
|
8
|
+
onComplete?: (code: string) => void;
|
|
9
|
+
/** Fired on every change (keystroke, paste, backspace). */
|
|
10
|
+
oninput?: (value: string) => void;
|
|
11
|
+
/** When true, slots render in error styling (red border + aria-invalid). */
|
|
12
|
+
error?: boolean;
|
|
13
|
+
/** Disables all slots. */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
/** Auto-focus the first empty slot on mount. Default: true. */
|
|
16
|
+
autoFocus?: boolean;
|
|
17
|
+
/** Restrict input. "numeric" (default) | "alphanumeric". */
|
|
18
|
+
mode?: "numeric" | "alphanumeric";
|
|
19
|
+
/** Pass-through to first slot for browser auto-fill. Default: "one-time-code". */
|
|
20
|
+
autocomplete?: HTMLInputAttributes["autocomplete"];
|
|
21
|
+
/** Skip default styling */
|
|
22
|
+
unstyled?: boolean;
|
|
23
|
+
/** Additional CSS classes on the root */
|
|
24
|
+
class?: string;
|
|
25
|
+
/** Bindable root element ref */
|
|
26
|
+
el?: HTMLDivElement;
|
|
27
|
+
}
|
|
28
|
+
declare const OtpInput: import("svelte").Component<Props, {}, "el" | "value">;
|
|
29
|
+
type OtpInput = ReturnType<typeof OtpInput>;
|
|
30
|
+
export default OtpInput;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# OtpInput
|
|
2
|
+
|
|
3
|
+
Generic N-slot one-time-code input. 6 digits by default, configurable. Building block for email verification, 2FA, and password-reset OTP flows.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```svelte
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import { OtpInput } from "@marianmeres/stuic";
|
|
10
|
+
|
|
11
|
+
let code = $state("");
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<OtpInput
|
|
15
|
+
bind:value={code}
|
|
16
|
+
length={6}
|
|
17
|
+
onComplete={(c) => console.log("Got code:", c)}
|
|
18
|
+
/>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Props
|
|
22
|
+
|
|
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 |
|
|
37
|
+
|
|
38
|
+
## Behavior
|
|
39
|
+
|
|
40
|
+
- **Auto-advance**: typing in slot K moves focus to slot K+1.
|
|
41
|
+
- **Backspace**: clears current slot; if already empty, jumps to and clears slot K-1.
|
|
42
|
+
- **Arrow keys**: ←/→ navigate without modifying values.
|
|
43
|
+
- **Paste**: any slot accepts paste; the pasted string is sanitized to allowed chars, truncated to `length`, and distributed across all slots starting from slot 0.
|
|
44
|
+
- **iOS/Android SMS auto-fill**: first slot has `autocomplete="one-time-code"` by default. The OS auto-fills the full code into slot 0 — the input handler distributes it.
|
|
45
|
+
- **Click**: focusing a filled slot selects its content (for easy overwrite).
|
|
46
|
+
- **Enter**: bubbles a native submit to the surrounding `<form>`.
|
|
47
|
+
- **Accessibility**: each slot gets `aria-label="Digit {n+1} of {length}"`.
|
|
48
|
+
|
|
49
|
+
## CSS Tokens
|
|
50
|
+
|
|
51
|
+
Prefix: `--stuic-otp-input-*`
|
|
52
|
+
|
|
53
|
+
`gap`, `slot-size`, `font-size`, `bg`, `color`, `radius`, `border-width`, `border-color`, `border-color-focus`, `border-color-error`, `transition`
|
|
54
|
+
|
|
55
|
+
The shared structural tokens `--stuic-radius`, `--stuic-border-width`, and `--stuic-transition` are used as fallbacks.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.stuic-otp-input {
|
|
3
|
+
display: flex;
|
|
4
|
+
gap: var(--stuic-otp-input-gap, 0.5rem);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.stuic-otp-input-slot {
|
|
8
|
+
width: var(--stuic-otp-input-slot-size, 2.75rem);
|
|
9
|
+
height: var(--stuic-otp-input-slot-size, 2.75rem);
|
|
10
|
+
text-align: center;
|
|
11
|
+
font-size: var(--stuic-otp-input-font-size, 1.25rem);
|
|
12
|
+
font-variant-numeric: tabular-nums;
|
|
13
|
+
background: var(--stuic-otp-input-bg, var(--stuic-color-background));
|
|
14
|
+
color: var(--stuic-otp-input-color, var(--stuic-color-foreground));
|
|
15
|
+
border-radius: var(--stuic-otp-input-radius, var(--stuic-radius));
|
|
16
|
+
border-style: solid;
|
|
17
|
+
border-width: var(--stuic-otp-input-border-width, var(--stuic-border-width));
|
|
18
|
+
border-color: var(--stuic-otp-input-border-color, var(--stuic-color-border));
|
|
19
|
+
transition: border-color var(--stuic-otp-input-transition, var(--stuic-transition));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.stuic-otp-input-slot:focus {
|
|
23
|
+
border-color: var(
|
|
24
|
+
--stuic-otp-input-border-color-focus,
|
|
25
|
+
var(--stuic-color-primary)
|
|
26
|
+
);
|
|
27
|
+
outline: none;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.stuic-otp-input-slot:disabled {
|
|
31
|
+
opacity: 0.5;
|
|
32
|
+
cursor: not-allowed;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.stuic-otp-input[data-error="true"] .stuic-otp-input-slot {
|
|
36
|
+
border-color: var(
|
|
37
|
+
--stuic-otp-input-border-color-error,
|
|
38
|
+
var(--stuic-color-destructive)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as OtpInput, type Props as OtpInputProps, } from "./OtpInput.svelte";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as OtpInput, } from "./OtpInput.svelte";
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import type { HTMLAttributes } from "svelte/elements";
|
|
3
3
|
import type { THC } from "../Thc/index.js";
|
|
4
|
+
import { tr, type MaybeLocalized } from "../../utils/tr.js";
|
|
4
5
|
import { twMerge } from "../../utils/tw-merge.js";
|
|
5
6
|
import Thc from "../Thc/Thc.svelte";
|
|
6
7
|
|
|
7
8
|
export interface TabbedMenuItem {
|
|
8
9
|
id: string | number;
|
|
9
|
-
label: THC;
|
|
10
|
+
label: THC | MaybeLocalized;
|
|
10
11
|
disabled?: boolean;
|
|
11
12
|
class?: string;
|
|
12
13
|
data?: Record<string, any>;
|
|
@@ -20,6 +21,8 @@
|
|
|
20
21
|
disabled?: boolean;
|
|
21
22
|
onSelect?: (item: TabbedMenuItem) => void;
|
|
22
23
|
orientation?: "horizontal" | "vertical";
|
|
24
|
+
/** Current locale for MaybeLocalized resolution */
|
|
25
|
+
locale?: string;
|
|
23
26
|
//
|
|
24
27
|
class?: string;
|
|
25
28
|
classItem?: string;
|
|
@@ -41,6 +44,7 @@
|
|
|
41
44
|
disabled,
|
|
42
45
|
onSelect,
|
|
43
46
|
orientation = "horizontal",
|
|
47
|
+
locale,
|
|
44
48
|
//
|
|
45
49
|
class: classProp,
|
|
46
50
|
classItem,
|
|
@@ -54,6 +58,26 @@
|
|
|
54
58
|
...rest
|
|
55
59
|
}: Props = $props();
|
|
56
60
|
|
|
61
|
+
// The `label` accepts both THC and MaybeLocalized. Since MaybeLocalized's
|
|
62
|
+
// `Record<string, string>` shape has no discriminator key that Thc recognizes
|
|
63
|
+
// (`text`/`html`/`component`/`snippet`), a locale-keyed object would otherwise
|
|
64
|
+
// fall through to Thc's string-cast fallback and render as `[object Object]`.
|
|
65
|
+
// So we detect that case here and resolve it via `tr()` before handing to Thc.
|
|
66
|
+
function resolveLabel(label: TabbedMenuItem["label"]): THC {
|
|
67
|
+
if (
|
|
68
|
+
label &&
|
|
69
|
+
typeof label === "object" &&
|
|
70
|
+
typeof label !== "function" &&
|
|
71
|
+
!("text" in label) &&
|
|
72
|
+
!("html" in label) &&
|
|
73
|
+
!("component" in label) &&
|
|
74
|
+
!("snippet" in label)
|
|
75
|
+
) {
|
|
76
|
+
return tr(label as MaybeLocalized, locale);
|
|
77
|
+
}
|
|
78
|
+
return label as THC;
|
|
79
|
+
}
|
|
80
|
+
|
|
57
81
|
let buttonEls = $state<Record<string | number, HTMLButtonElement | HTMLAnchorElement>>(
|
|
58
82
|
{}
|
|
59
83
|
);
|
|
@@ -136,11 +160,11 @@
|
|
|
136
160
|
>
|
|
137
161
|
{#if item.href}
|
|
138
162
|
<a href={item.href} {...props} bind:this={buttonEls[item.id]}>
|
|
139
|
-
<Thc thc={item.label} />
|
|
163
|
+
<Thc thc={resolveLabel(item.label)} />
|
|
140
164
|
</a>
|
|
141
165
|
{:else}
|
|
142
166
|
<button type="button" {...props} bind:this={buttonEls[item.id]}>
|
|
143
|
-
<Thc thc={item.label} />
|
|
167
|
+
<Thc thc={resolveLabel(item.label)} />
|
|
144
168
|
</button>
|
|
145
169
|
{/if}
|
|
146
170
|
</li>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { HTMLAttributes } from "svelte/elements";
|
|
2
2
|
import type { THC } from "../Thc/index.js";
|
|
3
|
+
import { type MaybeLocalized } from "../../utils/tr.js";
|
|
3
4
|
export interface TabbedMenuItem {
|
|
4
5
|
id: string | number;
|
|
5
|
-
label: THC;
|
|
6
|
+
label: THC | MaybeLocalized;
|
|
6
7
|
disabled?: boolean;
|
|
7
8
|
class?: string;
|
|
8
9
|
data?: Record<string, any>;
|
|
@@ -15,6 +16,8 @@ export interface Props extends Omit<HTMLAttributes<HTMLUListElement>, "children"
|
|
|
15
16
|
disabled?: boolean;
|
|
16
17
|
onSelect?: (item: TabbedMenuItem) => void;
|
|
17
18
|
orientation?: "horizontal" | "vertical";
|
|
19
|
+
/** Current locale for MaybeLocalized resolution */
|
|
20
|
+
locale?: string;
|
|
18
21
|
class?: string;
|
|
19
22
|
classItem?: string;
|
|
20
23
|
classButton?: string;
|
package/dist/index.css
CHANGED
|
@@ -71,6 +71,7 @@ In practice:
|
|
|
71
71
|
@import "./components/DataTable/index.css";
|
|
72
72
|
@import "./components/DismissibleMessage/index.css";
|
|
73
73
|
@import "./components/DropdownMenu/index.css";
|
|
74
|
+
@import "./components/EmailVerifyForm/index.css";
|
|
74
75
|
@import "./components/H/index.css";
|
|
75
76
|
@import "./components/Header/index.css";
|
|
76
77
|
@import "./components/ImageCycler/index.css";
|
|
@@ -82,6 +83,7 @@ In practice:
|
|
|
82
83
|
@import "./components/ModalDialog/index.css";
|
|
83
84
|
@import "./components/Nav/index.css";
|
|
84
85
|
@import "./components/Notifications/index.css";
|
|
86
|
+
@import "./components/OtpInput/index.css";
|
|
85
87
|
@import "./components/PricingTable/index.css";
|
|
86
88
|
@import "./components/Progress/index.css";
|
|
87
89
|
@import "./components/Separator/index.css";
|
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export * from "./components/DataTable/index.js";
|
|
|
43
43
|
export * from "./components/DismissibleMessage/index.js";
|
|
44
44
|
export * from "./components/Drawer/index.js";
|
|
45
45
|
export * from "./components/DropdownMenu/index.js";
|
|
46
|
+
export * from "./components/EmailVerifyForm/index.js";
|
|
46
47
|
export * from "./components/H/index.js";
|
|
47
48
|
export * from "./components/Header/index.js";
|
|
48
49
|
export * from "./components/ImageCycler/index.js";
|
|
@@ -58,6 +59,7 @@ export * from "./components/Modal/index.js";
|
|
|
58
59
|
export * from "./components/ModalDialog/index.js";
|
|
59
60
|
export * from "./components/Nav/index.js";
|
|
60
61
|
export * from "./components/Notifications/index.js";
|
|
62
|
+
export * from "./components/OtpInput/index.js";
|
|
61
63
|
export * from "./components/PricingTable/index.js";
|
|
62
64
|
export * from "./components/Progress/index.js";
|
|
63
65
|
export * from "./components/Separator/index.js";
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,7 @@ export * from "./components/DataTable/index.js";
|
|
|
44
44
|
export * from "./components/DismissibleMessage/index.js";
|
|
45
45
|
export * from "./components/Drawer/index.js";
|
|
46
46
|
export * from "./components/DropdownMenu/index.js";
|
|
47
|
+
export * from "./components/EmailVerifyForm/index.js";
|
|
47
48
|
export * from "./components/H/index.js";
|
|
48
49
|
export * from "./components/Header/index.js";
|
|
49
50
|
export * from "./components/ImageCycler/index.js";
|
|
@@ -59,6 +60,7 @@ export * from "./components/Modal/index.js";
|
|
|
59
60
|
export * from "./components/ModalDialog/index.js";
|
|
60
61
|
export * from "./components/Nav/index.js";
|
|
61
62
|
export * from "./components/Notifications/index.js";
|
|
63
|
+
export * from "./components/OtpInput/index.js";
|
|
62
64
|
export * from "./components/PricingTable/index.js";
|
|
63
65
|
export * from "./components/Progress/index.js";
|
|
64
66
|
export * from "./components/Separator/index.js";
|