zabi-components 5.0.5 → 5.0.7

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.
@@ -35,14 +35,14 @@
35
35
  // Variant classes - using semantic color system
36
36
  const variantClass =
37
37
  variant === "success"
38
- ? "bg-surface-secondary border-secondary text-success"
38
+ ? "bg-surface-level-1 border-secondary text-success"
39
39
  : variant === "warning"
40
- ? "bg-surface-secondary border-secondary text-warning"
40
+ ? "bg-surface-level-1 border-secondary text-warning"
41
41
  : variant === "error"
42
- ? "bg-surface-secondary border-secondary text-error"
42
+ ? "bg-surface-level-1 border-secondary text-error"
43
43
  : variant === "info"
44
- ? "bg-surface-secondary border-secondary text-body"
45
- : "bg-surface-secondary border-secondary text-body"; // default
44
+ ? "bg-surface-level-1 border-secondary text-body"
45
+ : "bg-surface-level-1 border-secondary text-body"; // default
46
46
 
47
47
  return `${baseClasses} ${sizeClass} ${variantClass}`.trim();
48
48
  });
@@ -2,13 +2,7 @@
2
2
  import type { Snippet } from "svelte";
3
3
 
4
4
  interface Props {
5
- variant?:
6
- | "primary"
7
- | "secondary"
8
- | "danger"
9
- | "success"
10
- | "ghost"
11
- | "brand";
5
+ variant?: "primary" | "secondary" | "danger" | "ghost";
12
6
  size?: "sm" | "md" | "lg";
13
7
  disabled?: boolean;
14
8
  type?: "button" | "submit" | "reset";
@@ -37,27 +31,23 @@
37
31
  : "px-4 py-2 text-sm font-medium"; // default md
38
32
  });
39
33
 
40
- // Variant classes using full class names in conditionals
34
+ // Variant classes using semantic action colors
41
35
  const variantClass = $derived(() => {
42
36
  return variant === "primary"
43
- ? "bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-blue-400"
37
+ ? "bg-action-primary text-inverse focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
44
38
  : variant === "secondary"
45
- ? "bg-gray-600 text-white hover:bg-gray-700 active:bg-gray-800 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:bg-gray-400"
39
+ ? "border border-secondary text-description hover:border-secondary-hover focus:ring-2 focus:ring-stone-500 focus:ring-offset-2"
46
40
  : variant === "danger"
47
- ? "bg-red-600 text-white hover:bg-red-700 active:bg-red-800 focus:ring-2 focus:ring-red-500 focus:ring-offset-2 disabled:bg-red-400"
48
- : variant === "success"
49
- ? "bg-green-600 text-white hover:bg-green-700 active:bg-green-800 focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:bg-green-400"
50
- : variant === "ghost"
51
- ? "bg-transparent text-gray-700 hover:bg-gray-100 active:bg-gray-200 focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 disabled:text-gray-400"
52
- : variant === "brand"
53
- ? "bg-purple-600 text-white hover:bg-purple-700 active:bg-purple-800 focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 disabled:bg-purple-400"
54
- : "bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-blue-400"; // default primary
41
+ ? "bg-action-danger text-inverse focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
42
+ : variant === "ghost"
43
+ ? "bg-transparent text-headline hover:bg-surface-hover active:bg-surface-active focus:ring-2 focus:ring-stone-500 focus:ring-offset-2 disabled:text-disabled"
44
+ : "bg-action-primary text-inverse focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"; // default primary
55
45
  });
56
46
 
57
47
  // Button classes using Badge pattern
58
48
  const buttonClasses = $derived(() => {
59
49
  const baseClasses =
60
- "inline-flex items-center justify-center rounded-md transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none focus:outline-none focus:ring-2 focus:ring-offset-2 active:scale-95 transform-gpu shadow-sm hover:shadow-md";
50
+ "inline-flex items-center justify-center rounded-md transition-all duration-200 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none focus:outline-none focus:ring-2 focus:ring-offset-2 active:scale-95 transform-gpu";
61
51
 
62
52
  return `${baseClasses} ${sizeClass()} ${variantClass()}`.trim();
63
53
  });
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from "svelte";
2
2
  interface Props {
3
- variant?: "primary" | "secondary" | "danger" | "success" | "ghost" | "brand";
3
+ variant?: "primary" | "secondary" | "danger" | "ghost";
4
4
  size?: "sm" | "md" | "lg";
5
5
  disabled?: boolean;
6
6
  type?: "button" | "submit" | "reset";
@@ -26,9 +26,9 @@
26
26
 
27
27
  const cardClasses = $derived(() => {
28
28
  const baseClasses =
29
- "bg-surface rounded-lg transition-all duration-200 hover:shadow-adaptive-md min-w-64";
29
+ "rounded-lg transition-all duration-200 min-w-64 bg-surface-level-0";
30
30
  const interactiveClasses = onclick
31
- ? "cursor-pointer hover:bg-surface-hover hover:border-focus"
31
+ ? "cursor-pointer hover:shadow-adaptive-md hover:bg-surface-hover hover:border-focus"
32
32
  : "";
33
33
  const widthClasses = fullWidth ? "w-full" : "";
34
34
 
@@ -12,31 +12,21 @@
12
12
  value?: string;
13
13
  label?: string;
14
14
  disabled?: boolean;
15
- onclick?: (event: Event) => void;
15
+ placeholder?: string;
16
+ onchange?: (event: Event) => void;
16
17
  }
17
18
 
18
19
  let {
19
20
  value = "",
20
21
  label = "",
21
22
  disabled = false,
22
- onclick,
23
+ placeholder = "#000000",
24
+ onchange,
23
25
  ...restProps
24
26
  }: Props = $props();
25
27
 
26
- const colors = [
27
- { label: "Red", value: "#ef4444" },
28
- { label: "Blue", value: "#3b82f6" },
29
- { label: "Green", value: "#10b981" },
30
- { label: "Yellow", value: "#f59e0b" },
31
- { label: "Purple", value: "#8b5cf6" },
32
- { label: "Pink", value: "#ec4899" },
33
- { label: "Gray", value: "#6b7280" },
34
- { label: "Black", value: "#000000" },
35
- ];
36
-
37
- // Generate unique IDs - SSR safe (call directly, not in onMount)
38
- const groupId = generateId("color-picker");
39
- const inputId = generateId("color-input");
28
+ // Generate unique ID - SSR safe
29
+ const inputId = generateId("color-picker");
40
30
 
41
31
  // Hex color validation
42
32
  function isValidHex(hex: string): boolean {
@@ -51,7 +41,7 @@
51
41
 
52
42
  if (hexValue === "" || isValidHex(hexValue)) {
53
43
  value = hexValue;
54
- if (onclick) onclick(event);
44
+ if (onchange) onchange(event);
55
45
  }
56
46
  }
57
47
 
@@ -75,20 +65,6 @@
75
65
  }
76
66
  }
77
67
 
78
- // Color button classes using full class names
79
- const colorButtonClasses = $derived(() => {
80
- return (colorValue: string) => {
81
- const baseClasses =
82
- "w-10 h-10 sm:w-12 sm:h-12 rounded-lg border-2 transition-all";
83
- const stateClasses =
84
- value === colorValue
85
- ? "border-blue-500 ring-2 ring-blue-200"
86
- : "border-gray-300 hover:border-gray-400";
87
-
88
- return `${baseClasses} ${stateClasses}`.trim();
89
- };
90
- });
91
-
92
68
  // Input classes
93
69
  const inputClasses = $derived(() => {
94
70
  const baseClasses =
@@ -102,70 +78,37 @@
102
78
  });
103
79
  </script>
104
80
 
105
- <div class="space-y-3 sm:space-y-4">
81
+ <div class="space-y-2" {...restProps}>
106
82
  {#if label}
107
- <label for={groupId} class="block text-sm font-medium text-label"
108
- >{label}</label
109
- >
83
+ <label for={inputId} class="block text-sm font-medium text-label">
84
+ {label}
85
+ </label>
110
86
  {/if}
111
87
 
112
- <!-- Predefined Colors -->
113
- <div
114
- id={groupId}
115
- class="grid grid-cols-4 sm:grid-cols-4 md:grid-cols-4 lg:grid-cols-4 gap-2 sm:gap-3"
116
- role="radiogroup"
117
- {...restProps}
118
- >
119
- {#each colors as color}
120
- <button
121
- type="button"
122
- class={colorButtonClasses()(color.value)}
123
- style="background-color: {color.value};"
124
- onclick={(e) => {
125
- value = color.value;
126
- if (onclick) onclick(e);
127
- }}
128
- {disabled}
129
- role="radio"
130
- aria-checked={value === color.value}
131
- aria-label={color.label}
132
- >
133
- {#if value === color.value}
134
- <span class="text-white text-lg">✓</span>
135
- {/if}
136
- </button>
137
- {/each}
138
- </div>
139
-
140
- <!-- Custom Hex Input -->
141
- <div class="space-y-1">
142
- <label for={inputId} class="block text-xs font-medium text-label">
143
- Or enter custom color
144
- </label>
145
- <div class="flex items-center space-x-2">
146
- <input
147
- id={inputId}
148
- type="text"
149
- placeholder="#000000"
150
- {value}
151
- oninput={handleHexInput}
152
- onblur={handleHexBlur}
153
- {disabled}
154
- class={inputClasses()}
155
- aria-label="Custom hex color input"
156
- />
157
- {#if value && isValidHex(value)}
158
- <div
159
- class="w-6 h-6 sm:w-8 sm:h-8 rounded border-2 border-gray-300 shrink-0"
160
- style="background-color: {value};"
161
- aria-label="Color preview"
162
- ></div>
163
- {/if}
164
- </div>
165
- {#if value && !isValidHex(value)}
166
- <p class="text-xs text-red-500">
167
- Please enter a valid hex color (e.g., #ff0000)
168
- </p>
88
+ <div class="flex items-center space-x-2">
89
+ <input
90
+ id={inputId}
91
+ type="text"
92
+ {placeholder}
93
+ {value}
94
+ oninput={handleHexInput}
95
+ onblur={handleHexBlur}
96
+ {disabled}
97
+ class={inputClasses()}
98
+ aria-label="Hex color input"
99
+ />
100
+ {#if value && isValidHex(value)}
101
+ <div
102
+ class="w-8 h-8 rounded border-2 border-gray-300 shrink-0"
103
+ style="background-color: {value};"
104
+ aria-label="Color preview"
105
+ ></div>
169
106
  {/if}
170
107
  </div>
108
+
109
+ {#if value && !isValidHex(value)}
110
+ <p class="text-xs text-red-500">
111
+ Please enter a valid hex color (e.g., #ff0000 or #f00)
112
+ </p>
113
+ {/if}
171
114
  </div>
@@ -2,7 +2,8 @@ interface Props {
2
2
  value?: string;
3
3
  label?: string;
4
4
  disabled?: boolean;
5
- onclick?: (event: Event) => void;
5
+ placeholder?: string;
6
+ onchange?: (event: Event) => void;
6
7
  }
7
8
  declare const ColorPicker: import("svelte").Component<Props, {}, "">;
8
9
  type ColorPicker = ReturnType<typeof ColorPicker>;
@@ -34,7 +34,7 @@
34
34
 
35
35
  {#if mounted}
36
36
  <div
37
- class="p-6 rounded-lg bg-surface border border-border hover:border-primary/20 hover:shadow-sm transition-colors duration-200 {className}"
37
+ class="p-6 rounded-lg bg-surface-level-0 border border-border hover:border-primary/20 hover:shadow-sm transition-colors duration-200 {className}"
38
38
  {...restProps}
39
39
  >
40
40
  <div class="flex items-start gap-4">
@@ -1,5 +1,40 @@
1
1
  <script lang="ts">
2
- let { level = 1, text }: { level?: number; text: string } = $props();
2
+ interface Props {
3
+ level?: number;
4
+ text: string;
5
+ }
6
+
7
+ let { level = 1, text }: Props = $props();
8
+
9
+ // Automatic weight and size based on heading level
10
+ const fontWeight = $derived(level <= 2 ? "700" : "500");
11
+ const Tag = $derived(`h${level}`);
12
+
13
+ // Size classes for different heading levels
14
+ const sizeClasses = {
15
+ 1: "text-4xl",
16
+ 2: "text-3xl",
17
+ 3: "text-2xl",
18
+ 4: "text-xl",
19
+ 5: "text-lg",
20
+ 6: "text-base",
21
+ };
22
+
23
+ const sizeClass = $derived(
24
+ sizeClasses[level as keyof typeof sizeClasses] || "text-base",
25
+ );
3
26
  </script>
4
27
 
5
- <div class="text-headline" role="heading" aria-level={level}>{text}</div>
28
+ <svelte:element
29
+ this={Tag}
30
+ class="text-headline font-nunito {sizeClass}"
31
+ style="font-weight: {fontWeight};"
32
+ >
33
+ {text}
34
+ </svelte:element>
35
+
36
+ <style>
37
+ .font-nunito {
38
+ font-family: "Nunito Sans", ui-sans-serif, system-ui, sans-serif;
39
+ }
40
+ </style>
@@ -1,7 +1,7 @@
1
- type $$ComponentProps = {
1
+ interface Props {
2
2
  level?: number;
3
3
  text: string;
4
- };
5
- declare const Heading: import("svelte").Component<$$ComponentProps, {}, "">;
4
+ }
5
+ declare const Heading: import("svelte").Component<Props, {}, "">;
6
6
  type Heading = ReturnType<typeof Heading>;
7
7
  export default Heading;
@@ -45,21 +45,21 @@
45
45
  : "px-4 py-2 text-sm"; // default md
46
46
  });
47
47
 
48
- // Variant classes using full class names
48
+ // Variant classes using semantic colors
49
49
  const variantClass = $derived(() => {
50
50
  return variant === "success"
51
- ? "border-green-300 focus:border-green-500 focus:ring-green-500"
51
+ ? "border-success focus:border-success focus:ring-success"
52
52
  : variant === "warning"
53
- ? "border-yellow-300 focus:border-yellow-500 focus:ring-yellow-500"
53
+ ? "border-warning focus:border-warning focus:ring-warning"
54
54
  : variant === "error"
55
- ? "border-red-300 focus:border-red-500 focus:ring-red-500"
56
- : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"; // default
55
+ ? "border-error focus:border-error focus:ring-error"
56
+ : "border-border focus:border-focus focus:ring-focus"; // default
57
57
  });
58
58
 
59
59
  // Input classes using Badge pattern
60
60
  const inputClasses = $derived(() => {
61
61
  const baseClasses =
62
- "w-full rounded-md transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-surface disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-disabled";
62
+ "w-full border rounded-md transition-colors duration-200 placeholder:text-input-placeholder focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-surface disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-disabled";
63
63
 
64
64
  return `${baseClasses} ${sizeClass()} ${variantClass()}`.trim();
65
65
  });
@@ -47,11 +47,16 @@
47
47
  // Select classes using Badge pattern
48
48
  const selectClasses = $derived(() => {
49
49
  const baseClasses =
50
- "w-full border border-gray-300 rounded-md bg-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:opacity-50 disabled:cursor-not-allowed";
50
+ "w-full border border-border rounded-md transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-surface focus:ring-focus focus:border-focus disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-disabled";
51
51
 
52
52
  return `${baseClasses} ${sizeClass()}`.trim();
53
53
  });
54
54
 
55
+ // Label classes using semantic text colors
56
+ const labelClasses = $derived(
57
+ () => "block text-sm font-medium text-label mb-1",
58
+ );
59
+
55
60
  function handleChange(event: Event) {
56
61
  const target = event.target as HTMLSelectElement;
57
62
  value = target.value;
@@ -60,9 +65,7 @@
60
65
 
61
66
  <div>
62
67
  {#if label}
63
- <label for={selectId} class="block text-sm font-medium text-label mb-1"
64
- >{label}</label
65
- >
68
+ <label for={selectId} class={labelClasses()}>{label}</label>
66
69
  {/if}
67
70
 
68
71
  <select
@@ -8,23 +8,6 @@
8
8
  }
9
9
  }
10
10
 
11
- // Input variant classes
12
- function getInputVariantClasses(
13
- variant: "default" | "success" | "warning" | "error" | "info",
14
- ): string {
15
- const variantMap = {
16
- default:
17
- "border-gray-300 focus:border-blue-500 focus:ring-blue-500",
18
- success:
19
- "border-green-300 focus:border-green-500 focus:ring-green-500",
20
- warning:
21
- "border-yellow-300 focus:border-yellow-500 focus:ring-yellow-500",
22
- error: "border-red-300 focus:border-red-500 focus:ring-red-500",
23
- info: "border-blue-300 focus:border-blue-500 focus:ring-blue-500",
24
- };
25
- return variantMap[variant] || variantMap.default;
26
- }
27
-
28
11
  interface Props {
29
12
  value?: string;
30
13
  name?: string;
@@ -62,21 +45,21 @@
62
45
  : "px-4 py-2 text-sm"; // default md
63
46
  });
64
47
 
65
- // Variant classes using full class names
48
+ // Variant classes using semantic colors
66
49
  const variantClass = $derived(() => {
67
50
  return variant === "success"
68
- ? "border-green-300 focus:border-green-500 focus:ring-green-500"
51
+ ? "border-success focus:border-success focus:ring-success"
69
52
  : variant === "warning"
70
- ? "border-yellow-300 focus:border-yellow-500 focus:ring-yellow-500"
53
+ ? "border-warning focus:border-warning focus:ring-warning"
71
54
  : variant === "error"
72
- ? "border-red-300 focus:border-red-500 focus:ring-red-500"
73
- : "border-gray-300 focus:border-blue-500 focus:ring-blue-500"; // default
55
+ ? "border-error focus:border-error focus:ring-error"
56
+ : "border-border focus:border-focus focus:ring-focus"; // default
74
57
  });
75
58
 
76
59
  // Textarea classes using Badge pattern
77
60
  const textareaClasses = $derived(() => {
78
61
  const baseClasses =
79
- "w-full rounded-md transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-surface disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-disabled resize-y";
62
+ "w-full border rounded-md transition-colors duration-200 placeholder:text-input-placeholder focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-surface disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-disabled resize-y";
80
63
 
81
64
  return `${baseClasses} ${sizeClass()} ${variantClass()}`.trim();
82
65
  });
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { onMount } from "svelte";
3
+ import { Sun, Moon } from "@lucide/svelte";
3
4
  // SSR-safe utilities
4
5
  function safeLocalStorage(): Storage | undefined {
5
6
  return typeof window !== "undefined" ? localStorage : undefined;
@@ -67,23 +68,23 @@
67
68
  {#if mounted}
68
69
  <button
69
70
  onclick={toggleTheme}
70
- class="w-10 h-10 bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-lg flex items-center justify-center text-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500"
71
+ class="w-10 h-10 bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-lg flex items-center justify-center text-gray-700 cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-500"
71
72
  aria-label={isDark ? "Switch to light mode" : "Switch to dark mode"}
72
73
  {...restProps}
73
74
  >
74
75
  {#if isDark}
75
- <span class="text-lg">☀️</span>
76
+ <Moon size={20} class="text-label" />
76
77
  {:else}
77
- <span class="text-lg">🌙</span>
78
+ <Sun size={20} class="text-label" />
78
79
  {/if}
79
80
  </button>
80
81
  {:else}
81
82
  <!-- SSR fallback -->
82
83
  <button
83
- class="w-10 h-10 bg-gray-100 border border-gray-300 rounded-lg flex items-center justify-center text-gray-700"
84
+ class="w-10 h-10 bg-gray-100 border border-gray-300 rounded-lg flex items-center justify-center text-gray-700 cursor-pointer"
84
85
  aria-label="Theme toggle"
85
86
  {...restProps}
86
87
  >
87
- <span class="text-lg">🌙</span>
88
+ <Sun size={20} class="text-label" />
88
89
  </button>
89
90
  {/if}
@@ -23,11 +23,11 @@
23
23
  </script>
24
24
 
25
25
  <div
26
- class="component-demo bg-surface border border-border rounded-lg overflow-hidden {className}"
26
+ class="component-demo bg-surface-level-0 border border-border rounded-lg overflow-hidden {className}"
27
27
  {...restProps}
28
28
  >
29
29
  <!-- Header -->
30
- <div class="px-6 py-4 border-b border-border bg-surface-secondary">
30
+ <div class="px-6 py-4 border-b border-border bg-surface-level-1">
31
31
  <div class="flex items-center justify-between">
32
32
  <div>
33
33
  <h3 class="text-lg font-semibold text-text">{title}</h3>
@@ -39,7 +39,7 @@
39
39
  </div>
40
40
  <button
41
41
  onclick={() => (showCode = !showCode)}
42
- class="flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text hover:bg-surface rounded-md transition-colors duration-200"
42
+ class="flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text hover:bg-surface-level-0 rounded-md transition-colors duration-200"
43
43
  aria-label={showCode ? "Show preview" : "Show code"}
44
44
  >
45
45
  {#if showCode}
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import Button from "../atoms/Button.svelte";
3
+ import { Image } from "@lucide/svelte";
3
4
 
4
5
  interface Props {
5
6
  value?: string | null;
@@ -53,7 +54,7 @@
53
54
  <img
54
55
  src={value}
55
56
  alt=""
56
- class="w-full h-32 object-cover rounded-lg border border-gray-300"
57
+ class="w-full h-32 object-cover rounded-lg border border-border"
57
58
  />
58
59
  <div
59
60
  class="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity rounded-lg flex items-center justify-center"
@@ -81,7 +82,7 @@
81
82
  {:else}
82
83
  <!-- Empty State -->
83
84
  <div
84
- class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center hover:border-gray-400 transition-colors cursor-pointer"
85
+ class="border-2 border-dashed border-border rounded-lg p-6 text-center hover:border-border-strong transition-colors cursor-pointer"
85
86
  onclick={triggerFileSelect}
86
87
  role="button"
87
88
  tabindex="0"
@@ -89,13 +90,15 @@
89
90
  >
90
91
  <div class="space-y-3">
91
92
  <div
92
- class="w-12 h-12 mx-auto bg-gray-100 rounded-lg flex items-center justify-center"
93
+ class="w-12 h-12 mx-auto bg-surface-level-1 rounded-lg flex items-center justify-center"
93
94
  >
94
- <span class="text-2xl">📷</span>
95
+ <Image size={24} class="text-description" />
95
96
  </div>
96
97
  <div>
97
- <p class="font-medium text-gray-900">{placeholder}</p>
98
- <p class="text-sm text-gray-500">Click to choose a file</p>
98
+ <p class="font-medium text-headline">{placeholder}</p>
99
+ <p class="text-sm text-description">
100
+ Click to choose a file
101
+ </p>
99
102
  </div>
100
103
  </div>
101
104
  </div>
@@ -1,7 +1,10 @@
1
1
  <script lang="ts">
2
+ type Size = "sm" | "md" | "lg";
3
+
2
4
  interface Props {
3
5
  isOpen?: boolean;
4
6
  title?: string;
7
+ size?: Size;
5
8
  onclick?: (event: Event) => void;
6
9
  onkeydown?: (event: Event) => void;
7
10
  }
@@ -9,6 +12,7 @@
9
12
  let {
10
13
  isOpen = false,
11
14
  title = "",
15
+ size = "md",
12
16
  onclick,
13
17
  onkeydown,
14
18
  children,
@@ -16,6 +20,14 @@
16
20
  ...restProps
17
21
  }: Props & { children?: any; footer?: any } = $props();
18
22
 
23
+ const sizeClasses = $derived(
24
+ {
25
+ sm: "w-full md:w-[24rem]",
26
+ md: "w-full md:w-[28rem]",
27
+ lg: "w-full md:w-[42rem]",
28
+ }[size] || "w-full md:w-[28rem]",
29
+ );
30
+
19
31
  function closeModal(event?: Event) {
20
32
  isOpen = false;
21
33
  if (onclick && event) {
@@ -42,7 +54,7 @@
42
54
 
43
55
  {#if isOpen}
44
56
  <div
45
- class="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50"
57
+ class="fixed inset-0 bg-black/50 flex items-end md:items-center justify-center p-0 md:p-4 z-50"
46
58
  onclick={handleBackdropClick}
47
59
  onkeydown={handleKeydown}
48
60
  role="dialog"
@@ -50,7 +62,7 @@
50
62
  tabindex="-1"
51
63
  >
52
64
  <div
53
- class="bg-white rounded-lg shadow-xl max-w-md w-full max-h-[90vh] overflow-y-auto"
65
+ class="bg-white rounded-t-2xl md:rounded-lg shadow-xl min-w-[320px] {sizeClasses} max-h-[90vh] overflow-y-auto animate-[slideUp_0.3s_ease-out] md:animate-none"
54
66
  >
55
67
  <!-- Header -->
56
68
  <div
@@ -60,7 +72,7 @@
60
72
  <button
61
73
  type="button"
62
74
  onclick={closeModal}
63
- class="text-gray-400 hover:text-gray-600 text-2xl"
75
+ class="text-gray-400 hover:text-gray-600 text-2xl cursor-pointer"
64
76
  aria-label="Close"
65
77
  >
66
78
  ×
@@ -1,6 +1,8 @@
1
+ type Size = "sm" | "md" | "lg";
1
2
  interface Props {
2
3
  isOpen?: boolean;
3
4
  title?: string;
5
+ size?: Size;
4
6
  onclick?: (event: Event) => void;
5
7
  onkeydown?: (event: Event) => void;
6
8
  }
@@ -31,7 +31,7 @@
31
31
  </script>
32
32
 
33
33
  <nav
34
- class="bg-white border-b border-gray-200 sticky top-0 z-50 {className}"
34
+ class="bg-surface-elevated border-b border-border sticky top-0 z-50 {className}"
35
35
  {...restProps}
36
36
  >
37
37
  <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@@ -81,7 +81,7 @@
81
81
  {#if isMenuOpen}
82
82
  <div class="md:hidden">
83
83
  <div
84
- class="px-2 pt-2 pb-3 space-y-1 sm:px-3 border-t border-gray-200"
84
+ class="px-2 pt-2 pb-3 space-y-1 sm:px-3 border-t border-border"
85
85
  >
86
86
  {@render nav?.()}
87
87
  <div class="pt-4">
@@ -7,13 +7,15 @@
7
7
  }>;
8
8
  currentPath?: string;
9
9
  onclick?: (event: Event) => void;
10
+ className?: string;
10
11
  }
11
12
 
12
13
  let {
13
14
  variant = "header",
14
15
  items = [],
15
16
  currentPath = "",
16
- children,
17
+ onclick,
18
+ className = "",
17
19
  ...restProps
18
20
  }: Props & { children?: any } = $props();
19
21
 
@@ -22,27 +24,37 @@
22
24
  // Navigation is now handled by the parent component
23
25
  // through event forwarding
24
26
  }
27
+
28
+ // Derived class for ul container based on variant
29
+ const ulClasses = $derived(() => {
30
+ return variant === "sidebar"
31
+ ? "flex flex-col space-y-2"
32
+ : "flex space-x-6";
33
+ });
34
+
35
+ // Function to get link classes based on active state
36
+ function getLinkClasses(itemHref: string): string {
37
+ const isActive = currentPath === itemHref;
38
+ const baseClasses = "px-3 py-2 text-sm font-medium rounded-md";
39
+
40
+ if (isActive) {
41
+ return `${baseClasses} text-body font-semibold`;
42
+ }
43
+ return `${baseClasses} text-description hover:text-body`;
44
+ }
25
45
  </script>
26
46
 
27
- <nav class="navigation navigation-{variant}" {...restProps}>
28
- <ul
29
- class="flex {variant === 'sidebar'
30
- ? 'flex-col space-y-2'
31
- : 'space-x-6'}"
32
- >
33
- {#each items as item}
34
- <li>
35
- <a
36
- href={item.href}
37
- class="px-3 py-2 text-sm font-medium rounded-md transition-colors {currentPath ===
38
- item.href
39
- ? 'bg-blue-100 text-body'
40
- : 'text-description hover:text-body hover:bg-gray-100'}"
41
- onclick={(e) => handleClick(item, e)}
42
- >
43
- {item.label}
44
- </a>
45
- </li>
46
- {/each}
47
- </ul>
48
- </nav>
47
+ <ul class="{ulClasses()} {className}" {...restProps}>
48
+ {#each items as item}
49
+ {@const linkClasses = getLinkClasses(item.href)}
50
+ <li>
51
+ <a
52
+ href={item.href}
53
+ class={linkClasses}
54
+ onclick={(e) => handleClick(item, e)}
55
+ >
56
+ {item.label}
57
+ </a>
58
+ </li>
59
+ {/each}
60
+ </ul>
@@ -6,6 +6,7 @@ interface Props {
6
6
  }>;
7
7
  currentPath?: string;
8
8
  onclick?: (event: Event) => void;
9
+ className?: string;
9
10
  }
10
11
  type $$ComponentProps = Props & {
11
12
  children?: any;
@@ -6,11 +6,18 @@
6
6
  ======================================== */
7
7
 
8
8
  @theme {
9
- /* Surface Colors - Semantic naming with stone palette */
10
- --color-surface: theme(colors.stone.50);
11
- --color-surface-secondary: theme(colors.stone.100);
12
- --color-surface-tertiary: theme(colors.stone.200);
9
+ /* Typography - Nunito Sans font family */
10
+ --font-family-sans: 'Nunito Sans', ui-sans-serif, system-ui, sans-serif;
11
+
12
+ /* Surface Colors - Level-based naming with stone palette */
13
+ --color-surface-level-0: theme(colors.stone.50);
14
+ --color-surface-level-0-hover: theme(colors.stone.100);
15
+ --color-surface-level-1: theme(colors.stone.100);
16
+ --color-surface-level-1-hover: theme(colors.stone.200);
17
+ --color-surface-level-2: theme(colors.stone.200);
18
+ --color-surface-level-2-hover: theme(colors.stone.300);
13
19
  --color-surface-elevated: theme(colors.white);
20
+ --color-surface-elevated-hover: theme(colors.stone.50);
14
21
  --color-surface-hover: theme(colors.stone.100);
15
22
  --color-surface-active: theme(colors.stone.200);
16
23
  --color-surface-inverse: theme(colors.stone.900);
@@ -22,12 +29,12 @@
22
29
  --color-background-tertiary: theme(colors.stone.100);
23
30
 
24
31
  /* Page Colors */
25
- --color-page: theme(colors.white);
26
- --color-page-secondary: theme(colors.stone.50);
32
+ --color-page: theme(colors.stone.100);
33
+ --color-page-secondary: theme(colors.stone.200);
27
34
 
28
35
  /* Card Colors */
29
36
  --color-card: theme(colors.white);
30
- --color-card-hover: theme(colors.stone.50);
37
+ --color-card-hover: theme(colors.stone.100);
31
38
  --color-card-active: theme(colors.stone.100);
32
39
  --color-card-elevated: theme(colors.white);
33
40
 
@@ -48,78 +55,76 @@
48
55
 
49
56
  /* Border Colors */
50
57
  --color-border: theme(colors.stone.200);
51
- --color-border-secondary: theme(colors.stone.300);
52
- --color-border-hover: theme(colors.stone.400);
53
- --color-border-focus: theme(colors.blue.500);
54
- --color-border-disabled: theme(colors.stone.200);
58
+ --color-border-weak: theme(colors.stone.300);
59
+ --color-border-medium: theme(colors.stone.400);
60
+ --color-border-strong: theme(colors.stone.500);
55
61
 
56
62
  /* Focus Colors */
57
63
  --color-focus: theme(colors.blue.500);
58
- --color-focus-hover: theme(colors.blue.600);
59
- --color-focus-active: theme(colors.blue.700);
60
- --color-focus-disabled: theme(colors.blue.300);
61
- --color-focus-light: theme(colors.blue.50);
62
- --color-focus-dark: theme(colors.blue.700);
63
- --color-focus-surface: theme(colors.blue.50);
64
- --color-focus-text: theme(colors.blue.700);
65
- --color-focus-ring: theme(colors.blue.500);
66
- --color-focus-ring-offset: theme(colors.white);
64
+ --color-focus-weak: theme(colors.blue.600);
65
+ --color-focus-medium: theme(colors.blue.700);
66
+ --color-focus-strong: theme(colors.blue.800);
67
67
 
68
68
  /* Primary Colors */
69
69
  --color-primary: theme(colors.blue.600);
70
- --color-primary-hover: theme(colors.blue.700);
71
- --color-primary-active: theme(colors.blue.800);
72
- --color-primary-disabled: theme(colors.blue.300);
73
- --color-primary-light: theme(colors.blue.100);
74
- --color-primary-dark: theme(colors.blue.800);
70
+ --color-primary-weak: theme(colors.blue.700);
71
+ --color-primary-medium: theme(colors.blue.800);
72
+ --color-primary-strong: theme(colors.blue.900);
75
73
 
76
74
  /* Secondary Colors */
77
75
  --color-secondary: theme(colors.stone.600);
78
- --color-secondary-hover: theme(colors.stone.700);
79
- --color-secondary-active: theme(colors.stone.800);
80
- --color-secondary-disabled: theme(colors.stone.300);
81
- --color-secondary-light: theme(colors.stone.100);
82
- --color-secondary-dark: theme(colors.stone.800);
76
+ --color-secondary-weak: theme(colors.stone.700);
77
+ --color-secondary-medium: theme(colors.stone.800);
78
+ --color-secondary-strong: theme(colors.stone.900);
83
79
 
84
80
  /* Success Colors */
85
81
  --color-success: theme(colors.green.600);
86
- --color-success-hover: theme(colors.green.700);
87
- --color-success-active: theme(colors.green.800);
88
- --color-success-disabled: theme(colors.green.300);
89
- --color-success-light: theme(colors.green.100);
90
- --color-success-dark: theme(colors.green.800);
91
- --color-success-surface: theme(colors.green.100);
92
- --color-success-text: theme(colors.green.800);
82
+ --color-success-weak: theme(colors.green.700);
83
+ --color-success-medium: theme(colors.green.800);
84
+ --color-success-strong: theme(colors.green.900);
93
85
 
94
86
  /* Warning Colors */
95
87
  --color-warning: theme(colors.yellow.600);
96
- --color-warning-hover: theme(colors.yellow.700);
97
- --color-warning-active: theme(colors.yellow.800);
98
- --color-warning-disabled: theme(colors.yellow.300);
99
- --color-warning-light: theme(colors.yellow.100);
100
- --color-warning-dark: theme(colors.yellow.800);
101
- --color-warning-surface: theme(colors.yellow.100);
102
- --color-warning-text: theme(colors.yellow.800);
88
+ --color-warning-weak: theme(colors.yellow.700);
89
+ --color-warning-medium: theme(colors.yellow.800);
90
+ --color-warning-strong: theme(colors.yellow.900);
103
91
 
104
92
  /* Error Colors */
105
93
  --color-error: theme(colors.red.600);
106
- --color-error-hover: theme(colors.red.700);
107
- --color-error-active: theme(colors.red.800);
108
- --color-error-disabled: theme(colors.red.300);
109
- --color-error-light: theme(colors.red.100);
110
- --color-error-dark: theme(colors.red.800);
111
- --color-error-surface: theme(colors.red.100);
112
- --color-error-text: theme(colors.red.800);
94
+ --color-error-weak: theme(colors.red.700);
95
+ --color-error-medium: theme(colors.red.800);
96
+ --color-error-strong: theme(colors.red.900);
113
97
 
114
98
  /* Info Colors */
115
99
  --color-info: theme(colors.blue.600);
116
- --color-info-hover: theme(colors.blue.700);
117
- --color-info-active: theme(colors.blue.800);
118
- --color-info-disabled: theme(colors.blue.300);
119
- --color-info-light: theme(colors.blue.100);
120
- --color-info-dark: theme(colors.blue.800);
121
- --color-info-surface: theme(colors.blue.100);
122
- --color-info-text: theme(colors.blue.800);
100
+ --color-info-weak: theme(colors.blue.700);
101
+ --color-info-medium: theme(colors.blue.800);
102
+ --color-info-strong: theme(colors.blue.900);
103
+
104
+ /* Action Colors - For interactive elements like buttons */
105
+ /* Primary Actions */
106
+ --color-action-primary: theme(colors.blue.600);
107
+ --color-action-primary-hover: theme(colors.blue.700);
108
+ --color-action-primary-active: theme(colors.blue.800);
109
+ --color-action-primary-disabled: theme(colors.blue.300);
110
+ --color-action-primary-subtle: theme(colors.blue.50);
111
+ --color-action-primary-subtle-hover: theme(colors.blue.100);
112
+
113
+ /* Secondary Actions */
114
+ --color-action-secondary: theme(colors.stone.600);
115
+ --color-action-secondary-hover: theme(colors.stone.700);
116
+ --color-action-secondary-active: theme(colors.stone.800);
117
+ --color-action-secondary-disabled: theme(colors.stone.300);
118
+ --color-action-secondary-subtle: theme(colors.stone.100);
119
+ --color-action-secondary-subtle-hover: theme(colors.stone.200);
120
+
121
+ /* Danger Actions */
122
+ --color-action-danger: theme(colors.red.600);
123
+ --color-action-danger-hover: theme(colors.red.700);
124
+ --color-action-danger-active: theme(colors.red.800);
125
+ --color-action-danger-disabled: theme(colors.red.300);
126
+ --color-action-danger-subtle: theme(colors.red.50);
127
+ --color-action-danger-subtle-hover: theme(colors.red.100);
123
128
 
124
129
  /* Shadow Colors */
125
130
  --shadow-color: 0 0 0;
@@ -154,15 +159,26 @@
154
159
  --z-toast: 1080;
155
160
  }
156
161
 
162
+ /* ========================================
163
+ BASE TYPOGRAPHY
164
+ ======================================== */
165
+ body {
166
+ font-family: var(--font-family-sans);
167
+ }
168
+
157
169
  /* ========================================
158
170
  DARK MODE THEME
159
171
  ======================================== */
160
172
  .dark {
161
173
  /* Surface Colors - Dark mode variants */
162
- --color-surface: theme(colors.stone.800);
163
- --color-surface-secondary: theme(colors.stone.700);
164
- --color-surface-tertiary: theme(colors.stone.600);
174
+ --color-surface-level-0: theme(colors.stone.800);
175
+ --color-surface-level-0-hover: theme(colors.stone.700);
176
+ --color-surface-level-1: theme(colors.stone.700);
177
+ --color-surface-level-1-hover: theme(colors.stone.600);
178
+ --color-surface-level-2: theme(colors.stone.600);
179
+ --color-surface-level-2-hover: theme(colors.stone.500);
165
180
  --color-surface-elevated: theme(colors.stone.800);
181
+ --color-surface-elevated-hover: theme(colors.stone.700);
166
182
  --color-surface-hover: theme(colors.stone.700);
167
183
  --color-surface-active: theme(colors.stone.600);
168
184
  --color-surface-inverse: theme(colors.stone.100);
@@ -200,78 +216,78 @@
200
216
 
201
217
  /* Border Colors */
202
218
  --color-border: theme(colors.stone.600);
203
- --color-border-secondary: theme(colors.stone.500);
204
- --color-border-hover: theme(colors.stone.400);
205
- --color-border-focus: theme(colors.blue.400);
206
- --color-border-disabled: theme(colors.stone.600);
219
+ --color-border-weak: theme(colors.stone.500);
220
+ --color-border-medium: theme(colors.stone.400);
221
+ --color-border-strong: theme(colors.stone.300);
207
222
 
208
223
  /* Focus Colors */
209
224
  --color-focus: theme(colors.blue.400);
210
- --color-focus-hover: theme(colors.blue.500);
211
- --color-focus-active: theme(colors.blue.600);
225
+ --color-focus-weak: theme(colors.blue.500);
226
+ --color-focus-medium: theme(colors.blue.600);
227
+ --color-focus-strong: theme(colors.blue.700);
212
228
  --color-focus-disabled: theme(colors.blue.600);
213
- --color-focus-light: theme(colors.blue.900);
214
- --color-focus-dark: theme(colors.blue.400);
215
- --color-focus-surface: theme(colors.blue.900);
216
- --color-focus-text: theme(colors.blue.400);
217
- --color-focus-ring: theme(colors.blue.400);
218
- --color-focus-ring-offset: theme(colors.stone.700);
219
229
 
220
230
  /* Primary Colors */
221
231
  --color-primary: theme(colors.blue.600);
222
- --color-primary-hover: theme(colors.blue.700);
223
- --color-primary-active: theme(colors.blue.800);
224
- --color-primary-disabled: theme(colors.blue.300);
225
- --color-primary-light: theme(colors.blue.100);
226
- --color-primary-dark: theme(colors.blue.800);
232
+ --color-primary-weak: theme(colors.blue.700);
233
+ --color-primary-medium: theme(colors.blue.800);
234
+ --color-primary-strong: theme(colors.blue.900);
227
235
 
228
236
  /* Secondary Colors */
229
237
  --color-secondary: theme(colors.stone.600);
230
- --color-secondary-hover: theme(colors.stone.700);
231
- --color-secondary-active: theme(colors.stone.800);
232
- --color-secondary-disabled: theme(colors.stone.300);
233
- --color-secondary-light: theme(colors.stone.100);
234
- --color-secondary-dark: theme(colors.stone.800);
238
+ --color-secondary-weak: theme(colors.stone.700);
239
+ --color-secondary-medium: theme(colors.stone.800);
240
+ --color-secondary-strong: theme(colors.stone.900);
235
241
 
236
242
  /* Success Colors */
237
243
  --color-success: theme(colors.green.600);
238
- --color-success-hover: theme(colors.green.700);
239
- --color-success-active: theme(colors.green.800);
240
- --color-success-disabled: theme(colors.green.300);
241
- --color-success-light: theme(colors.green.100);
242
- --color-success-dark: theme(colors.green.800);
243
- --color-success-surface: theme(colors.green.100);
244
- --color-success-text: theme(colors.green.800);
244
+ --color-success-weak: theme(colors.green.700);
245
+ --color-success-medium: theme(colors.green.800);
246
+ --color-success-strong: theme(colors.green.900);
245
247
 
246
248
  /* Warning Colors */
247
249
  --color-warning: theme(colors.yellow.600);
248
- --color-warning-hover: theme(colors.yellow.700);
249
- --color-warning-active: theme(colors.yellow.800);
250
- --color-warning-disabled: theme(colors.yellow.300);
251
- --color-warning-light: theme(colors.yellow.100);
252
- --color-warning-dark: theme(colors.yellow.800);
253
- --color-warning-surface: theme(colors.yellow.100);
254
- --color-warning-text: theme(colors.yellow.800);
250
+ --color-warning-weak: theme(colors.yellow.700);
251
+ --color-warning-medium: theme(colors.yellow.800);
252
+ --color-warning-strong: theme(colors.yellow.900);
255
253
 
256
254
  /* Error Colors */
257
255
  --color-error: theme(colors.red.600);
258
- --color-error-hover: theme(colors.red.700);
259
- --color-error-active: theme(colors.red.800);
260
- --color-error-disabled: theme(colors.red.300);
261
- --color-error-light: theme(colors.red.100);
262
- --color-error-dark: theme(colors.red.800);
263
- --color-error-surface: theme(colors.red.100);
264
- --color-error-text: theme(colors.red.800);
256
+ --color-error-weak: theme(colors.red.700);
257
+ --color-error-medium: theme(colors.red.800);
258
+ --color-error-strong: theme(colors.red.900);
265
259
 
266
260
  /* Info Colors */
267
261
  --color-info: theme(colors.blue.600);
268
- --color-info-hover: theme(colors.blue.700);
262
+ --color-info-weak: theme(colors.blue.700);
269
263
  --color-info-active: theme(colors.blue.800);
270
- --color-info-disabled: theme(colors.blue.300);
271
- --color-info-light: theme(colors.blue.100);
272
- --color-info-dark: theme(colors.blue.800);
273
- --color-info-surface: theme(colors.blue.100);
274
- --color-info-text: theme(colors.blue.800);
264
+ --color-info-medium: theme(colors.blue.800);
265
+ --color-info-strong: theme(colors.blue.900);
266
+
267
+ /* Action Colors - Dark mode variants */
268
+ /* Primary Actions */
269
+ --color-action-primary: theme(colors.blue.500);
270
+ --color-action-primary-hover: theme(colors.blue.600);
271
+ --color-action-primary-active: theme(colors.blue.700);
272
+ --color-action-primary-disabled: theme(colors.blue.700);
273
+ --color-action-primary-subtle: theme(colors.blue.950);
274
+ --color-action-primary-subtle-hover: theme(colors.blue.900);
275
+
276
+ /* Secondary Actions */
277
+ --color-action-secondary: theme(colors.stone.500);
278
+ --color-action-secondary-hover: theme(colors.stone.600);
279
+ --color-action-secondary-active: theme(colors.stone.700);
280
+ --color-action-secondary-disabled: theme(colors.stone.700);
281
+ --color-action-secondary-subtle: theme(colors.stone.800);
282
+ --color-action-secondary-subtle-hover: theme(colors.stone.700);
283
+
284
+ /* Danger Actions */
285
+ --color-action-danger: theme(colors.red.500);
286
+ --color-action-danger-hover: theme(colors.red.600);
287
+ --color-action-danger-active: theme(colors.red.700);
288
+ --color-action-danger-disabled: theme(colors.red.700);
289
+ --color-action-danger-subtle: theme(colors.red.950);
290
+ --color-action-danger-subtle-hover: theme(colors.red.900);
275
291
 
276
292
  /* Shadow Colors */
277
293
  --shadow-opacity: 0.3;
@@ -286,27 +302,29 @@
286
302
  ======================================== */
287
303
 
288
304
  /* Surface utilities */
289
- .bg-surface {
290
- background-color: var(--color-surface);
305
+ .bg-surface-level-0 {
306
+ background-color: var(--color-surface-level-0);
291
307
  }
292
308
 
293
- .bg-surface-secondary {
294
- background-color: var(--color-surface-secondary);
309
+ .bg-surface-level-1 {
310
+ background-color: var(--color-surface-level-1);
295
311
  }
296
312
 
297
- .bg-surface-tertiary {
298
- background-color: var(--color-surface-tertiary);
313
+ .bg-surface-level-2 {
314
+ background-color: var(--color-surface-level-2);
299
315
  }
300
316
 
301
317
  .bg-surface-elevated {
302
318
  background-color: var(--color-surface-elevated);
303
319
  }
304
320
 
305
- .bg-surface-hover:hover {
321
+ /* Global hover effects removed - components should define their own hover states */
322
+
323
+ .bg-surface-hover {
306
324
  background-color: var(--color-surface-hover);
307
325
  }
308
326
 
309
- .bg-surface-active:active {
327
+ .bg-surface-active {
310
328
  background-color: var(--color-surface-active);
311
329
  }
312
330
 
@@ -396,4 +414,90 @@
396
414
  .focus-outline {
397
415
  outline: 2px solid var(--color-focus-ring);
398
416
  outline-offset: 2px;
417
+ }
418
+
419
+ /* Action utilities - For interactive elements like buttons */
420
+ /* Primary Actions */
421
+ .bg-action-primary {
422
+ background-color: var(--color-action-primary);
423
+ }
424
+
425
+ .bg-action-primary:hover {
426
+ background-color: var(--color-action-primary-hover);
427
+ }
428
+
429
+ .bg-action-primary:active {
430
+ background-color: var(--color-action-primary-active);
431
+ }
432
+
433
+ .bg-action-primary:disabled {
434
+ background-color: var(--color-action-primary-disabled);
435
+ }
436
+
437
+ .bg-action-primary-subtle {
438
+ background-color: var(--color-action-primary-subtle);
439
+ }
440
+
441
+ .bg-action-primary-subtle:hover {
442
+ background-color: var(--color-action-primary-subtle-hover);
443
+ }
444
+
445
+ /* Secondary Actions */
446
+ .bg-action-secondary {
447
+ background-color: var(--color-action-secondary);
448
+ }
449
+
450
+ .bg-action-secondary:hover {
451
+ background-color: var(--color-action-secondary-hover);
452
+ }
453
+
454
+ .bg-action-secondary:active {
455
+ background-color: var(--color-action-secondary-active);
456
+ }
457
+
458
+ .bg-action-secondary:disabled {
459
+ background-color: var(--color-action-secondary-disabled);
460
+ }
461
+
462
+ .bg-action-secondary-subtle {
463
+ background-color: var(--color-action-secondary-subtle);
464
+ }
465
+
466
+ .bg-action-secondary-subtle:hover {
467
+ background-color: var(--color-action-secondary-subtle-hover);
468
+ }
469
+
470
+ /* Danger Actions */
471
+ .bg-action-danger {
472
+ background-color: var(--color-action-danger);
473
+ }
474
+
475
+ .bg-action-danger:hover {
476
+ background-color: var(--color-action-danger-hover);
477
+ }
478
+
479
+ .bg-action-danger:active {
480
+ background-color: var(--color-action-danger-active);
481
+ }
482
+
483
+ .bg-action-danger:disabled {
484
+ background-color: var(--color-action-danger-disabled);
485
+ }
486
+
487
+ .bg-action-danger-subtle {
488
+ background-color: var(--color-action-danger-subtle);
489
+ }
490
+
491
+ .bg-action-danger-subtle:hover {
492
+ background-color: var(--color-action-danger-subtle-hover);
493
+ }
494
+
495
+ /* Modal Animation */
496
+ @keyframes slideUp {
497
+ from {
498
+ transform: translateY(100%);
499
+ }
500
+ to {
501
+ transform: translateY(0);
502
+ }
399
503
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zabi-components",
3
- "version": "5.0.5",
3
+ "version": "5.0.7",
4
4
  "description": "A modern Svelte 5 component library with TypeScript, Tailwind CSS v4, and 100% SSR-safe components",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -80,19 +80,18 @@
80
80
  "prepublishOnly": "npm run build:lib"
81
81
  },
82
82
  "devDependencies": {
83
- "@storybook/addon-svelte-csf": "^5.0.8",
84
- "@storybook/sveltekit": "^9.1.7",
83
+ "@storybook/sveltekit": "^9.1.15",
85
84
  "@sveltejs/adapter-auto": "^7.0.0",
86
85
  "@sveltejs/kit": "^2.47.2",
87
86
  "@sveltejs/package": "^2.5.4",
88
87
  "@sveltejs/vite-plugin-svelte": "^6.2.0",
88
+ "@tailwindcss/postcss": "^4.1.13",
89
89
  "@tsconfig/svelte": "^5.0.5",
90
90
  "@types/node": "^24.5.2",
91
91
  "@types/react": "^19.2.2",
92
- "@tailwindcss/postcss": "^4.1.13",
93
92
  "autoprefixer": "^10.4.17",
94
93
  "postcss": "^8.4.35",
95
- "storybook": "^9.1.7",
94
+ "storybook": "^9.1.15",
96
95
  "svelte": "^5.38.10",
97
96
  "svelte-check": "^4.3.1",
98
97
  "tailwindcss": "^4.1.13",