@marianmeres/stuic 3.67.0 → 3.69.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/DataTable/DataTable.svelte +182 -26
- package/dist/components/DataTable/DataTable.svelte.d.ts +45 -3
- package/dist/components/DataTable/README.md +84 -8
- package/dist/components/DataTable/index.css +24 -0
- package/dist/components/LoginOrRegisterForm/LoginOrRegisterForm.svelte +223 -0
- package/dist/components/LoginOrRegisterForm/LoginOrRegisterForm.svelte.d.ts +68 -0
- package/dist/components/LoginOrRegisterForm/LoginOrRegisterFormModal.svelte +184 -0
- package/dist/components/LoginOrRegisterForm/LoginOrRegisterFormModal.svelte.d.ts +55 -0
- package/dist/components/LoginOrRegisterForm/_internal/login-or-register-form-i18n-defaults.d.ts +1 -0
- package/dist/components/LoginOrRegisterForm/_internal/login-or-register-form-i18n-defaults.js +17 -0
- package/dist/components/LoginOrRegisterForm/index.css +66 -0
- package/dist/components/LoginOrRegisterForm/index.d.ts +2 -0
- package/dist/components/LoginOrRegisterForm/index.js +2 -0
- package/dist/components/RegisterForm/RegisterForm.svelte +367 -0
- package/dist/components/RegisterForm/RegisterForm.svelte.d.ts +77 -0
- package/dist/components/RegisterForm/RegisterFormModal.svelte +212 -0
- package/dist/components/RegisterForm/RegisterFormModal.svelte.d.ts +82 -0
- package/dist/components/RegisterForm/_internal/register-form-i18n-defaults.d.ts +1 -0
- package/dist/components/RegisterForm/_internal/register-form-i18n-defaults.js +30 -0
- package/dist/components/RegisterForm/_internal/register-form-types.d.ts +35 -0
- package/dist/components/RegisterForm/_internal/register-form-types.js +1 -0
- package/dist/components/RegisterForm/_internal/register-form-utils.d.ts +7 -0
- package/dist/components/RegisterForm/_internal/register-form-utils.js +55 -0
- package/dist/components/RegisterForm/index.css +70 -0
- package/dist/components/RegisterForm/index.d.ts +4 -0
- package/dist/components/RegisterForm/index.js +3 -0
- package/dist/index.css +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
import type { TranslateFn } from "../../types.js";
|
|
3
|
+
import type { RegisterFieldConfig, RegisterFormData, RegisterFormValidationError } from "./_internal/register-form-types.js";
|
|
4
|
+
import type { NotificationsStack } from "../Notifications/notifications-stack.svelte.js";
|
|
5
|
+
export interface Props {
|
|
6
|
+
/** Bindable register data. Default: createEmptyRegisterFormData() */
|
|
7
|
+
formData?: RegisterFormData;
|
|
8
|
+
/** Called on form submit after client-side validation passes. */
|
|
9
|
+
onSubmit: (data: RegisterFormData) => void;
|
|
10
|
+
/** Whether the form is currently submitting (disables CTA) */
|
|
11
|
+
isSubmitting?: boolean;
|
|
12
|
+
/** Field-specific validation errors (e.g., from server) */
|
|
13
|
+
errors?: RegisterFormValidationError[];
|
|
14
|
+
/**
|
|
15
|
+
* General error message (not field-specific).
|
|
16
|
+
* Rendered as an alert box above the form.
|
|
17
|
+
*/
|
|
18
|
+
error?: string;
|
|
19
|
+
/** Show password confirmation field. Default: true */
|
|
20
|
+
showPasswordConfirm?: boolean;
|
|
21
|
+
/** Minimum password length. Default: 8 */
|
|
22
|
+
passwordMinLength?: number;
|
|
23
|
+
/** Declarative extra fields */
|
|
24
|
+
extraFields?: RegisterFieldConfig[];
|
|
25
|
+
/** Escape-hatch slot for non-FieldInput extras */
|
|
26
|
+
extraFieldsSlot?: Snippet<[
|
|
27
|
+
{
|
|
28
|
+
formData: RegisterFormData;
|
|
29
|
+
fieldError: (name: string) => string | undefined;
|
|
30
|
+
}
|
|
31
|
+
]>;
|
|
32
|
+
/** Override CTA label */
|
|
33
|
+
submitLabel?: string;
|
|
34
|
+
/** Override CTA label while submitting */
|
|
35
|
+
submittingLabel?: string;
|
|
36
|
+
/** Override the CTA section */
|
|
37
|
+
submitButton?: Snippet<[{
|
|
38
|
+
isSubmitting: boolean;
|
|
39
|
+
disabled: boolean;
|
|
40
|
+
}]>;
|
|
41
|
+
/**
|
|
42
|
+
* Social/OAuth login buttons rendered below the primary form.
|
|
43
|
+
*/
|
|
44
|
+
socialLogins?: Snippet;
|
|
45
|
+
/**
|
|
46
|
+
* Override the divider label above social login buttons.
|
|
47
|
+
*/
|
|
48
|
+
socialDividerLabel?: string | false;
|
|
49
|
+
/**
|
|
50
|
+
* Content below the form.
|
|
51
|
+
*/
|
|
52
|
+
footer?: Snippet;
|
|
53
|
+
/** Optional notifications instance */
|
|
54
|
+
notifications?: NotificationsStack;
|
|
55
|
+
/** Modal title. Default: i18n key "register_form.modal_title" ("Create account") */
|
|
56
|
+
title?: string;
|
|
57
|
+
/** Bindable modal visibility */
|
|
58
|
+
visible?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Optional trigger element rendered outside the modal.
|
|
61
|
+
* Receives an `open` callback.
|
|
62
|
+
*/
|
|
63
|
+
trigger?: Snippet<[{
|
|
64
|
+
open: () => void;
|
|
65
|
+
}]>;
|
|
66
|
+
/** CSS class for the Modal box */
|
|
67
|
+
classModal?: string;
|
|
68
|
+
/** CSS class for the Modal inner width container */
|
|
69
|
+
classInner?: string;
|
|
70
|
+
/** CSS class for the RegisterForm */
|
|
71
|
+
classForm?: string;
|
|
72
|
+
t?: TranslateFn;
|
|
73
|
+
unstyled?: boolean;
|
|
74
|
+
noXClose?: boolean;
|
|
75
|
+
onClose?: () => false | void;
|
|
76
|
+
}
|
|
77
|
+
declare const RegisterFormModal: import("svelte").Component<Props, {
|
|
78
|
+
open: (openerOrEvent?: null | HTMLElement | MouseEvent) => void;
|
|
79
|
+
close: () => void;
|
|
80
|
+
}, "visible" | "formData">;
|
|
81
|
+
type RegisterFormModal = ReturnType<typeof RegisterFormModal>;
|
|
82
|
+
export default RegisterFormModal;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function t_default(k: string, values?: false | null | undefined | Record<string, string | number>, fallback?: string | boolean): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isPlainObject } from "../../../utils/is-plain-object.js";
|
|
2
|
+
import { replaceMap } from "../../../utils/replace-map.js";
|
|
3
|
+
const DEFAULTS = {
|
|
4
|
+
"register_form.email_label": "Email",
|
|
5
|
+
"register_form.email_placeholder": "you@example.com",
|
|
6
|
+
"register_form.password_label": "Password",
|
|
7
|
+
"register_form.password_placeholder": "",
|
|
8
|
+
"register_form.password_confirm_label": "Confirm password",
|
|
9
|
+
"register_form.password_confirm_placeholder": "",
|
|
10
|
+
"register_form.submit": "Create account",
|
|
11
|
+
"register_form.submitting": "Creating account...",
|
|
12
|
+
"register_form.email_required": "Email is required",
|
|
13
|
+
"register_form.email_invalid": "Please enter a valid email address",
|
|
14
|
+
"register_form.password_required": "Password is required",
|
|
15
|
+
"register_form.password_too_short": "Password must be at least {min} characters",
|
|
16
|
+
"register_form.password_confirm_required": "Please confirm your password",
|
|
17
|
+
"register_form.password_mismatch": "Passwords do not match",
|
|
18
|
+
"register_form.field_required": "{label} is required",
|
|
19
|
+
"register_form.social_divider": "or continue with",
|
|
20
|
+
"register_form.already_have_account": "Already have an account?",
|
|
21
|
+
"register_form.modal_title": "Create account",
|
|
22
|
+
};
|
|
23
|
+
export function t_default(k, values = null, fallback = "") {
|
|
24
|
+
const out = DEFAULTS[k] ?? (typeof fallback === "string" ? fallback : "") ?? k;
|
|
25
|
+
return isPlainObject(values)
|
|
26
|
+
? replaceMap(out, values, {
|
|
27
|
+
preSearchKeyTransform: (k) => `{${k}}`,
|
|
28
|
+
})
|
|
29
|
+
: out;
|
|
30
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from "svelte/elements";
|
|
2
|
+
export interface RegisterFormData {
|
|
3
|
+
email: string;
|
|
4
|
+
password: string;
|
|
5
|
+
passwordConfirm: string;
|
|
6
|
+
/** Values for consumer-defined extraFields, keyed by field name. */
|
|
7
|
+
extra: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export interface RegisterFormValidationError {
|
|
10
|
+
field: string;
|
|
11
|
+
message: string;
|
|
12
|
+
}
|
|
13
|
+
/** Declarative descriptor for a consumer-defined FieldInput-style extra field. */
|
|
14
|
+
export interface RegisterFieldConfig {
|
|
15
|
+
/** Key under formData.extra where the value lives. Must be unique. */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Visible label (already translated; RegisterForm does not apply `t()` here). */
|
|
18
|
+
label: string;
|
|
19
|
+
/** FieldInput `type`. Default "text". */
|
|
20
|
+
type?: "text" | "email" | "tel" | "url" | "password" | "number";
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
autocomplete?: HTMLInputAttributes["autocomplete"];
|
|
24
|
+
/** Initial value to seed into formData.extra[name] if undefined. */
|
|
25
|
+
initialValue?: unknown;
|
|
26
|
+
/**
|
|
27
|
+
* Synchronous validator. Return empty string / undefined for "valid".
|
|
28
|
+
* Return a message string for "invalid" (wired into the same allErrors pipeline).
|
|
29
|
+
*/
|
|
30
|
+
validate?: (value: unknown, data: RegisterFormData) => string | undefined;
|
|
31
|
+
/** Render before core fields ("top") or after passwordConfirm ("bottom"). Default "bottom". */
|
|
32
|
+
position?: "top" | "bottom";
|
|
33
|
+
/** Extra passthrough props merged onto FieldInput. */
|
|
34
|
+
props?: Record<string, unknown>;
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RegisterFieldConfig, RegisterFormData, RegisterFormValidationError } from "./register-form-types.js";
|
|
2
|
+
import type { TranslateFn } from "../../../types.js";
|
|
3
|
+
export declare function validateRegisterForm(data: RegisterFormData, t: TranslateFn, extraFields?: RegisterFieldConfig[], options?: {
|
|
4
|
+
showPasswordConfirm?: boolean;
|
|
5
|
+
passwordMinLength?: number;
|
|
6
|
+
}): RegisterFormValidationError[];
|
|
7
|
+
export declare function createEmptyRegisterFormData(): RegisterFormData;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2
|
+
export function validateRegisterForm(data, t, extraFields = [], options = {}) {
|
|
3
|
+
const { showPasswordConfirm = true, passwordMinLength = 8 } = options;
|
|
4
|
+
const errors = [];
|
|
5
|
+
const trimmedEmail = data.email.trim();
|
|
6
|
+
if (!trimmedEmail) {
|
|
7
|
+
errors.push({ field: "email", message: t("register_form.email_required") });
|
|
8
|
+
}
|
|
9
|
+
else if (!EMAIL_RE.test(trimmedEmail)) {
|
|
10
|
+
errors.push({ field: "email", message: t("register_form.email_invalid") });
|
|
11
|
+
}
|
|
12
|
+
if (!data.password) {
|
|
13
|
+
errors.push({ field: "password", message: t("register_form.password_required") });
|
|
14
|
+
}
|
|
15
|
+
else if (data.password.length < passwordMinLength) {
|
|
16
|
+
errors.push({
|
|
17
|
+
field: "password",
|
|
18
|
+
message: t("register_form.password_too_short", { min: passwordMinLength }),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
if (showPasswordConfirm) {
|
|
22
|
+
if (!data.passwordConfirm) {
|
|
23
|
+
errors.push({
|
|
24
|
+
field: "passwordConfirm",
|
|
25
|
+
message: t("register_form.password_confirm_required"),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else if (data.password && data.password !== data.passwordConfirm) {
|
|
29
|
+
errors.push({
|
|
30
|
+
field: "passwordConfirm",
|
|
31
|
+
message: t("register_form.password_mismatch"),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
for (const cfg of extraFields) {
|
|
36
|
+
const value = data.extra?.[cfg.name];
|
|
37
|
+
const asString = typeof value === "string" ? value : value == null ? "" : String(value);
|
|
38
|
+
if (cfg.required && !asString.trim()) {
|
|
39
|
+
errors.push({
|
|
40
|
+
field: cfg.name,
|
|
41
|
+
message: t("register_form.field_required", { label: cfg.label }),
|
|
42
|
+
});
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (cfg.validate) {
|
|
46
|
+
const msg = cfg.validate(value, data);
|
|
47
|
+
if (msg)
|
|
48
|
+
errors.push({ field: cfg.name, message: msg });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return errors;
|
|
52
|
+
}
|
|
53
|
+
export function createEmptyRegisterFormData() {
|
|
54
|
+
return { email: "", password: "", passwordConfirm: "", extra: {} };
|
|
55
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
/* RegisterForm */
|
|
3
|
+
--stuic-register-form-gap: 0rem;
|
|
4
|
+
--stuic-register-form-gap-row: 1rem;
|
|
5
|
+
|
|
6
|
+
/* Social login section */
|
|
7
|
+
--stuic-register-form-social-margin-top: 1rem;
|
|
8
|
+
--stuic-register-form-social-gap: 0.75rem;
|
|
9
|
+
--stuic-register-form-social-divider-color: var(--stuic-color-muted-foreground);
|
|
10
|
+
--stuic-register-form-social-divider-line-color: var(--stuic-color-border);
|
|
11
|
+
--stuic-register-form-social-divider-font-size: var(--text-sm);
|
|
12
|
+
--stuic-register-form-social-divider-margin-bottom: 0.75rem;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@layer components {
|
|
16
|
+
.stuic-register-form {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
gap: var(--stuic-register-form-gap);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.stuic-register-form-submit {
|
|
23
|
+
margin-top: 1rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Social login container */
|
|
27
|
+
.stuic-register-form-social {
|
|
28
|
+
margin-top: var(--stuic-register-form-social-margin-top);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* "or continue with" divider */
|
|
32
|
+
.stuic-register-form-social-divider {
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: 1rem;
|
|
36
|
+
margin-bottom: var(--stuic-register-form-social-divider-margin-bottom);
|
|
37
|
+
color: var(--stuic-register-form-social-divider-color);
|
|
38
|
+
font-size: var(--stuic-register-form-social-divider-font-size);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.stuic-register-form-social-divider::before,
|
|
42
|
+
.stuic-register-form-social-divider::after {
|
|
43
|
+
content: "";
|
|
44
|
+
flex: 1;
|
|
45
|
+
border-top: 1px solid var(--stuic-register-form-social-divider-line-color);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Button container */
|
|
49
|
+
.stuic-register-form-social-buttons {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
gap: var(--stuic-register-form-social-gap);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.stuic-register-form-compact-cta {
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
margin-top: 0.5rem;
|
|
59
|
+
gap: 2rem;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.stuic-register-form[data-compact] {
|
|
63
|
+
.stuic-register-form-submit {
|
|
64
|
+
margin-top: 0.5rem;
|
|
65
|
+
}
|
|
66
|
+
.stuic-button {
|
|
67
|
+
flex: 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as RegisterForm, type Props as RegisterFormProps, } from "./RegisterForm.svelte";
|
|
2
|
+
export { default as RegisterFormModal, type Props as RegisterFormModalProps, } from "./RegisterFormModal.svelte";
|
|
3
|
+
export { createEmptyRegisterFormData } from "./_internal/register-form-utils.js";
|
|
4
|
+
export type { RegisterFormData, RegisterFormValidationError, RegisterFieldConfig, } from "./_internal/register-form-types.js";
|
package/dist/index.css
CHANGED
|
@@ -63,6 +63,8 @@ In practice:
|
|
|
63
63
|
@import "./components/Card/index.css";
|
|
64
64
|
@import "./components/Carousel/index.css";
|
|
65
65
|
@import "./components/LoginForm/index.css";
|
|
66
|
+
@import "./components/RegisterForm/index.css";
|
|
67
|
+
@import "./components/LoginOrRegisterForm/index.css";
|
|
66
68
|
@import "./components/Checkout/index.css";
|
|
67
69
|
@import "./components/CommandMenu/index.css";
|
|
68
70
|
@import "./components/CronInput/index.css";
|
package/dist/index.d.ts
CHANGED
|
@@ -51,6 +51,8 @@ export * from "./components/IconSwap/index.js";
|
|
|
51
51
|
export * from "./components/Input/index.js";
|
|
52
52
|
export * from "./components/KbdShortcut/index.js";
|
|
53
53
|
export * from "./components/LoginForm/index.js";
|
|
54
|
+
export * from "./components/RegisterForm/index.js";
|
|
55
|
+
export * from "./components/LoginOrRegisterForm/index.js";
|
|
54
56
|
export * from "./components/ListItemButton/index.js";
|
|
55
57
|
export * from "./components/Modal/index.js";
|
|
56
58
|
export * from "./components/ModalDialog/index.js";
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,8 @@ export * from "./components/IconSwap/index.js";
|
|
|
52
52
|
export * from "./components/Input/index.js";
|
|
53
53
|
export * from "./components/KbdShortcut/index.js";
|
|
54
54
|
export * from "./components/LoginForm/index.js";
|
|
55
|
+
export * from "./components/RegisterForm/index.js";
|
|
56
|
+
export * from "./components/LoginOrRegisterForm/index.js";
|
|
55
57
|
export * from "./components/ListItemButton/index.js";
|
|
56
58
|
export * from "./components/Modal/index.js";
|
|
57
59
|
export * from "./components/ModalDialog/index.js";
|