@urbicon-ui/blocks 6.21.1 → 6.21.2
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/NumberInput/NumberInput.svelte +197 -0
- package/dist/components/NumberInput/NumberInput.svelte.d.ts +4 -0
- package/dist/components/NumberInput/index.d.ts +55 -0
- package/dist/components/NumberInput/index.js +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +1 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/primitives/Badge/Badge.svelte +12 -4
- package/dist/primitives/Badge/index.d.ts +26 -6
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +11 -6
- package/dist/primitives/Breadcrumb/index.d.ts +2 -2
- package/dist/primitives/Checkbox/Checkbox.svelte +3 -3
- package/dist/primitives/Combobox/Combobox.svelte +478 -104
- package/dist/primitives/Combobox/combobox.variants.d.ts +89 -17
- package/dist/primitives/Combobox/combobox.variants.js +94 -13
- package/dist/primitives/Combobox/index.d.ts +166 -51
- package/dist/primitives/ConfirmDialog/index.d.ts +19 -0
- package/dist/primitives/Dialog/Dialog.svelte +74 -0
- package/dist/primitives/Dialog/index.d.ts +12 -1
- package/dist/primitives/Drawer/Drawer.svelte +2 -1
- package/dist/primitives/Drawer/drawer.variants.d.ts +8 -0
- package/dist/primitives/Drawer/drawer.variants.js +45 -10
- package/dist/primitives/Drawer/index.d.ts +13 -4
- package/dist/primitives/FormField/FormField.svelte +6 -6
- package/dist/primitives/FormField/index.d.ts +13 -4
- package/dist/primitives/Input/Input.svelte +8 -4
- package/dist/primitives/Menu/Menu.svelte +66 -4
- package/dist/primitives/Menu/index.d.ts +25 -0
- package/dist/primitives/Pagination/Pagination.svelte +28 -13
- package/dist/primitives/Pagination/index.d.ts +44 -0
- package/dist/primitives/Popover/Popover.svelte +10 -0
- package/dist/primitives/Popover/index.d.ts +3 -3
- package/dist/primitives/RadioGroup/RadioGroup.svelte +3 -3
- package/dist/primitives/Select/Select.svelte +21 -11
- package/dist/primitives/Select/index.d.ts +7 -0
- package/dist/primitives/Select/select.variants.d.ts +17 -17
- package/dist/primitives/Select/select.variants.js +18 -0
- package/dist/primitives/Slider/Slider.svelte +4 -8
- package/dist/primitives/Textarea/Textarea.svelte +4 -5
- package/dist/primitives/Textarea/textarea.variants.d.ts +7 -7
- package/dist/primitives/Textarea/textarea.variants.js +5 -2
- package/dist/primitives/Toast/Toaster.svelte +42 -2
- package/dist/primitives/Toast/index.d.ts +30 -0
- package/dist/primitives/Toast/toast.store.svelte.d.ts +25 -1
- package/dist/primitives/Toast/toast.store.svelte.js +91 -1
- package/dist/primitives/Toast/toast.variants.d.ts +18 -0
- package/dist/primitives/Toast/toast.variants.js +15 -0
- package/dist/primitives/Toggle/Toggle.svelte +17 -3
- package/dist/primitives/Toggle/index.d.ts +8 -2
- package/dist/primitives/Toggle/toggle.variants.d.ts +7 -0
- package/dist/primitives/Toggle/toggle.variants.js +26 -0
- package/dist/primitives/Tooltip/Tooltip.svelte +47 -21
- package/dist/primitives/Tooltip/Tooltip.svelte.d.ts +1 -1
- package/dist/primitives/Tooltip/index.d.ts +31 -3
- package/dist/primitives/Tooltip/tooltip.variants.d.ts +4 -4
- package/dist/primitives/Tooltip/tooltip.variants.js +2 -2
- package/dist/primitives/index.d.ts +3 -3
- package/dist/translations/de.d.ts +3 -0
- package/dist/translations/de.js +4 -1
- package/dist/translations/en.d.ts +3 -0
- package/dist/translations/en.js +4 -1
- package/dist/utils/guide.svelte.d.ts +8 -2
- package/dist/utils/guide.svelte.js +86 -5
- package/dist/utils/use-form-field.svelte.d.ts +9 -9
- package/dist/utils/use-form-field.svelte.js +12 -12
- package/package.json +3 -3
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
import WarningTriangleIconDefault from '../../icons/WarningTriangleIcon.svelte';
|
|
12
12
|
import DangerCircleIconDefault from '../../icons/DangerCircleIcon.svelte';
|
|
13
13
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
14
|
-
import
|
|
14
|
+
import Spinner from '../Spinner/Spinner.svelte';
|
|
15
|
+
import type { ToastData, ToastProps } from './index';
|
|
15
16
|
|
|
16
17
|
const bt = useBlocksI18n();
|
|
17
18
|
|
|
@@ -66,12 +67,25 @@
|
|
|
66
67
|
content: () => '',
|
|
67
68
|
title: () => '',
|
|
68
69
|
description: () => '',
|
|
70
|
+
actions: () => '',
|
|
71
|
+
actionButton: () => '',
|
|
72
|
+
cancelButton: () => '',
|
|
69
73
|
dismissButton: () => '',
|
|
70
74
|
progress: () => ''
|
|
71
75
|
}
|
|
72
76
|
: toastVariants({ placement })
|
|
73
77
|
);
|
|
74
78
|
|
|
79
|
+
// Run a toast action/cancel button: fire its handler, then dismiss unless the
|
|
80
|
+
// action opted out (`dismissOnClick: false`, e.g. a "Retry" that re-issues the
|
|
81
|
+
// async work and updates the same toast).
|
|
82
|
+
function runAction(toast: ToastData, which: 'action' | 'cancel') {
|
|
83
|
+
const action = toast[which];
|
|
84
|
+
if (!action) return;
|
|
85
|
+
action.onClick?.(toast.id);
|
|
86
|
+
if (action.dismissOnClick !== false) toaster.dismiss(toast.id);
|
|
87
|
+
}
|
|
88
|
+
|
|
75
89
|
function slot(key: keyof typeof styles, intent?: string) {
|
|
76
90
|
const overrides = slotClasses?.[key];
|
|
77
91
|
if (unstyled) return overrides ?? '';
|
|
@@ -115,7 +129,11 @@
|
|
|
115
129
|
{#each visibleToasts as toast (toast.id)}
|
|
116
130
|
{@const IntentIcon = INTENT_ICON_MAP[toast.intent] ?? INTENT_ICON_MAP.neutral}
|
|
117
131
|
<div class={slot('toast', toast.intent)} role="alert" transition:fly={flyParams()}>
|
|
118
|
-
|
|
132
|
+
{#if toast.loading}
|
|
133
|
+
<span class={slot('icon', toast.intent)}><Spinner size="sm" /></span>
|
|
134
|
+
{:else}
|
|
135
|
+
<IntentIcon class={slot('icon', toast.intent)} />
|
|
136
|
+
{/if}
|
|
119
137
|
|
|
120
138
|
<div class={slot('content')}>
|
|
121
139
|
{#if toast.title}
|
|
@@ -124,6 +142,28 @@
|
|
|
124
142
|
{#if toast.description}
|
|
125
143
|
<div class={slot('description')}>{toast.description}</div>
|
|
126
144
|
{/if}
|
|
145
|
+
{#if toast.action || toast.cancel}
|
|
146
|
+
<div class={slot('actions')}>
|
|
147
|
+
{#if toast.action}
|
|
148
|
+
<button
|
|
149
|
+
type="button"
|
|
150
|
+
class={slot('actionButton')}
|
|
151
|
+
onclick={() => runAction(toast, 'action')}
|
|
152
|
+
>
|
|
153
|
+
{toast.action.label}
|
|
154
|
+
</button>
|
|
155
|
+
{/if}
|
|
156
|
+
{#if toast.cancel}
|
|
157
|
+
<button
|
|
158
|
+
type="button"
|
|
159
|
+
class={slot('cancelButton')}
|
|
160
|
+
onclick={() => runAction(toast, 'cancel')}
|
|
161
|
+
>
|
|
162
|
+
{toast.cancel.label}
|
|
163
|
+
</button>
|
|
164
|
+
{/if}
|
|
165
|
+
</div>
|
|
166
|
+
{/if}
|
|
127
167
|
</div>
|
|
128
168
|
|
|
129
169
|
{#if toast.dismissible}
|
|
@@ -11,6 +11,17 @@ export declare const TOAST_INTENTS: readonly ["primary", "info", "success", "war
|
|
|
11
11
|
* standard intent palette.
|
|
12
12
|
*/
|
|
13
13
|
export type ToastIntent = (typeof TOAST_INTENTS)[number];
|
|
14
|
+
/**
|
|
15
|
+
* An action or cancel button rendered inside a toast (Sonner-style).
|
|
16
|
+
*/
|
|
17
|
+
export interface ToastAction {
|
|
18
|
+
/** Button label. */
|
|
19
|
+
label: string;
|
|
20
|
+
/** Click handler. Receives the toast id so the handler can dismiss/update it. */
|
|
21
|
+
onClick?: (id: string) => void;
|
|
22
|
+
/** Dismiss the toast after the click. @default true */
|
|
23
|
+
dismissOnClick?: boolean;
|
|
24
|
+
}
|
|
14
25
|
/**
|
|
15
26
|
* Internal data shape for a rendered toast. Created by `toaster.add()`.
|
|
16
27
|
*/
|
|
@@ -29,6 +40,25 @@ export interface ToastData {
|
|
|
29
40
|
dismissible: boolean;
|
|
30
41
|
/** Show an animated progress bar that counts down the remaining `duration`. @default true */
|
|
31
42
|
showProgress: boolean;
|
|
43
|
+
/** Primary action button (prominent). */
|
|
44
|
+
action?: ToastAction;
|
|
45
|
+
/** Secondary/cancel button (quiet). */
|
|
46
|
+
cancel?: ToastAction;
|
|
47
|
+
/** Render a spinner instead of the intent icon (used by `toaster.promise` while pending). @default false */
|
|
48
|
+
loading?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Per-state config for `toaster.promise`. Each state is either a plain title
|
|
52
|
+
* string or a full {@link ToastInput}; `success`/`error` may also be a function
|
|
53
|
+
* of the resolved value / rejection reason.
|
|
54
|
+
*/
|
|
55
|
+
export interface ToastPromiseOptions<T> {
|
|
56
|
+
/** Shown while the promise is pending (spinner, persistent, not dismissible). */
|
|
57
|
+
loading: string | ToastInput;
|
|
58
|
+
/** Shown when the promise resolves. */
|
|
59
|
+
success: string | ToastInput | ((value: T) => string | ToastInput);
|
|
60
|
+
/** Shown when the promise rejects. */
|
|
61
|
+
error: string | ToastInput | ((reason: unknown) => string | ToastInput);
|
|
32
62
|
}
|
|
33
63
|
/**
|
|
34
64
|
* Options accepted by `toaster.add()` and the shorthand methods (`info`, `success`, `warning`, `danger`).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ToastData, ToastInput, ToastShorthandOpts } from './index.js';
|
|
1
|
+
import type { ToastData, ToastInput, ToastPromiseOptions, ToastShorthandOpts } from './index.js';
|
|
2
2
|
import type { ToastPlacement } from './toast.variants.js';
|
|
3
3
|
/**
|
|
4
4
|
* Reactive store that manages the global toast queue.
|
|
@@ -24,6 +24,30 @@ declare class ToastStore {
|
|
|
24
24
|
registerSubscriber(): () => void;
|
|
25
25
|
/** Create a toast with full control over all options. Returns the toast ID for programmatic dismissal. */
|
|
26
26
|
add(input: ToastInput): string;
|
|
27
|
+
/**
|
|
28
|
+
* Merge new fields into an existing toast in place — same id, same stack
|
|
29
|
+
* position — and reset its auto-dismiss timer to the new `duration`. No-op if
|
|
30
|
+
* the toast is gone. Backs `promise()`, which flips a pending toast to
|
|
31
|
+
* success/error without it sliding out and a new one flying in.
|
|
32
|
+
*/
|
|
33
|
+
update(id: string, input: ToastInput): void;
|
|
34
|
+
/**
|
|
35
|
+
* Drive a toast through a promise's lifecycle (Sonner-style). Shows a
|
|
36
|
+
* persistent, non-dismissible spinner toast while pending, then flips it in
|
|
37
|
+
* place to success on resolve or danger on reject. `success`/`error` may be a
|
|
38
|
+
* plain title, a full {@link ToastInput}, or a function of the resolved value
|
|
39
|
+
* / rejection reason. Returns the toast id.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* toaster.promise(saveDraft(), {
|
|
44
|
+
* loading: 'Saving…',
|
|
45
|
+
* success: (draft) => `Saved “${draft.title}”`,
|
|
46
|
+
* error: (e) => `Could not save: ${e.message}`
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
promise<T>(promise: Promise<T>, opts: ToastPromiseOptions<T>): string;
|
|
27
51
|
/** Remove a single toast by ID. Clears its auto-dismiss timer. */
|
|
28
52
|
dismiss(id: string): void;
|
|
29
53
|
/** Remove all toasts and cancel their timers. */
|
|
@@ -50,7 +50,10 @@ class ToastStore {
|
|
|
50
50
|
description: input.description,
|
|
51
51
|
duration: input.duration ?? 5000,
|
|
52
52
|
dismissible: input.dismissible ?? true,
|
|
53
|
-
showProgress: input.showProgress ?? true
|
|
53
|
+
showProgress: input.showProgress ?? true,
|
|
54
|
+
action: input.action,
|
|
55
|
+
cancel: input.cancel,
|
|
56
|
+
loading: input.loading ?? false
|
|
54
57
|
};
|
|
55
58
|
this.toasts = [...this.toasts, toast];
|
|
56
59
|
if (toast.duration > 0) {
|
|
@@ -58,6 +61,93 @@ class ToastStore {
|
|
|
58
61
|
}
|
|
59
62
|
return id;
|
|
60
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Merge new fields into an existing toast in place — same id, same stack
|
|
66
|
+
* position — and reset its auto-dismiss timer to the new `duration`. No-op if
|
|
67
|
+
* the toast is gone. Backs `promise()`, which flips a pending toast to
|
|
68
|
+
* success/error without it sliding out and a new one flying in.
|
|
69
|
+
*/
|
|
70
|
+
update(id, input) {
|
|
71
|
+
const idx = this.toasts.findIndex((t) => t.id === id);
|
|
72
|
+
if (idx === -1)
|
|
73
|
+
return;
|
|
74
|
+
const next = { ...this.toasts[idx], ...input };
|
|
75
|
+
this.toasts = [...this.toasts.slice(0, idx), next, ...this.toasts.slice(idx + 1)];
|
|
76
|
+
const timer = this.timers.get(id);
|
|
77
|
+
if (timer) {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
this.timers.delete(id);
|
|
80
|
+
}
|
|
81
|
+
if (next.duration > 0) {
|
|
82
|
+
this.timers.set(id, setTimeout(() => this.dismiss(id), next.duration));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Drive a toast through a promise's lifecycle (Sonner-style). Shows a
|
|
87
|
+
* persistent, non-dismissible spinner toast while pending, then flips it in
|
|
88
|
+
* place to success on resolve or danger on reject. `success`/`error` may be a
|
|
89
|
+
* plain title, a full {@link ToastInput}, or a function of the resolved value
|
|
90
|
+
* / rejection reason. Returns the toast id.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* toaster.promise(saveDraft(), {
|
|
95
|
+
* loading: 'Saving…',
|
|
96
|
+
* success: (draft) => `Saved “${draft.title}”`,
|
|
97
|
+
* error: (e) => `Could not save: ${e.message}`
|
|
98
|
+
* });
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
promise(promise, opts) {
|
|
102
|
+
const loadingInput = typeof opts.loading === 'string' ? { title: opts.loading } : opts.loading;
|
|
103
|
+
const id = this.add({
|
|
104
|
+
intent: 'neutral',
|
|
105
|
+
...loadingInput,
|
|
106
|
+
loading: true,
|
|
107
|
+
duration: 0,
|
|
108
|
+
dismissible: false,
|
|
109
|
+
showProgress: false
|
|
110
|
+
});
|
|
111
|
+
// Shared settle fields: leave the spinner/persistent/non-dismissible state
|
|
112
|
+
// and become a normal auto-dismissing toast. `description: undefined` clears
|
|
113
|
+
// the loading description unless the success/error config sets its own.
|
|
114
|
+
const settled = {
|
|
115
|
+
loading: false,
|
|
116
|
+
duration: 5000,
|
|
117
|
+
dismissible: true,
|
|
118
|
+
showProgress: true
|
|
119
|
+
};
|
|
120
|
+
// A throwing user formatter must not turn into an unhandled rejection on the
|
|
121
|
+
// internal `.then`; fall back to a bare settled toast (still flips out of the
|
|
122
|
+
// loading state) and dev-warn instead.
|
|
123
|
+
const resolveMessage = (fn, arg, label) => {
|
|
124
|
+
let out;
|
|
125
|
+
try {
|
|
126
|
+
out = typeof fn === 'function' ? fn(arg) : fn;
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
if (import.meta.env?.DEV)
|
|
130
|
+
console.warn(`[Toast] promise ${label} formatter threw:`, err);
|
|
131
|
+
}
|
|
132
|
+
return typeof out === 'string' ? { title: out } : out;
|
|
133
|
+
};
|
|
134
|
+
promise.then((value) => {
|
|
135
|
+
this.update(id, {
|
|
136
|
+
intent: 'success',
|
|
137
|
+
description: undefined,
|
|
138
|
+
...settled,
|
|
139
|
+
...resolveMessage(opts.success, value, 'success')
|
|
140
|
+
});
|
|
141
|
+
}, (reason) => {
|
|
142
|
+
this.update(id, {
|
|
143
|
+
intent: 'danger',
|
|
144
|
+
description: undefined,
|
|
145
|
+
...settled,
|
|
146
|
+
...resolveMessage(opts.error, reason, 'error')
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
return id;
|
|
150
|
+
}
|
|
61
151
|
/** Remove a single toast by ID. Clears its auto-dismiss timer. */
|
|
62
152
|
dismiss(id) {
|
|
63
153
|
const timer = this.timers.get(id);
|
|
@@ -39,6 +39,24 @@ export declare const toastVariants: ((props?: {
|
|
|
39
39
|
} & {
|
|
40
40
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
41
41
|
}) | undefined) => string;
|
|
42
|
+
actions: (props?: ({
|
|
43
|
+
intent?: "primary" | "info" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
44
|
+
placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
|
|
45
|
+
} & {
|
|
46
|
+
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
47
|
+
}) | undefined) => string;
|
|
48
|
+
actionButton: (props?: ({
|
|
49
|
+
intent?: "primary" | "info" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
50
|
+
placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
|
|
51
|
+
} & {
|
|
52
|
+
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
53
|
+
}) | undefined) => string;
|
|
54
|
+
cancelButton: (props?: ({
|
|
55
|
+
intent?: "primary" | "info" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
56
|
+
placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
|
|
57
|
+
} & {
|
|
58
|
+
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
59
|
+
}) | undefined) => string;
|
|
42
60
|
dismissButton: (props?: ({
|
|
43
61
|
intent?: "primary" | "info" | "success" | "warning" | "danger" | "neutral" | undefined;
|
|
44
62
|
placement?: "bottom-right" | "top-right" | "bottom-left" | "top-left" | "top-center" | "bottom-center" | undefined;
|
|
@@ -16,6 +16,21 @@ export const toastVariants = tv({
|
|
|
16
16
|
content: 'flex-1 min-w-0',
|
|
17
17
|
title: 'font-semibold text-sm leading-tight',
|
|
18
18
|
description: 'text-sm mt-0.5 opacity-80',
|
|
19
|
+
// Action row (Sonner-style). Intent-neutral, prominent primary + quiet
|
|
20
|
+
// cancel — the toast's intent already reads through the icon/progress, so
|
|
21
|
+
// the buttons stay contrast-based rather than intent-coloured.
|
|
22
|
+
actions: 'flex items-center gap-2 mt-2.5',
|
|
23
|
+
// tier: modify — small interactive sub-elements on a contain surface.
|
|
24
|
+
actionButton: [
|
|
25
|
+
'rounded-modify px-2.5 py-1 text-xs font-medium',
|
|
26
|
+
'bg-text-primary/10 hover:bg-text-primary/20 text-text-primary',
|
|
27
|
+
'transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current/40'
|
|
28
|
+
],
|
|
29
|
+
cancelButton: [
|
|
30
|
+
'rounded-modify px-2.5 py-1 text-xs font-medium',
|
|
31
|
+
'text-text-secondary hover:text-text-primary',
|
|
32
|
+
'transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current/40'
|
|
33
|
+
],
|
|
19
34
|
// tier: modify — small interactive sub-element on a contain surface.
|
|
20
35
|
dismissButton: [
|
|
21
36
|
'shrink-0 rounded-modify p-1',
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
checked = $bindable(false),
|
|
12
12
|
label,
|
|
13
13
|
helper,
|
|
14
|
+
error,
|
|
14
15
|
tier,
|
|
15
16
|
size = 'md',
|
|
16
17
|
intent = 'primary',
|
|
@@ -35,7 +36,8 @@
|
|
|
35
36
|
const id = $derived(idProp ?? propsId);
|
|
36
37
|
const ff = useFormField(() => ({
|
|
37
38
|
fieldId: id,
|
|
38
|
-
|
|
39
|
+
helper,
|
|
40
|
+
error,
|
|
39
41
|
required,
|
|
40
42
|
disabled
|
|
41
43
|
}));
|
|
@@ -61,6 +63,7 @@
|
|
|
61
63
|
appearance,
|
|
62
64
|
checked,
|
|
63
65
|
disabled,
|
|
66
|
+
error: !!error,
|
|
64
67
|
withBorder
|
|
65
68
|
});
|
|
66
69
|
|
|
@@ -111,6 +114,7 @@
|
|
|
111
114
|
aria-checked={checked}
|
|
112
115
|
aria-label={label ? undefined : bt('accessibility.toggle') || 'Toggle'}
|
|
113
116
|
aria-describedby={ff.describedBy}
|
|
117
|
+
aria-invalid={ff.invalid ? 'true' : undefined}
|
|
114
118
|
onchange={handleChange}
|
|
115
119
|
{...restProps}
|
|
116
120
|
/>
|
|
@@ -135,9 +139,19 @@
|
|
|
135
139
|
{/if}
|
|
136
140
|
</label>
|
|
137
141
|
|
|
138
|
-
{#if ff.
|
|
142
|
+
{#if ff.errorId}
|
|
143
|
+
<div
|
|
144
|
+
id={ff.errorId}
|
|
145
|
+
class={unstyled
|
|
146
|
+
? (slotClasses?.message ?? '')
|
|
147
|
+
: styles.message({ class: slotClasses?.message })}
|
|
148
|
+
role="alert"
|
|
149
|
+
>
|
|
150
|
+
{error}
|
|
151
|
+
</div>
|
|
152
|
+
{:else if ff.helperId}
|
|
139
153
|
<div
|
|
140
|
-
id={ff.
|
|
154
|
+
id={ff.helperId}
|
|
141
155
|
class={unstyled
|
|
142
156
|
? (slotClasses?.message ?? '')
|
|
143
157
|
: styles.message({ class: slotClasses?.message })}
|
|
@@ -24,13 +24,19 @@ import type { ToggleSlots, ToggleVariants } from './toggle.variants.js';
|
|
|
24
24
|
* />
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
|
-
export interface ToggleProps extends Omit<ToggleVariants, 'checked'>, Omit<HTMLInputAttributes, 'type' | 'size' | 'checked' | 'class' | 'children'> {
|
|
27
|
+
export interface ToggleProps extends Omit<ToggleVariants, 'checked' | 'error'>, Omit<HTMLInputAttributes, 'type' | 'size' | 'checked' | 'class' | 'children'> {
|
|
28
28
|
/** Current on/off state. Supports two-way binding via `bind:checked`. */
|
|
29
29
|
checked?: boolean;
|
|
30
30
|
/** Text label displayed to the right of the toggle track. */
|
|
31
31
|
label?: string;
|
|
32
|
-
/**
|
|
32
|
+
/** Helper text shown below the control. Hidden when `error` is set. Useful for explaining side-effects of the toggle. */
|
|
33
33
|
helper?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Error message shown below the control. Replaces `helper`, flags the
|
|
36
|
+
* hidden input `aria-invalid`, and marks the unchecked track with the
|
|
37
|
+
* danger colour — e.g. for a consent toggle that must be switched on.
|
|
38
|
+
*/
|
|
39
|
+
error?: string;
|
|
34
40
|
/** Prevent interaction and dim the control. */
|
|
35
41
|
disabled?: boolean;
|
|
36
42
|
/** Mark the native input as required for form validation. */
|
|
@@ -6,6 +6,7 @@ export declare const toggleVariants: ((props?: {
|
|
|
6
6
|
appearance?: "default" | "dot" | undefined;
|
|
7
7
|
checked?: boolean | undefined;
|
|
8
8
|
disabled?: boolean | undefined;
|
|
9
|
+
error?: boolean | undefined;
|
|
9
10
|
withBorder?: boolean | undefined;
|
|
10
11
|
} | undefined) => {
|
|
11
12
|
wrapper: (props?: ({
|
|
@@ -15,6 +16,7 @@ export declare const toggleVariants: ((props?: {
|
|
|
15
16
|
appearance?: "default" | "dot" | undefined;
|
|
16
17
|
checked?: boolean | undefined;
|
|
17
18
|
disabled?: boolean | undefined;
|
|
19
|
+
error?: boolean | undefined;
|
|
18
20
|
withBorder?: boolean | undefined;
|
|
19
21
|
} & {
|
|
20
22
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
@@ -26,6 +28,7 @@ export declare const toggleVariants: ((props?: {
|
|
|
26
28
|
appearance?: "default" | "dot" | undefined;
|
|
27
29
|
checked?: boolean | undefined;
|
|
28
30
|
disabled?: boolean | undefined;
|
|
31
|
+
error?: boolean | undefined;
|
|
29
32
|
withBorder?: boolean | undefined;
|
|
30
33
|
} & {
|
|
31
34
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
@@ -37,6 +40,7 @@ export declare const toggleVariants: ((props?: {
|
|
|
37
40
|
appearance?: "default" | "dot" | undefined;
|
|
38
41
|
checked?: boolean | undefined;
|
|
39
42
|
disabled?: boolean | undefined;
|
|
43
|
+
error?: boolean | undefined;
|
|
40
44
|
withBorder?: boolean | undefined;
|
|
41
45
|
} & {
|
|
42
46
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
@@ -48,6 +52,7 @@ export declare const toggleVariants: ((props?: {
|
|
|
48
52
|
appearance?: "default" | "dot" | undefined;
|
|
49
53
|
checked?: boolean | undefined;
|
|
50
54
|
disabled?: boolean | undefined;
|
|
55
|
+
error?: boolean | undefined;
|
|
51
56
|
withBorder?: boolean | undefined;
|
|
52
57
|
} & {
|
|
53
58
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
@@ -59,6 +64,7 @@ export declare const toggleVariants: ((props?: {
|
|
|
59
64
|
appearance?: "default" | "dot" | undefined;
|
|
60
65
|
checked?: boolean | undefined;
|
|
61
66
|
disabled?: boolean | undefined;
|
|
67
|
+
error?: boolean | undefined;
|
|
62
68
|
withBorder?: boolean | undefined;
|
|
63
69
|
} & {
|
|
64
70
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
@@ -70,6 +76,7 @@ export declare const toggleVariants: ((props?: {
|
|
|
70
76
|
appearance?: "default" | "dot" | undefined;
|
|
71
77
|
checked?: boolean | undefined;
|
|
72
78
|
disabled?: boolean | undefined;
|
|
79
|
+
error?: boolean | undefined;
|
|
73
80
|
withBorder?: boolean | undefined;
|
|
74
81
|
} & {
|
|
75
82
|
class?: string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | (string | number | false | /*elided*/ any | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined)[] | Record<string, boolean | null | undefined> | null | undefined;
|
|
@@ -86,6 +86,11 @@ export const toggleVariants = tv({
|
|
|
86
86
|
control: 'opacity-50 cursor-not-allowed pointer-events-none'
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
|
+
error: {
|
|
90
|
+
true: {
|
|
91
|
+
message: 'text-danger'
|
|
92
|
+
}
|
|
93
|
+
},
|
|
89
94
|
withBorder: {
|
|
90
95
|
true: {},
|
|
91
96
|
false: {}
|
|
@@ -153,6 +158,19 @@ export const toggleVariants = tv({
|
|
|
153
158
|
intent: 'neutral',
|
|
154
159
|
class: { track: 'bg-neutral border-neutral' }
|
|
155
160
|
},
|
|
161
|
+
// ── Error state: danger boundary on the unchecked track (Switch-Pill) ──
|
|
162
|
+
// Mirrors Checkbox ("error overrides unchecked border"): the off state
|
|
163
|
+
// carries the danger mark, the on state keeps its intent colour — an
|
|
164
|
+
// error on a boolean control usually means "must be switched on".
|
|
165
|
+
// The dot-appearance twin lives at the END of the compound list so it
|
|
166
|
+
// folds over the dot-unchecked `border-border-default` (order is
|
|
167
|
+
// semantic — later compounds win conflicting buckets).
|
|
168
|
+
{
|
|
169
|
+
appearance: 'default',
|
|
170
|
+
error: true,
|
|
171
|
+
checked: false,
|
|
172
|
+
class: { track: 'border-danger peer-focus-visible:ring-danger/40' }
|
|
173
|
+
},
|
|
156
174
|
// ── Thumb translation per size when checked (Switch-Pill only) ──
|
|
157
175
|
{ appearance: 'default', checked: true, size: 'xs', class: { thumb: 'translate-x-4' } },
|
|
158
176
|
{ appearance: 'default', checked: true, size: 'sm', class: { thumb: 'translate-x-5' } },
|
|
@@ -212,6 +230,13 @@ export const toggleVariants = tv({
|
|
|
212
230
|
checked: true,
|
|
213
231
|
intent: 'neutral',
|
|
214
232
|
class: { track: 'border-neutral bg-neutral' }
|
|
233
|
+
},
|
|
234
|
+
// ── Error state, dot appearance (must fold over dot-unchecked border) ──
|
|
235
|
+
{
|
|
236
|
+
appearance: 'dot',
|
|
237
|
+
error: true,
|
|
238
|
+
checked: false,
|
|
239
|
+
class: { track: 'border-danger' }
|
|
215
240
|
}
|
|
216
241
|
],
|
|
217
242
|
defaultVariants: {
|
|
@@ -221,6 +246,7 @@ export const toggleVariants = tv({
|
|
|
221
246
|
appearance: 'default',
|
|
222
247
|
checked: false,
|
|
223
248
|
disabled: false,
|
|
249
|
+
error: false,
|
|
224
250
|
withBorder: false
|
|
225
251
|
}
|
|
226
252
|
});
|