zabi-components 5.0.22 → 7.0.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/README.md +139 -1478
- package/THEME.md +473 -0
- package/THEMING.md +248 -0
- package/dist/atoms/ActionPanel.svelte +116 -0
- package/dist/atoms/ActionPanel.svelte.d.ts +19 -0
- package/dist/atoms/Badge.svelte +1 -1
- package/dist/atoms/Badge.svelte.d.ts +1 -1
- package/dist/atoms/Button.svelte +35 -16
- package/dist/atoms/Button.svelte.d.ts +3 -1
- package/dist/atoms/Card.svelte +49 -67
- package/dist/atoms/Card.svelte.d.ts +4 -4
- package/dist/atoms/CardHeader.svelte +15 -2
- package/dist/atoms/CardHeader.svelte.d.ts +5 -0
- package/dist/atoms/Checkbox.svelte +50 -76
- package/dist/atoms/Checkbox.svelte.d.ts +7 -2
- package/dist/atoms/CodeBlock.svelte +20 -34
- package/dist/atoms/CodeBlock.svelte.d.ts +1 -0
- package/dist/atoms/ColorPicker.svelte +3 -7
- package/dist/atoms/Container.svelte +41 -0
- package/dist/atoms/Container.svelte.d.ts +12 -0
- package/dist/atoms/Divider.svelte +68 -0
- package/dist/atoms/Divider.svelte.d.ts +13 -0
- package/dist/atoms/FeatureCard.svelte +35 -50
- package/dist/atoms/FeatureCard.svelte.d.ts +9 -4
- package/dist/atoms/IconButton.svelte +33 -24
- package/dist/atoms/IconButton.svelte.d.ts +4 -8
- package/dist/atoms/Input.svelte +58 -26
- package/dist/atoms/Input.svelte.d.ts +6 -1
- package/dist/atoms/List.svelte +2 -7
- package/dist/atoms/List.svelte.d.ts +1 -6
- package/dist/atoms/ListItem.svelte +54 -65
- package/dist/atoms/ListItem.svelte.d.ts +7 -13
- package/dist/atoms/ListItemLeading.svelte +19 -0
- package/dist/atoms/ListItemLeading.svelte.d.ts +9 -0
- package/dist/atoms/Progress.svelte +2 -2
- package/dist/atoms/Radio.svelte +51 -0
- package/dist/atoms/Radio.svelte.d.ts +14 -0
- package/dist/atoms/Select.svelte +28 -33
- package/dist/atoms/Select.svelte.d.ts +0 -10
- package/dist/atoms/SelectionControl.svelte +98 -0
- package/dist/atoms/SelectionControl.svelte.d.ts +26 -0
- package/dist/atoms/Skeleton.svelte +39 -15
- package/dist/atoms/Skeleton.svelte.d.ts +7 -3
- package/dist/atoms/Table.svelte +27 -0
- package/dist/atoms/Table.svelte.d.ts +10 -0
- package/dist/atoms/Text.svelte +46 -0
- package/dist/atoms/Text.svelte.d.ts +13 -0
- package/dist/atoms/Textarea.svelte +74 -53
- package/dist/atoms/Textarea.svelte.d.ts +6 -2
- package/dist/atoms/ThemeToggle.svelte +35 -24
- package/dist/atoms/ThemeToggle.svelte.d.ts +1 -0
- package/dist/atoms/Toast.svelte +55 -31
- package/dist/atoms/Toast.svelte.d.ts +4 -1
- package/dist/atoms/Toggle.svelte +37 -22
- package/dist/atoms/Toggle.svelte.d.ts +2 -1
- package/dist/atoms/Tooltip.svelte +90 -11
- package/dist/atoms/index.d.ts +6 -0
- package/dist/atoms/index.js +6 -0
- package/dist/atoms/selection-control.styles.d.ts +25 -0
- package/dist/atoms/selection-control.styles.js +30 -0
- package/dist/components/atoms/index.d.ts +6 -0
- package/dist/components/atoms/index.d.ts.map +1 -1
- package/dist/components/atoms/selection-control.styles.d.ts +26 -0
- package/dist/components/atoms/selection-control.styles.d.ts.map +1 -0
- package/dist/components/index.d.ts +42 -7
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/molecules/index.d.ts +10 -0
- package/dist/components/molecules/index.d.ts.map +1 -1
- package/dist/components/molecules/navigation-menu-context.d.ts +11 -0
- package/dist/components/molecules/navigation-menu-context.d.ts.map +1 -1
- package/dist/components/molecules/toast-store.d.ts +39 -0
- package/dist/components/molecules/toast-store.d.ts.map +1 -0
- package/dist/components/organisms/index.d.ts +3 -3
- package/dist/components/organisms/index.d.ts.map +1 -1
- package/dist/components/types/page.types.d.ts +69 -0
- package/dist/components/types/page.types.d.ts.map +1 -0
- package/dist/components/types/page.types.js +1 -0
- package/dist/components/types/variants.d.ts +64 -0
- package/dist/components/types/variants.d.ts.map +1 -0
- package/dist/components/types/variants.js +44 -0
- package/dist/components/util/fixed-sidebar-flyout.d.ts +23 -0
- package/dist/components/util/fixed-sidebar-flyout.d.ts.map +1 -0
- package/dist/components/util/focus-utils.d.ts +12 -0
- package/dist/components/util/focus-utils.d.ts.map +1 -0
- package/dist/components/util/ssr-safe.d.ts +17 -0
- package/dist/components/util/ssr-safe.d.ts.map +1 -0
- package/dist/index.d.ts +42 -7
- package/dist/index.js +45 -10
- package/dist/lib/layout-width-tokens.d.ts +17 -0
- package/dist/lib/layout-width-tokens.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/Button.d.ts +3 -0
- package/dist/lib/showcase/component-docs/Button.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/Input.d.ts +3 -0
- package/dist/lib/showcase/component-docs/Input.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/List.d.ts +3 -0
- package/dist/lib/showcase/component-docs/List.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/Modal.d.ts +3 -0
- package/dist/lib/showcase/component-docs/Modal.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/Radio.d.ts +3 -0
- package/dist/lib/showcase/component-docs/Radio.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts +3 -0
- package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/Skeleton.d.ts +3 -0
- package/dist/lib/showcase/component-docs/Skeleton.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/_shared.d.ts +12 -0
- package/dist/lib/showcase/component-docs/_shared.d.ts.map +1 -0
- package/dist/lib/showcase/component-docs/index.d.ts +4 -0
- package/dist/lib/showcase/component-docs/index.d.ts.map +1 -0
- package/dist/lib/showcase/components-catalog.d.ts +3 -0
- package/dist/lib/showcase/components-catalog.d.ts.map +1 -0
- package/dist/lib/showcase/components-showcase-constants.d.ts +89 -0
- package/dist/lib/showcase/components-showcase-constants.d.ts.map +1 -0
- package/dist/lib/showcase/docs-sidebar-helpers.d.ts +15 -0
- package/dist/lib/showcase/docs-sidebar-helpers.d.ts.map +1 -0
- package/dist/molecules/Alert.svelte +50 -23
- package/dist/molecules/Alert.svelte.d.ts +1 -1
- package/dist/molecules/ComponentDemo.svelte +54 -51
- package/dist/molecules/ContactForm.svelte +70 -65
- package/dist/molecules/Dropdown.svelte +99 -108
- package/dist/molecules/Dropdown.svelte.d.ts +12 -6
- package/dist/molecules/EmptyState.svelte +44 -0
- package/dist/molecules/EmptyState.svelte.d.ts +11 -0
- package/dist/molecules/FormField.svelte +89 -0
- package/dist/molecules/FormField.svelte.d.ts +23 -0
- package/dist/molecules/Header.svelte +41 -0
- package/dist/molecules/Header.svelte.d.ts +10 -0
- package/dist/molecules/ImageUpload.svelte +1 -1
- package/dist/molecules/Modal.svelte +39 -26
- package/dist/molecules/Modal.svelte.d.ts +4 -2
- package/dist/molecules/NavigationMenu.svelte +16 -0
- package/dist/molecules/NavigationMenu.svelte.d.ts +2 -0
- package/dist/molecules/NavigationMenuContent.svelte +9 -1
- package/dist/molecules/NavigationMenuLink.svelte +1 -1
- package/dist/molecules/NavigationMenuTrigger.svelte +9 -4
- package/dist/molecules/Page.svelte +16 -0
- package/dist/molecules/Page.svelte.d.ts +8 -0
- package/dist/molecules/PropsTable.svelte +61 -0
- package/dist/molecules/PropsTable.svelte.d.ts +8 -0
- package/dist/molecules/RadioGroup.svelte +197 -0
- package/dist/molecules/RadioGroup.svelte.d.ts +20 -0
- package/dist/molecules/Section.svelte +14 -23
- package/dist/molecules/Section.svelte.d.ts +2 -11
- package/dist/molecules/SidebarBrandHeader.svelte +68 -0
- package/dist/molecules/SidebarBrandHeader.svelte.d.ts +10 -0
- package/dist/molecules/SidebarFooter.svelte +119 -0
- package/dist/molecules/SidebarFooter.svelte.d.ts +23 -0
- package/dist/molecules/SidebarNavSection.svelte +49 -0
- package/dist/molecules/SidebarNavSection.svelte.d.ts +14 -0
- package/dist/molecules/SlideUp.svelte +21 -16
- package/dist/molecules/SlideUp.svelte.d.ts +1 -1
- package/dist/molecules/Tabs.svelte +6 -11
- package/dist/molecules/Toaster.svelte +21 -0
- package/dist/molecules/Toaster.svelte.d.ts +6 -0
- package/dist/molecules/ToasterToast.svelte +217 -0
- package/dist/molecules/ToasterToast.svelte.d.ts +7 -0
- package/dist/molecules/index.d.ts +10 -0
- package/dist/molecules/index.js +10 -0
- package/dist/molecules/navigation-menu-context.d.ts +11 -0
- package/dist/molecules/navigation-menu-context.js +18 -0
- package/dist/molecules/toast-store.d.ts +38 -0
- package/dist/molecules/toast-store.js +34 -0
- package/dist/organisms/SidebarAccountPanel.svelte +118 -0
- package/dist/organisms/SidebarAccountPanel.svelte.d.ts +20 -0
- package/dist/organisms/SidebarNavigation.svelte +286 -212
- package/dist/organisms/SidebarNavigation.svelte.d.ts +22 -1
- package/dist/organisms/{SidebarProjectPanel.svelte → SidebarPanel.svelte} +67 -34
- package/dist/organisms/{SidebarProjectPanel.svelte.d.ts → SidebarPanel.svelte.d.ts} +9 -6
- package/dist/organisms/TopNavbar.svelte +214 -0
- package/dist/organisms/TopNavbar.svelte.d.ts +35 -0
- package/dist/organisms/index.d.ts +3 -3
- package/dist/organisms/index.js +3 -3
- package/dist/routes/lib/focus-utils.d.ts +7 -18
- package/dist/routes/lib/focus-utils.ts +32 -34
- package/dist/routes/lib/ssr-safe.ts +5 -4
- package/dist/routes/lib/variant-utils.ts +48 -39
- package/dist/types/components.d.ts +187 -0
- package/dist/types/components.d.ts.map +1 -0
- package/dist/types/events.d.ts +200 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/index.d.ts +171 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/page.types.d.ts +3 -0
- package/dist/types/page.types.d.ts.map +1 -0
- package/dist/types/page.types.js +1 -0
- package/dist/types/page.types.ts +79 -0
- package/dist/types/variants.d.ts +3 -0
- package/dist/types/variants.d.ts.map +1 -0
- package/dist/types/variants.js +1 -0
- package/dist/types/variants.ts +75 -0
- package/dist/util/fixed-sidebar-flyout.d.ts +22 -0
- package/dist/util/fixed-sidebar-flyout.js +148 -0
- package/dist/util/focus-utils.d.ts +11 -0
- package/dist/util/focus-utils.js +94 -0
- package/dist/util/ssr-safe.d.ts +16 -0
- package/dist/util/ssr-safe.js +48 -0
- package/dist/zabi-components-colors.css +360 -324
- package/dist/zabi-components-theme-dark-only.css +164 -151
- package/dist/zabi-components-theme-dark.css +164 -151
- package/dist/zabi-components-theme-only.css +253 -230
- package/dist/zabi-components-theme.css +253 -230
- package/dist/zabi-components.css +1262 -241
- package/docs/theme-imports.md +112 -0
- package/package.json +32 -10
- package/dist/organisms/Navbar.svelte +0 -92
- package/dist/organisms/Navbar.svelte.d.ts +0 -14
- package/dist/organisms/Navigation.svelte +0 -119
- package/dist/organisms/Navigation.svelte.d.ts +0 -21
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { CheckCircle, AlertTriangle, AlertCircle } from
|
|
3
|
-
import type { SemanticVariant, SizeVariant } from
|
|
4
|
-
import { generateId } from "
|
|
2
|
+
import { CheckCircle, AlertTriangle, AlertCircle } from '@lucide/svelte';
|
|
3
|
+
import type { SemanticVariant, SizeVariant } from '../types/variants.js';
|
|
4
|
+
import { generateId } from "../util/ssr-safe.js";
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
|
+
id?: string;
|
|
7
8
|
value?: string;
|
|
8
9
|
name?: string;
|
|
10
|
+
class?: string;
|
|
9
11
|
label?: string;
|
|
12
|
+
hideLabel?: boolean;
|
|
10
13
|
placeholder?: string;
|
|
11
14
|
required?: boolean;
|
|
12
15
|
disabled?: boolean;
|
|
16
|
+
loading?: boolean;
|
|
13
17
|
rows?: number;
|
|
14
18
|
size?: SizeVariant;
|
|
15
19
|
variant?: SemanticVariant;
|
|
@@ -18,95 +22,112 @@
|
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
let {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
id: idProp,
|
|
26
|
+
value = $bindable(''),
|
|
27
|
+
name = '',
|
|
28
|
+
class: className = '',
|
|
29
|
+
label = '',
|
|
30
|
+
hideLabel = false,
|
|
31
|
+
placeholder = '',
|
|
25
32
|
required = false,
|
|
26
33
|
disabled = false,
|
|
34
|
+
loading = false,
|
|
27
35
|
rows = 4,
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
size = 'md',
|
|
37
|
+
variant = 'default',
|
|
38
|
+
message = '',
|
|
30
39
|
oninput,
|
|
31
40
|
...restProps
|
|
32
41
|
}: Props = $props();
|
|
33
42
|
|
|
34
|
-
const
|
|
43
|
+
const fallbackId = generateId('textarea');
|
|
44
|
+
const textareaId = $derived(idProp ?? fallbackId);
|
|
45
|
+
const isDisabled = $derived(disabled || loading);
|
|
35
46
|
|
|
36
47
|
const variantClass = $derived(() => {
|
|
37
|
-
return variant ===
|
|
38
|
-
?
|
|
39
|
-
: variant ===
|
|
40
|
-
?
|
|
41
|
-
: variant ===
|
|
42
|
-
?
|
|
43
|
-
:
|
|
48
|
+
return variant === 'success'
|
|
49
|
+
? 'border-success focus-visible:border-success'
|
|
50
|
+
: variant === 'warning'
|
|
51
|
+
? 'border-warning focus-visible:border-warning'
|
|
52
|
+
: variant === 'error'
|
|
53
|
+
? 'border-error focus-visible:border-error'
|
|
54
|
+
: 'border-input-border';
|
|
44
55
|
});
|
|
45
56
|
|
|
46
57
|
const textareaClasses = $derived(() => {
|
|
47
58
|
const baseClasses =
|
|
48
|
-
|
|
59
|
+
'focus-ring w-full border bg-input hover:bg-input-hover focus-visible:bg-input-focus disabled:bg-input-disabled rounded-lg transition-all duration-200 placeholder:text-description text-body focus:outline-none focus-visible:outline-none disabled:opacity-50 disabled:cursor-not-allowed resize-y px-4 py-2.5 text-base leading-6';
|
|
49
60
|
|
|
50
|
-
return `${baseClasses} ${variantClass()}`.trim();
|
|
61
|
+
return `${baseClasses} ${variantClass()} ${className}`.trim();
|
|
51
62
|
});
|
|
52
63
|
|
|
53
64
|
const labelClasses = $derived(
|
|
54
|
-
() =>
|
|
65
|
+
() => 'mb-1 block text-sm font-medium text-label',
|
|
55
66
|
);
|
|
56
67
|
|
|
57
68
|
const messageClasses = $derived(() => {
|
|
58
|
-
if (variant ===
|
|
59
|
-
return
|
|
60
|
-
} else if (variant ===
|
|
61
|
-
return
|
|
62
|
-
} else if (variant ===
|
|
63
|
-
return
|
|
69
|
+
if (variant === 'error') {
|
|
70
|
+
return 'mt-1 flex items-center gap-1.5 text-sm text-error';
|
|
71
|
+
} else if (variant === 'success') {
|
|
72
|
+
return 'mt-1 flex items-center gap-1.5 text-sm text-success';
|
|
73
|
+
} else if (variant === 'warning') {
|
|
74
|
+
return 'mt-1 flex items-center gap-1.5 text-sm text-warning';
|
|
64
75
|
}
|
|
65
|
-
return
|
|
76
|
+
return 'mt-1 flex items-center gap-1.5 text-sm text-description';
|
|
66
77
|
});
|
|
67
78
|
|
|
68
79
|
const getIcon = $derived(() => {
|
|
69
|
-
if (variant ===
|
|
70
|
-
if (variant ===
|
|
71
|
-
if (variant ===
|
|
80
|
+
if (variant === 'error') return AlertCircle;
|
|
81
|
+
if (variant === 'success') return CheckCircle;
|
|
82
|
+
if (variant === 'warning') return AlertTriangle;
|
|
72
83
|
return null;
|
|
73
84
|
});
|
|
74
85
|
|
|
75
86
|
function handleInput(event: Event) {
|
|
76
87
|
const target = event.target as HTMLTextAreaElement;
|
|
77
88
|
value = target.value;
|
|
78
|
-
|
|
79
|
-
if (oninput) {
|
|
80
|
-
oninput(event);
|
|
81
|
-
}
|
|
89
|
+
oninput?.(event);
|
|
82
90
|
}
|
|
83
91
|
</script>
|
|
84
92
|
|
|
85
93
|
<div>
|
|
86
|
-
{#if label}
|
|
94
|
+
{#if label && !hideLabel}
|
|
87
95
|
<label for={textareaId} class={labelClasses()}>{label}</label>
|
|
88
96
|
{/if}
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
<div class="relative">
|
|
98
|
+
<textarea
|
|
99
|
+
id={textareaId}
|
|
100
|
+
{name}
|
|
101
|
+
bind:value
|
|
102
|
+
{placeholder}
|
|
103
|
+
{required}
|
|
104
|
+
disabled={isDisabled}
|
|
105
|
+
{rows}
|
|
106
|
+
class={textareaClasses()}
|
|
107
|
+
oninput={handleInput}
|
|
108
|
+
aria-invalid={variant === 'error' ? 'true' : undefined}
|
|
109
|
+
aria-required={required ? 'true' : undefined}
|
|
110
|
+
aria-busy={loading ? 'true' : undefined}
|
|
111
|
+
aria-describedby={message ? `${textareaId}-message` : undefined}
|
|
112
|
+
{...restProps}
|
|
113
|
+
></textarea>
|
|
114
|
+
{#if loading}
|
|
115
|
+
<span
|
|
116
|
+
class="pointer-events-none absolute top-3 right-3 flex items-center text-description"
|
|
117
|
+
aria-hidden="true"
|
|
118
|
+
>
|
|
119
|
+
<span
|
|
120
|
+
class="inline-block size-5 shrink-0 animate-spin rounded-full border-2 border-current border-t-transparent opacity-70"
|
|
121
|
+
></span>
|
|
122
|
+
</span>
|
|
123
|
+
{/if}
|
|
124
|
+
</div>
|
|
125
|
+
{#if message && variant !== 'default'}
|
|
105
126
|
<p
|
|
106
127
|
id={`${textareaId}-message`}
|
|
107
128
|
class={messageClasses()}
|
|
108
|
-
role={variant ===
|
|
109
|
-
aria-live={variant ===
|
|
129
|
+
role={variant === 'error' ? 'alert' : 'status'}
|
|
130
|
+
aria-live={variant === 'error' ? 'assertive' : 'polite'}
|
|
110
131
|
>
|
|
111
132
|
{#if getIcon()}
|
|
112
133
|
{@const Icon = getIcon()}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import type { SemanticVariant, SizeVariant } from
|
|
1
|
+
import type { SemanticVariant, SizeVariant } from '../types/variants.js';
|
|
2
2
|
interface Props {
|
|
3
|
+
id?: string;
|
|
3
4
|
value?: string;
|
|
4
5
|
name?: string;
|
|
6
|
+
class?: string;
|
|
5
7
|
label?: string;
|
|
8
|
+
hideLabel?: boolean;
|
|
6
9
|
placeholder?: string;
|
|
7
10
|
required?: boolean;
|
|
8
11
|
disabled?: boolean;
|
|
12
|
+
loading?: boolean;
|
|
9
13
|
rows?: number;
|
|
10
14
|
size?: SizeVariant;
|
|
11
15
|
variant?: SemanticVariant;
|
|
12
16
|
message?: string;
|
|
13
17
|
oninput?: (event: Event) => void;
|
|
14
18
|
}
|
|
15
|
-
declare const Textarea: import("svelte").Component<Props, {}, "">;
|
|
19
|
+
declare const Textarea: import("svelte").Component<Props, {}, "value">;
|
|
16
20
|
type Textarea = ReturnType<typeof Textarea>;
|
|
17
21
|
export default Textarea;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { onMount } from "svelte";
|
|
3
3
|
import { Sun, Moon } from "@lucide/svelte";
|
|
4
|
+
import { FOCUS_BRAND_CLASS } from "../util/focus-utils.js";
|
|
4
5
|
|
|
5
6
|
function safeLocalStorage(): Storage | undefined {
|
|
6
7
|
return typeof window !== "undefined" ? localStorage : undefined;
|
|
@@ -13,13 +14,15 @@
|
|
|
13
14
|
interface Props {
|
|
14
15
|
size?: "sm" | "md" | "lg";
|
|
15
16
|
variant?: "default" | "ghost" | "outline";
|
|
17
|
+
disabled?: boolean;
|
|
16
18
|
onclick?: (event: Event) => void;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
let {
|
|
21
|
+
let {
|
|
20
22
|
size = "md",
|
|
21
23
|
variant = "default",
|
|
22
|
-
|
|
24
|
+
disabled = false,
|
|
25
|
+
...restProps
|
|
23
26
|
}: Props = $props();
|
|
24
27
|
|
|
25
28
|
let isDark = $state(false);
|
|
@@ -27,25 +30,27 @@
|
|
|
27
30
|
|
|
28
31
|
onMount(() => {
|
|
29
32
|
mounted = true;
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const doc = safeDocument();
|
|
34
|
+
if (doc) {
|
|
35
|
+
isDark = doc.documentElement.classList.contains("dark");
|
|
36
|
+
}
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
38
|
-
} catch (e) {
|
|
39
|
-
prefersDark = false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
38
|
+
if (!window.matchMedia) return;
|
|
42
39
|
|
|
43
|
-
|
|
40
|
+
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
41
|
+
const handleSystemChange = (event: MediaQueryListEvent) => {
|
|
42
|
+
const storage = safeLocalStorage();
|
|
43
|
+
if (storage && storage.getItem("theme")) return;
|
|
44
|
+
isDark = event.matches;
|
|
44
45
|
updateTheme();
|
|
45
|
-
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
media.addEventListener("change", handleSystemChange);
|
|
49
|
+
return () => media.removeEventListener("change", handleSystemChange);
|
|
46
50
|
});
|
|
47
51
|
|
|
48
52
|
function toggleTheme(event: Event) {
|
|
53
|
+
if (disabled) return;
|
|
49
54
|
isDark = !isDark;
|
|
50
55
|
updateTheme();
|
|
51
56
|
const storage = safeLocalStorage();
|
|
@@ -63,8 +68,10 @@
|
|
|
63
68
|
if (mounted && doc) {
|
|
64
69
|
if (isDark) {
|
|
65
70
|
doc.documentElement.classList.add("dark");
|
|
71
|
+
doc.documentElement.style.colorScheme = "dark";
|
|
66
72
|
} else {
|
|
67
73
|
doc.documentElement.classList.remove("dark");
|
|
74
|
+
doc.documentElement.style.colorScheme = "light";
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
77
|
}
|
|
@@ -90,11 +97,11 @@
|
|
|
90
97
|
|
|
91
98
|
const variantClass = $derived(() => {
|
|
92
99
|
if (variant === "ghost") {
|
|
93
|
-
return "bg-transparent hover:bg-base-100 border-0";
|
|
100
|
+
return "bg-transparent hover:bg-base-100 active:bg-base-200 border-0";
|
|
94
101
|
} else if (variant === "outline") {
|
|
95
|
-
return "bg-base-50 hover:bg-base-100 border border-border";
|
|
102
|
+
return "bg-base-50 hover:bg-base-100 active:bg-base-200 border border-border";
|
|
96
103
|
} else {
|
|
97
|
-
return "bg-base-50 hover:bg-base-100 border-0";
|
|
104
|
+
return "bg-base-50 hover:bg-base-100 active:bg-base-200 border-0";
|
|
98
105
|
}
|
|
99
106
|
});
|
|
100
107
|
|
|
@@ -111,11 +118,12 @@
|
|
|
111
118
|
cursor-pointer
|
|
112
119
|
transition-colors
|
|
113
120
|
duration-200
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
active:scale-[0.96]
|
|
122
|
+
disabled:opacity-50
|
|
123
|
+
disabled:cursor-not-allowed
|
|
124
|
+
disabled:active:scale-100
|
|
125
|
+
disabled:hover:bg-base-50
|
|
126
|
+
${FOCUS_BRAND_CLASS}
|
|
119
127
|
`.trim().replace(/\s+/g, " ");
|
|
120
128
|
});
|
|
121
129
|
</script>
|
|
@@ -125,7 +133,9 @@
|
|
|
125
133
|
onclick={toggleTheme}
|
|
126
134
|
class={buttonClasses()}
|
|
127
135
|
aria-label={isDark ? "Switch to light mode" : "Switch to dark mode"}
|
|
136
|
+
aria-pressed={isDark}
|
|
128
137
|
type="button"
|
|
138
|
+
{disabled}
|
|
129
139
|
{...restProps}
|
|
130
140
|
>
|
|
131
141
|
{#if isDark}
|
|
@@ -136,9 +146,10 @@
|
|
|
136
146
|
</button>
|
|
137
147
|
{:else}
|
|
138
148
|
<button
|
|
139
|
-
class="w-10 h-10 bg-base-50 rounded-lg flex items-center justify-center text-label cursor-pointer"
|
|
149
|
+
class="w-10 h-10 bg-base-50 rounded-lg flex items-center justify-center text-label cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed"
|
|
140
150
|
aria-label="Theme toggle"
|
|
141
151
|
type="button"
|
|
152
|
+
{disabled}
|
|
142
153
|
{...restProps}
|
|
143
154
|
>
|
|
144
155
|
<Sun size={20} class="text-label" />
|
package/dist/atoms/Toast.svelte
CHANGED
|
@@ -1,57 +1,81 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
interface Props {
|
|
3
3
|
message?: string;
|
|
4
|
-
type?:
|
|
4
|
+
type?: 'success' | 'error' | 'warning' | 'info';
|
|
5
5
|
closable?: boolean;
|
|
6
6
|
onclick?: (event: Event) => void;
|
|
7
|
+
class?: string;
|
|
8
|
+
/** `viewport`: fixed corner; `inline`: block in flow (e.g. demos). */
|
|
9
|
+
layout?: 'viewport' | 'inline';
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
let {
|
|
10
|
-
message =
|
|
11
|
-
type =
|
|
13
|
+
message = '',
|
|
14
|
+
type = 'info',
|
|
12
15
|
closable = true,
|
|
13
16
|
onclick,
|
|
17
|
+
class: className = '',
|
|
18
|
+
layout = 'viewport',
|
|
14
19
|
...restProps
|
|
15
20
|
}: Props = $props();
|
|
16
21
|
|
|
17
22
|
let isVisible = $state(true);
|
|
18
23
|
|
|
19
|
-
const typeClasses = {
|
|
20
|
-
success:
|
|
21
|
-
error:
|
|
22
|
-
warning:
|
|
23
|
-
info:
|
|
24
|
+
const typeClasses: Record<NonNullable<Props['type']>, string> = {
|
|
25
|
+
success: 'border-success bg-card text-success',
|
|
26
|
+
error: 'border-error bg-card text-error',
|
|
27
|
+
warning: 'border-warning bg-card text-warning',
|
|
28
|
+
info: 'border-border bg-card text-body',
|
|
24
29
|
};
|
|
25
30
|
|
|
31
|
+
const cardClasses =
|
|
32
|
+
'box-border w-full min-w-[18rem] max-w-[min(24rem,calc(100vw-2rem))] overflow-hidden rounded-lg border p-4 shadow-lg';
|
|
33
|
+
|
|
26
34
|
function closeToast(event: Event) {
|
|
27
35
|
isVisible = false;
|
|
28
|
-
|
|
29
|
-
onclick(event);
|
|
30
|
-
}
|
|
36
|
+
onclick?.(event);
|
|
31
37
|
}
|
|
32
38
|
</script>
|
|
33
39
|
|
|
40
|
+
{#snippet toastBody()}
|
|
41
|
+
<div class="flex min-w-0 items-start gap-3">
|
|
42
|
+
<div class="min-w-0 max-w-full flex-1 basis-0">
|
|
43
|
+
<p class="text-sm break-words [overflow-wrap:anywhere]">{message}</p>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
{#if closable}
|
|
47
|
+
<button
|
|
48
|
+
type="button"
|
|
49
|
+
class="focus-ring shrink-0 cursor-pointer rounded-md text-description hover:text-headline focus:outline-none"
|
|
50
|
+
onclick={closeToast}
|
|
51
|
+
aria-label="Close notification"
|
|
52
|
+
>
|
|
53
|
+
×
|
|
54
|
+
</button>
|
|
55
|
+
{/if}
|
|
56
|
+
</div>
|
|
57
|
+
{/snippet}
|
|
58
|
+
|
|
34
59
|
{#if isVisible}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
60
|
+
{#if layout === 'viewport'}
|
|
61
|
+
<div
|
|
62
|
+
class="pointer-events-none fixed top-4 right-4 left-4 z-toast flex justify-end sm:left-auto"
|
|
63
|
+
>
|
|
64
|
+
<div
|
|
65
|
+
class="pointer-events-auto {cardClasses} {typeClasses[type]} {className}"
|
|
66
|
+
role="alert"
|
|
67
|
+
{...restProps}
|
|
68
|
+
>
|
|
69
|
+
{@render toastBody()}
|
|
43
70
|
</div>
|
|
44
|
-
|
|
45
|
-
{#if closable}
|
|
46
|
-
<button
|
|
47
|
-
type="button"
|
|
48
|
-
class="ml-3 text-base-400 hover:text-base-600"
|
|
49
|
-
onclick={closeToast}
|
|
50
|
-
aria-label="Close notification"
|
|
51
|
-
>
|
|
52
|
-
×
|
|
53
|
-
</button>
|
|
54
|
-
{/if}
|
|
55
71
|
</div>
|
|
56
|
-
|
|
72
|
+
{:else}
|
|
73
|
+
<div
|
|
74
|
+
class="relative z-toast mx-auto {cardClasses} {typeClasses[type]} {className}"
|
|
75
|
+
role="alert"
|
|
76
|
+
{...restProps}
|
|
77
|
+
>
|
|
78
|
+
{@render toastBody()}
|
|
79
|
+
</div>
|
|
80
|
+
{/if}
|
|
57
81
|
{/if}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
interface Props {
|
|
2
2
|
message?: string;
|
|
3
|
-
type?:
|
|
3
|
+
type?: 'success' | 'error' | 'warning' | 'info';
|
|
4
4
|
closable?: boolean;
|
|
5
5
|
onclick?: (event: Event) => void;
|
|
6
|
+
class?: string;
|
|
7
|
+
/** `viewport`: fixed corner; `inline`: block in flow (e.g. demos). */
|
|
8
|
+
layout?: 'viewport' | 'inline';
|
|
6
9
|
}
|
|
7
10
|
declare const Toast: import("svelte").Component<Props, {}, "">;
|
|
8
11
|
type Toast = ReturnType<typeof Toast>;
|
package/dist/atoms/Toggle.svelte
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { generateId } from "
|
|
2
|
+
import { generateId } from "../util/ssr-safe.js";
|
|
3
3
|
|
|
4
4
|
interface Props {
|
|
5
5
|
checked?: boolean;
|
|
6
6
|
disabled?: boolean;
|
|
7
|
+
loading?: boolean;
|
|
7
8
|
label?: string;
|
|
8
9
|
onclick?: (event: MouseEvent) => void;
|
|
9
10
|
onchange?: (event: { checked: boolean }) => void;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
let {
|
|
13
|
-
checked = false,
|
|
14
|
+
checked = $bindable(false),
|
|
14
15
|
disabled = false,
|
|
16
|
+
loading = false,
|
|
15
17
|
label = "",
|
|
16
18
|
onclick,
|
|
17
19
|
onchange,
|
|
@@ -19,38 +21,40 @@
|
|
|
19
21
|
}: Props = $props();
|
|
20
22
|
|
|
21
23
|
const toggleId = generateId("toggle");
|
|
24
|
+
const isDisabled = $derived(disabled || loading);
|
|
22
25
|
|
|
23
26
|
function handleClick(event: MouseEvent) {
|
|
24
|
-
if (
|
|
27
|
+
if (isDisabled) return;
|
|
25
28
|
checked = !checked;
|
|
26
29
|
|
|
27
30
|
if (onclick) onclick(event);
|
|
28
31
|
if (onchange) onchange({ checked });
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
const toggleButtonClasses = $derived(() =>
|
|
32
|
-
|
|
33
|
-
"relative inline-flex w-10 h-6 flex-shrink-0
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const toggleButtonClasses = $derived(() => {
|
|
35
|
+
const base =
|
|
36
|
+
"focus-ring relative inline-flex w-10 h-6 flex-shrink-0 rounded-full border-0 transition-colors duration-200 ease-in-out focus:outline-none focus-visible:outline-none";
|
|
37
|
+
const colorClass = checked
|
|
38
|
+
? "bg-action-primary hover:bg-action-primary-hover active:bg-action-primary-active"
|
|
39
|
+
: "bg-base-400 hover:bg-base-500 active:bg-base-500";
|
|
40
|
+
const stateClass = isDisabled
|
|
41
|
+
? "opacity-50 cursor-not-allowed"
|
|
42
|
+
: "cursor-pointer";
|
|
43
|
+
return `${base} ${colorClass} ${stateClass}`;
|
|
44
|
+
});
|
|
40
45
|
|
|
41
46
|
const toggleThumbClasses = $derived(() => {
|
|
42
|
-
const
|
|
43
|
-
"pointer-events-none absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-card transition-transform duration-200 ease-in-out";
|
|
47
|
+
const base =
|
|
48
|
+
"pointer-events-none absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-card shadow transition-transform duration-200 ease-in-out flex items-center justify-center";
|
|
44
49
|
const positionClasses = checked ? "translate-x-4" : "translate-x-0";
|
|
45
|
-
|
|
46
|
-
return `${baseClasses} ${positionClasses}`.trim();
|
|
50
|
+
return `${base} ${positionClasses}`;
|
|
47
51
|
});
|
|
48
52
|
|
|
49
53
|
function handleKeydown(event: KeyboardEvent) {
|
|
50
|
-
if (
|
|
54
|
+
if (isDisabled) return;
|
|
51
55
|
if (event.key === " " || event.key === "Enter") {
|
|
52
56
|
event.preventDefault();
|
|
53
|
-
handleClick(event as
|
|
57
|
+
handleClick(event as unknown as MouseEvent);
|
|
54
58
|
}
|
|
55
59
|
}
|
|
56
60
|
</script>
|
|
@@ -61,19 +65,30 @@
|
|
|
61
65
|
role="switch"
|
|
62
66
|
id={toggleId}
|
|
63
67
|
aria-checked={checked}
|
|
64
|
-
aria-label={label
|
|
65
|
-
{
|
|
68
|
+
aria-label={label ? undefined : "Toggle"}
|
|
69
|
+
aria-busy={loading ? "true" : undefined}
|
|
70
|
+
disabled={isDisabled}
|
|
66
71
|
onclick={handleClick}
|
|
67
72
|
onkeydown={handleKeydown}
|
|
68
73
|
class={toggleButtonClasses()}
|
|
74
|
+
{...restProps}
|
|
69
75
|
>
|
|
70
|
-
<span class={toggleThumbClasses()}
|
|
76
|
+
<span class={toggleThumbClasses()}>
|
|
77
|
+
{#if loading}
|
|
78
|
+
<span
|
|
79
|
+
class="inline-block size-3 shrink-0 animate-spin rounded-full border-2 border-brand-500 border-t-transparent"
|
|
80
|
+
aria-hidden="true"
|
|
81
|
+
></span>
|
|
82
|
+
{/if}
|
|
83
|
+
</span>
|
|
71
84
|
</button>
|
|
72
85
|
|
|
73
86
|
{#if label}
|
|
74
87
|
<label
|
|
75
88
|
for={toggleId}
|
|
76
|
-
class="text-sm font-medium text-label
|
|
89
|
+
class="text-sm font-medium text-label {isDisabled
|
|
90
|
+
? 'cursor-not-allowed opacity-50'
|
|
91
|
+
: 'cursor-pointer'}"
|
|
77
92
|
>
|
|
78
93
|
{label}
|
|
79
94
|
</label>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
interface Props {
|
|
2
2
|
checked?: boolean;
|
|
3
3
|
disabled?: boolean;
|
|
4
|
+
loading?: boolean;
|
|
4
5
|
label?: string;
|
|
5
6
|
onclick?: (event: MouseEvent) => void;
|
|
6
7
|
onchange?: (event: {
|
|
7
8
|
checked: boolean;
|
|
8
9
|
}) => void;
|
|
9
10
|
}
|
|
10
|
-
declare const Toggle: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
declare const Toggle: import("svelte").Component<Props, {}, "checked">;
|
|
11
12
|
type Toggle = ReturnType<typeof Toggle>;
|
|
12
13
|
export default Toggle;
|