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.
Files changed (207) hide show
  1. package/README.md +139 -1478
  2. package/THEME.md +473 -0
  3. package/THEMING.md +248 -0
  4. package/dist/atoms/ActionPanel.svelte +116 -0
  5. package/dist/atoms/ActionPanel.svelte.d.ts +19 -0
  6. package/dist/atoms/Badge.svelte +1 -1
  7. package/dist/atoms/Badge.svelte.d.ts +1 -1
  8. package/dist/atoms/Button.svelte +35 -16
  9. package/dist/atoms/Button.svelte.d.ts +3 -1
  10. package/dist/atoms/Card.svelte +49 -67
  11. package/dist/atoms/Card.svelte.d.ts +4 -4
  12. package/dist/atoms/CardHeader.svelte +15 -2
  13. package/dist/atoms/CardHeader.svelte.d.ts +5 -0
  14. package/dist/atoms/Checkbox.svelte +50 -76
  15. package/dist/atoms/Checkbox.svelte.d.ts +7 -2
  16. package/dist/atoms/CodeBlock.svelte +20 -34
  17. package/dist/atoms/CodeBlock.svelte.d.ts +1 -0
  18. package/dist/atoms/ColorPicker.svelte +3 -7
  19. package/dist/atoms/Container.svelte +41 -0
  20. package/dist/atoms/Container.svelte.d.ts +12 -0
  21. package/dist/atoms/Divider.svelte +68 -0
  22. package/dist/atoms/Divider.svelte.d.ts +13 -0
  23. package/dist/atoms/FeatureCard.svelte +35 -50
  24. package/dist/atoms/FeatureCard.svelte.d.ts +9 -4
  25. package/dist/atoms/IconButton.svelte +33 -24
  26. package/dist/atoms/IconButton.svelte.d.ts +4 -8
  27. package/dist/atoms/Input.svelte +58 -26
  28. package/dist/atoms/Input.svelte.d.ts +6 -1
  29. package/dist/atoms/List.svelte +2 -7
  30. package/dist/atoms/List.svelte.d.ts +1 -6
  31. package/dist/atoms/ListItem.svelte +54 -65
  32. package/dist/atoms/ListItem.svelte.d.ts +7 -13
  33. package/dist/atoms/ListItemLeading.svelte +19 -0
  34. package/dist/atoms/ListItemLeading.svelte.d.ts +9 -0
  35. package/dist/atoms/Progress.svelte +2 -2
  36. package/dist/atoms/Radio.svelte +51 -0
  37. package/dist/atoms/Radio.svelte.d.ts +14 -0
  38. package/dist/atoms/Select.svelte +28 -33
  39. package/dist/atoms/Select.svelte.d.ts +0 -10
  40. package/dist/atoms/SelectionControl.svelte +98 -0
  41. package/dist/atoms/SelectionControl.svelte.d.ts +26 -0
  42. package/dist/atoms/Skeleton.svelte +39 -15
  43. package/dist/atoms/Skeleton.svelte.d.ts +7 -3
  44. package/dist/atoms/Table.svelte +27 -0
  45. package/dist/atoms/Table.svelte.d.ts +10 -0
  46. package/dist/atoms/Text.svelte +46 -0
  47. package/dist/atoms/Text.svelte.d.ts +13 -0
  48. package/dist/atoms/Textarea.svelte +74 -53
  49. package/dist/atoms/Textarea.svelte.d.ts +6 -2
  50. package/dist/atoms/ThemeToggle.svelte +35 -24
  51. package/dist/atoms/ThemeToggle.svelte.d.ts +1 -0
  52. package/dist/atoms/Toast.svelte +55 -31
  53. package/dist/atoms/Toast.svelte.d.ts +4 -1
  54. package/dist/atoms/Toggle.svelte +37 -22
  55. package/dist/atoms/Toggle.svelte.d.ts +2 -1
  56. package/dist/atoms/Tooltip.svelte +90 -11
  57. package/dist/atoms/index.d.ts +6 -0
  58. package/dist/atoms/index.js +6 -0
  59. package/dist/atoms/selection-control.styles.d.ts +25 -0
  60. package/dist/atoms/selection-control.styles.js +30 -0
  61. package/dist/components/atoms/index.d.ts +6 -0
  62. package/dist/components/atoms/index.d.ts.map +1 -1
  63. package/dist/components/atoms/selection-control.styles.d.ts +26 -0
  64. package/dist/components/atoms/selection-control.styles.d.ts.map +1 -0
  65. package/dist/components/index.d.ts +42 -7
  66. package/dist/components/index.d.ts.map +1 -1
  67. package/dist/components/molecules/index.d.ts +10 -0
  68. package/dist/components/molecules/index.d.ts.map +1 -1
  69. package/dist/components/molecules/navigation-menu-context.d.ts +11 -0
  70. package/dist/components/molecules/navigation-menu-context.d.ts.map +1 -1
  71. package/dist/components/molecules/toast-store.d.ts +39 -0
  72. package/dist/components/molecules/toast-store.d.ts.map +1 -0
  73. package/dist/components/organisms/index.d.ts +3 -3
  74. package/dist/components/organisms/index.d.ts.map +1 -1
  75. package/dist/components/types/page.types.d.ts +69 -0
  76. package/dist/components/types/page.types.d.ts.map +1 -0
  77. package/dist/components/types/page.types.js +1 -0
  78. package/dist/components/types/variants.d.ts +64 -0
  79. package/dist/components/types/variants.d.ts.map +1 -0
  80. package/dist/components/types/variants.js +44 -0
  81. package/dist/components/util/fixed-sidebar-flyout.d.ts +23 -0
  82. package/dist/components/util/fixed-sidebar-flyout.d.ts.map +1 -0
  83. package/dist/components/util/focus-utils.d.ts +12 -0
  84. package/dist/components/util/focus-utils.d.ts.map +1 -0
  85. package/dist/components/util/ssr-safe.d.ts +17 -0
  86. package/dist/components/util/ssr-safe.d.ts.map +1 -0
  87. package/dist/index.d.ts +42 -7
  88. package/dist/index.js +45 -10
  89. package/dist/lib/layout-width-tokens.d.ts +17 -0
  90. package/dist/lib/layout-width-tokens.d.ts.map +1 -0
  91. package/dist/lib/showcase/component-docs/Button.d.ts +3 -0
  92. package/dist/lib/showcase/component-docs/Button.d.ts.map +1 -0
  93. package/dist/lib/showcase/component-docs/Input.d.ts +3 -0
  94. package/dist/lib/showcase/component-docs/Input.d.ts.map +1 -0
  95. package/dist/lib/showcase/component-docs/List.d.ts +3 -0
  96. package/dist/lib/showcase/component-docs/List.d.ts.map +1 -0
  97. package/dist/lib/showcase/component-docs/Modal.d.ts +3 -0
  98. package/dist/lib/showcase/component-docs/Modal.d.ts.map +1 -0
  99. package/dist/lib/showcase/component-docs/Radio.d.ts +3 -0
  100. package/dist/lib/showcase/component-docs/Radio.d.ts.map +1 -0
  101. package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts +3 -0
  102. package/dist/lib/showcase/component-docs/SidebarNavigation.d.ts.map +1 -0
  103. package/dist/lib/showcase/component-docs/Skeleton.d.ts +3 -0
  104. package/dist/lib/showcase/component-docs/Skeleton.d.ts.map +1 -0
  105. package/dist/lib/showcase/component-docs/_shared.d.ts +12 -0
  106. package/dist/lib/showcase/component-docs/_shared.d.ts.map +1 -0
  107. package/dist/lib/showcase/component-docs/index.d.ts +4 -0
  108. package/dist/lib/showcase/component-docs/index.d.ts.map +1 -0
  109. package/dist/lib/showcase/components-catalog.d.ts +3 -0
  110. package/dist/lib/showcase/components-catalog.d.ts.map +1 -0
  111. package/dist/lib/showcase/components-showcase-constants.d.ts +89 -0
  112. package/dist/lib/showcase/components-showcase-constants.d.ts.map +1 -0
  113. package/dist/lib/showcase/docs-sidebar-helpers.d.ts +15 -0
  114. package/dist/lib/showcase/docs-sidebar-helpers.d.ts.map +1 -0
  115. package/dist/molecules/Alert.svelte +50 -23
  116. package/dist/molecules/Alert.svelte.d.ts +1 -1
  117. package/dist/molecules/ComponentDemo.svelte +54 -51
  118. package/dist/molecules/ContactForm.svelte +70 -65
  119. package/dist/molecules/Dropdown.svelte +99 -108
  120. package/dist/molecules/Dropdown.svelte.d.ts +12 -6
  121. package/dist/molecules/EmptyState.svelte +44 -0
  122. package/dist/molecules/EmptyState.svelte.d.ts +11 -0
  123. package/dist/molecules/FormField.svelte +89 -0
  124. package/dist/molecules/FormField.svelte.d.ts +23 -0
  125. package/dist/molecules/Header.svelte +41 -0
  126. package/dist/molecules/Header.svelte.d.ts +10 -0
  127. package/dist/molecules/ImageUpload.svelte +1 -1
  128. package/dist/molecules/Modal.svelte +39 -26
  129. package/dist/molecules/Modal.svelte.d.ts +4 -2
  130. package/dist/molecules/NavigationMenu.svelte +16 -0
  131. package/dist/molecules/NavigationMenu.svelte.d.ts +2 -0
  132. package/dist/molecules/NavigationMenuContent.svelte +9 -1
  133. package/dist/molecules/NavigationMenuLink.svelte +1 -1
  134. package/dist/molecules/NavigationMenuTrigger.svelte +9 -4
  135. package/dist/molecules/Page.svelte +16 -0
  136. package/dist/molecules/Page.svelte.d.ts +8 -0
  137. package/dist/molecules/PropsTable.svelte +61 -0
  138. package/dist/molecules/PropsTable.svelte.d.ts +8 -0
  139. package/dist/molecules/RadioGroup.svelte +197 -0
  140. package/dist/molecules/RadioGroup.svelte.d.ts +20 -0
  141. package/dist/molecules/Section.svelte +14 -23
  142. package/dist/molecules/Section.svelte.d.ts +2 -11
  143. package/dist/molecules/SidebarBrandHeader.svelte +68 -0
  144. package/dist/molecules/SidebarBrandHeader.svelte.d.ts +10 -0
  145. package/dist/molecules/SidebarFooter.svelte +119 -0
  146. package/dist/molecules/SidebarFooter.svelte.d.ts +23 -0
  147. package/dist/molecules/SidebarNavSection.svelte +49 -0
  148. package/dist/molecules/SidebarNavSection.svelte.d.ts +14 -0
  149. package/dist/molecules/SlideUp.svelte +21 -16
  150. package/dist/molecules/SlideUp.svelte.d.ts +1 -1
  151. package/dist/molecules/Tabs.svelte +6 -11
  152. package/dist/molecules/Toaster.svelte +21 -0
  153. package/dist/molecules/Toaster.svelte.d.ts +6 -0
  154. package/dist/molecules/ToasterToast.svelte +217 -0
  155. package/dist/molecules/ToasterToast.svelte.d.ts +7 -0
  156. package/dist/molecules/index.d.ts +10 -0
  157. package/dist/molecules/index.js +10 -0
  158. package/dist/molecules/navigation-menu-context.d.ts +11 -0
  159. package/dist/molecules/navigation-menu-context.js +18 -0
  160. package/dist/molecules/toast-store.d.ts +38 -0
  161. package/dist/molecules/toast-store.js +34 -0
  162. package/dist/organisms/SidebarAccountPanel.svelte +118 -0
  163. package/dist/organisms/SidebarAccountPanel.svelte.d.ts +20 -0
  164. package/dist/organisms/SidebarNavigation.svelte +286 -212
  165. package/dist/organisms/SidebarNavigation.svelte.d.ts +22 -1
  166. package/dist/organisms/{SidebarProjectPanel.svelte → SidebarPanel.svelte} +67 -34
  167. package/dist/organisms/{SidebarProjectPanel.svelte.d.ts → SidebarPanel.svelte.d.ts} +9 -6
  168. package/dist/organisms/TopNavbar.svelte +214 -0
  169. package/dist/organisms/TopNavbar.svelte.d.ts +35 -0
  170. package/dist/organisms/index.d.ts +3 -3
  171. package/dist/organisms/index.js +3 -3
  172. package/dist/routes/lib/focus-utils.d.ts +7 -18
  173. package/dist/routes/lib/focus-utils.ts +32 -34
  174. package/dist/routes/lib/ssr-safe.ts +5 -4
  175. package/dist/routes/lib/variant-utils.ts +48 -39
  176. package/dist/types/components.d.ts +187 -0
  177. package/dist/types/components.d.ts.map +1 -0
  178. package/dist/types/events.d.ts +200 -0
  179. package/dist/types/events.d.ts.map +1 -0
  180. package/dist/types/index.d.ts +171 -0
  181. package/dist/types/index.d.ts.map +1 -0
  182. package/dist/types/page.types.d.ts +3 -0
  183. package/dist/types/page.types.d.ts.map +1 -0
  184. package/dist/types/page.types.js +1 -0
  185. package/dist/types/page.types.ts +79 -0
  186. package/dist/types/variants.d.ts +3 -0
  187. package/dist/types/variants.d.ts.map +1 -0
  188. package/dist/types/variants.js +1 -0
  189. package/dist/types/variants.ts +75 -0
  190. package/dist/util/fixed-sidebar-flyout.d.ts +22 -0
  191. package/dist/util/fixed-sidebar-flyout.js +148 -0
  192. package/dist/util/focus-utils.d.ts +11 -0
  193. package/dist/util/focus-utils.js +94 -0
  194. package/dist/util/ssr-safe.d.ts +16 -0
  195. package/dist/util/ssr-safe.js +48 -0
  196. package/dist/zabi-components-colors.css +360 -324
  197. package/dist/zabi-components-theme-dark-only.css +164 -151
  198. package/dist/zabi-components-theme-dark.css +164 -151
  199. package/dist/zabi-components-theme-only.css +253 -230
  200. package/dist/zabi-components-theme.css +253 -230
  201. package/dist/zabi-components.css +1262 -241
  202. package/docs/theme-imports.md +112 -0
  203. package/package.json +32 -10
  204. package/dist/organisms/Navbar.svelte +0 -92
  205. package/dist/organisms/Navbar.svelte.d.ts +0 -14
  206. package/dist/organisms/Navigation.svelte +0 -119
  207. package/dist/organisms/Navigation.svelte.d.ts +0 -21
package/README.md CHANGED
@@ -1,1583 +1,244 @@
1
1
  # Zabi Components
2
2
 
3
- A clean, minimal Svelte 5 component library built with TypeScript and Tailwind CSS. **Less is more** - focused on essential components that just work.
3
+ Svelte **5** UI primitives (runes, `onclick` / `oninput`, …), Tailwind **v4** design tokens, SSR-safe. Requires **Svelte ≥ 5.43.8**.
4
4
 
5
- > **⚠️ Svelte 5 Required**: This library uses Svelte 5 runes syntax (`$props`, `$derived`, `$state`). Make sure you're using Svelte 5.43.8 or later.
6
-
7
- ## Philosophy
8
-
9
- **Clean & Simple**: No unnecessary complexity, just clean components that focus on what matters most. Every component is designed to be intuitive, accessible, and performant. We've simplified everything to use modern CSS and minimal JavaScript.
10
-
11
- ## Features
5
+ ---
12
6
 
13
- - 🎯 **TypeScript First** - Full TypeScript support with comprehensive type definitions
14
- - 🎨 **Semantic Color System** - Built-in semantic colors with automatic dark mode support
15
- - 🌙 **Dark Mode Ready** - Automatic dark mode switching with CSS custom properties
16
- - ♿ **Accessibility First** - ARIA compliant components with keyboard navigation support
17
- - 📱 **Responsive Design** - Mobile-first approach with responsive utilities
18
- - 🧩 **Clean API** - Simple, intuitive component APIs with minimal props
19
- - 🔧 **Utility Functions** - Reusable variant utilities for consistent styling
20
- - 📦 **Tree Shakeable** - Import only what you need
21
- - ✅ **Production Ready** - Fully tested and optimized for production use
22
- - 🚀 **Modern CSS** - CSS-only positioning, animations, and interactions
23
- - ⚡ **Lightweight** - 60-80% less code than traditional component libraries
24
- - 🎭 **Emoji Icons** - Simple emoji-based icons instead of complex SVG libraries
25
- - 🛡️ **SSR Safe** - 100% server-side rendering compatible with zero runtime errors
26
- - 🔄 **SvelteKit Ready** - Full SvelteKit integration with proper hydration
7
+ ## Quick start
27
8
 
28
- ## Installation
9
+ **1. Install**
29
10
 
30
11
  ```bash
31
12
  npm install zabi-components
32
13
  ```
33
14
 
34
- ### Peer Dependencies
35
-
36
- Make sure you have the required peer dependencies installed:
37
-
38
- ```bash
39
- npm install svelte@^5.43.8
40
- npm install @sveltejs/kit@^2.0.0 # Optional, for SvelteKit projects
41
- ```
42
-
43
- ## Theme Setup
44
-
45
- Zabi Components includes a comprehensive theme system with Tailwind CSS v4. You need to import the theme before using components.
46
-
47
- ### Quick Setup
48
-
49
- **For projects with existing Tailwind CSS:**
50
-
51
- ```css
52
- /* app.css */
53
- @import "tailwindcss";
54
- @import 'zabi-components/theme-only';
55
- @import 'zabi-components/dist/zabi-components.css';
56
- ```
57
-
58
- **For standalone projects (no Tailwind setup):**
15
+ Ensure `svelte@^5.43.8` is installed — SvelteKit apps usually already match; add `@sveltejs/kit@^2` only for Kit. Optional: `react@^18` if you use `zabi-components/react`.
59
16
 
60
- ```css
61
- /* app.css */
62
- @import 'zabi-components/theme';
63
- @import 'zabi-components/dist/zabi-components.css';
64
- ```
65
-
66
- ### With Dark Mode
17
+ **2. Global CSS** (e.g. SvelteKit `src/app.css` — adjust for your bundler entry)
67
18
 
68
19
  ```css
69
20
  @import "tailwindcss";
70
- @import 'zabi-components/theme-only';
71
- @import 'zabi-components/theme-dark-only'; /* Add dark mode support */
72
- @import 'zabi-components/dist/zabi-components.css';
21
+ @import "zabi-components/theme-only";
22
+ @import "zabi-components/theme-dark-only";
73
23
  ```
74
24
 
75
- ### Extending the Theme
25
+ No Tailwind? See [docs/theme-imports.md](./docs/theme-imports.md) (`colors` or full `css`).
76
26
 
77
- You can extend the theme with custom colors and fonts:
78
-
79
- ```css
80
- @import "tailwindcss";
81
- @import 'zabi-components/theme-only';
82
-
83
- /* Your custom theme extensions */
84
- @theme {
85
- --font-family-title: 'Your Font', sans-serif;
86
- --color-custom-primary: #ff0000;
87
- }
88
-
89
- @import 'zabi-components/dist/zabi-components.css';
90
- ```
91
-
92
- > 📖 **Complete Theme Guide**: See [THEME.md](./THEME.md) for comprehensive documentation on theme usage, customization, dark mode, and advanced patterns.
93
-
94
- ## Import Methods
95
-
96
- Zabi Components supports multiple import patterns:
97
-
98
- ### Main Import (All Components)
99
- ```typescript
100
- import {
101
- Button,
102
- IconButton,
103
- Input,
104
- Card,
105
- CardHeader,
106
- CardContent,
107
- CardFooter,
108
- Alert,
109
- Badge,
110
- Modal,
111
- NavigationMenu,
112
- Section
113
- } from 'zabi-components';
114
- ```
115
-
116
- ### Subpath Imports (Recommended for Tree Shaking)
117
- ```typescript
118
- // Import from specific categories
119
- import {
120
- Button,
121
- IconButton,
122
- Input,
123
- Badge,
124
- Card,
125
- CardHeader,
126
- CardContent,
127
- CardFooter
128
- } from 'zabi-components/atoms';
129
- import {
130
- Alert,
131
- Modal,
132
- Dropdown,
133
- NavigationMenu,
134
- NavigationMenuList,
135
- NavigationMenuItem,
136
- NavigationMenuTrigger,
137
- NavigationMenuContent,
138
- NavigationMenuLink,
139
- Section,
140
- Tabs
141
- } from 'zabi-components/molecules';
142
- import {
143
- Navbar,
144
- Navigation
145
- } from 'zabi-components/organisms';
146
-
147
- // Import types separately
148
- import type { ButtonEvents, InputEvents } from 'zabi-components/types';
149
-
150
- // Import utility functions
151
- import {
152
- createId,
153
- cn,
154
- getFormData,
155
- validateEmail,
156
- safeLocalStorage,
157
- safeDocument
158
- } from 'zabi-components';
159
- ```
160
-
161
- ## Quick Start
27
+ **3. Use a component** (`+page.svelte` or any Svelte 5 component)
162
28
 
163
29
  ```svelte
164
30
  <script lang="ts">
165
- // Clean Components - Less is More
166
- import {
167
- Card,
168
- CardHeader,
169
- CardContent,
170
- CardFooter,
171
- Form,
172
- Navigation,
173
- Button,
174
- IconButton,
175
- Input,
176
- Textarea,
177
- Badge,
178
- Alert
179
- } from 'zabi-components';
180
-
181
- let formData = $state({
182
- name: '',
183
- email: '',
184
- message: '',
185
- });
186
-
187
- function handleFormSubmit(event: SubmitEvent) {
188
- const formData = new FormData(event.target as HTMLFormElement);
189
- const data = Object.fromEntries(formData.entries());
190
- console.log('Form submitted:', data);
191
- }
192
-
193
- function handleCardClick(event: MouseEvent) {
194
- console.log('Card clicked:', event);
195
- }
196
-
197
- const navItems = [
198
- { label: "Home", href: "/" },
199
- { label: "About", href: "/about" },
200
- { label: "Contact", href: "/contact" },
201
- ];
31
+ import { Button, Input } from "zabi-components";
32
+
33
+ let name = $state("");
202
34
  </script>
203
35
 
204
- <div class="min-h-screen bg-gray-50">
205
- <header class="flex items-center justify-between p-4 bg-white border-b">
206
- <h1 class="text-xl font-bold">My App</h1>
207
- <Navigation variant="header" items={navItems} />
208
- </header>
209
-
210
- <main class="container mx-auto p-6">
211
- <!-- Card with Compound Components -->
212
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-8">
213
- <Card variant="elevated" onclick={handleCardClick}>
214
- <CardHeader>
215
- <h3 class="text-lg font-semibold">Default Card</h3>
216
- </CardHeader>
217
- <CardContent>
218
- <p>This is a card using compound components.</p>
219
- </CardContent>
220
- <CardFooter>
221
- <Button variant="primary" size="sm">Learn More</Button>
222
- </CardFooter>
223
- </Card>
224
-
225
- <Card variant="success" onclick={handleCardClick}>
226
- <CardHeader>
227
- <h3 class="text-lg font-semibold">Success Card</h3>
228
- </CardHeader>
229
- <CardContent>
230
- <p>This card indicates a successful action.</p>
231
- </CardContent>
232
- </Card>
233
-
234
- <Card variant="warning" onclick={handleCardClick}>
235
- <CardHeader>
236
- <h3 class="text-lg font-semibold">Warning Card</h3>
237
- </CardHeader>
238
- <CardContent>
239
- <p>This card shows a warning state.</p>
240
- </CardContent>
241
- </Card>
242
- </div>
243
-
244
- <!-- Form with Semantic Variants -->
245
- <Card variant="outlined">
246
- <CardHeader>
247
- <h2 class="text-xl font-bold">Contact Form</h2>
248
- </CardHeader>
249
- <CardContent>
250
- <Form onsubmit={handleFormSubmit}>
251
- <div class="form-field">
252
- <Input
253
- id="name"
254
- name="name"
255
- value={formData.name}
256
- oninput={(e) => formData.name = (e.target as HTMLInputElement).value}
257
- label="Name"
258
- placeholder="Enter your name"
259
- variant="default"
260
- />
261
- </div>
262
-
263
- <div class="form-field">
264
- <Input
265
- id="email"
266
- name="email"
267
- type="email"
268
- value={formData.email}
269
- oninput={(e) => formData.email = (e.target as HTMLInputElement).value}
270
- label="Email"
271
- placeholder="Enter your email"
272
- variant="success"
273
- />
274
- </div>
275
-
276
- <div class="form-field">
277
- <Textarea
278
- id="message"
279
- name="message"
280
- value={formData.message}
281
- oninput={(e) => formData.message = (e.target as HTMLTextAreaElement).value}
282
- label="Message"
283
- placeholder="Enter your message"
284
- variant="default"
285
- />
286
- </div>
287
-
288
- <div class="form-actions flex gap-2">
289
- <Button type="submit" variant="primary" className="flex-1">
290
- Submit
291
- </Button>
292
- <IconButton variant="outline" label="Help">
293
- ❓
294
- </IconButton>
295
- </div>
296
- </Form>
297
- </CardContent>
298
- </Card>
299
-
300
- <!-- Badges and Alerts -->
301
- <div class="mt-6 space-y-4">
302
- <div class="flex gap-2">
303
- <Badge variant="success">Success</Badge>
304
- <Badge variant="warning">Warning</Badge>
305
- <Badge variant="error">Error</Badge>
306
- <Badge variant="info">Info</Badge>
307
- </div>
308
-
309
- <Alert variant="info" title="Information" message="This is an informational alert." />
310
- </div>
311
- </main>
36
+ <div class="flex max-w-md flex-col gap-4 p-6">
37
+ <Input label="Name" name="name" bind:value={name} placeholder="Ada Lovelace" />
38
+ <Button onclick={() => console.log(name)}>Save</Button>
312
39
  </div>
313
40
  ```
314
41
 
315
- ## Component Overview
316
-
317
- ### Core Components (Clean & Simple)
318
-
319
- | Component | Category | Description | Key Features |
320
- |-----------|----------|-------------|--------------|
321
- | **Card** | Atom | Clean card container | Simple, interactive, image support, compound components, 4 variants |
322
- | **CardHeader** | Atom | Card header section | Compound component for card structure |
323
- | **CardContent** | Atom | Card content section | Compound component for card structure |
324
- | **CardFooter** | Atom | Card footer section | Compound component for card structure |
325
- | **Form** | Molecule | Simple form wrapper | FormData handling, clean API |
326
- | **Navigation** | Organism | Clean navigation | Header/sidebar variants, active state |
327
- | **Button** | Atom | Action button | 6 variants (primary, secondary, danger, ghost, outline, link) |
328
- | **IconButton** | Atom | Icon-only button | Icon-only, variants, sizes, accessible label |
329
- | **Input** | Atom | Form input | Essential props, accessibility, semantic variants |
330
- | **Badge** | Atom | Status indicator | 5 color variants, closable, icon support |
331
- | **Modal** | Molecule | Overlay dialog | Focus trap, keyboard navigation, focus return |
332
- | **Tabs** | Molecule | Tab navigation | Keyboard navigation, 2 variants |
333
- | **Dropdown** | Molecule | Dropdown menu | CSS-only positioning, keyboard navigation, ARIA support |
334
- | **ImageUpload** | Molecule | File upload | Direct selection, preview |
335
- | **Navbar** | Organism | Navigation bar | Mobile menu, responsive |
336
- | **NavigationMenu** | Molecule | Advanced navigation menu | Compound components, keyboard navigation |
337
- | **Section** | Molecule | Content section wrapper | Responsive layout, variant support |
338
- | **Sidebar** | Molecule | Sidebar navigation | Collapsible, responsive |
339
-
340
- ### Simplified Components
341
-
342
- | Component | Category | Description | Key Features |
343
- |-----------|----------|-------------|--------------|
344
- | **Checkbox** | Atom | Checkbox input | Simple on/off state, semantic variants |
345
- | **Select** | Atom | Dropdown select | Basic options support, semantic variants |
346
- | **Textarea** | Atom | Multi-line input | Essential configuration, semantic variants |
347
- | **Toggle** | Atom | Toggle switch | Fixed size, simple state |
348
- | **Progress** | Atom | Progress bar | Percentage display |
349
- | **Heading** | Atom | Text headings | 6 levels, clean styling |
350
- | **ThemeToggle** | Atom | Theme switcher | Emoji-based, simple |
351
- | **Toast** | Atom | Notification toast | Fixed position, basic |
352
- | **Tooltip** | Atom | Hover tooltip | CSS-only positioning |
353
- | **Skeleton** | Atom | Loading placeholder | Simple animation |
354
- | **ColorPicker** | Atom | Color selection | Simple color grid |
355
- | **SlideUp** | Molecule | Slide-up panel | CSS-only animations |
356
- | **CodeBlock** | Atom | Code display | Syntax highlighting support |
357
- | **FeatureCard** | Atom | Feature showcase card | Image, title, description |
358
- | **OptimizedImage** | Atom | Optimized image | Lazy loading, responsive |
359
- | **Alert** | Molecule | Alert notification | Variants, closable, custom content |
360
- | **ContactForm** | Molecule | Contact form | Pre-built form with validation |
361
- | **ComponentDemo** | Molecule | Component showcase | Demo wrapper for examples |
362
-
363
- ## Semantic Color System
364
-
365
- Zabi Components includes a comprehensive semantic color system that automatically supports dark mode and provides consistent styling across all components.
366
-
367
- ### Available Variants
368
-
369
- All components support these semantic color variants:
370
-
371
- - **`default`** - Standard appearance with primary colors
372
- - **`success`** - Green colors for positive states
373
- - **`warning`** - Yellow/amber colors for caution states
374
- - **`error`** - Red colors for error states
375
- - **`info`** - Blue colors for informational states
376
-
377
- ### Usage Examples
42
+ Without the theme CSS, token classes (`bg-input`, `text-body`, …) look unstyled — always import the theme.
378
43
 
379
- ```svelte
380
- <!-- Input variants -->
381
- <Input variant="default" label="Default Input" />
382
- <Input variant="success" label="Success Input" />
383
- <Input variant="warning" label="Warning Input" />
384
- <Input variant="error" label="Error Input" />
385
-
386
- <!-- Textarea variants -->
387
- <Textarea variant="default" label="Default Textarea" />
388
- <Textarea variant="success" label="Success Textarea" />
389
-
390
- <!-- Card variants -->
391
- <Card variant="default" title="Default Card" />
392
- <Card variant="success" title="Success Card" />
393
- <Card variant="warning" title="Warning Card" />
394
- <Card variant="error" title="Error Card" />
395
- <Card variant="info" title="Info Card" />
396
- ```
397
-
398
- ### Utility Functions
399
-
400
- Zabi Components exports several utility functions for common tasks:
401
-
402
- ```typescript
403
- // Main exports (most utilities)
404
- import {
405
- createId,
406
- cn,
407
- getFormData,
408
- validateEmail,
409
- validateRequired,
410
- isBrowser,
411
- safeWindow,
412
- safeDocument,
413
- safeLocalStorage,
414
- generateId
415
- } from 'zabi-components';
416
-
417
- // Or import SSR-safe utilities directly
418
- import {
419
- safeLocalStorage,
420
- safeDocument,
421
- safeWindow,
422
- isBrowser,
423
- generateId
424
- } from 'zabi-components/lib/ssr-safe';
425
-
426
- // ID Generation (SSR-safe)
427
- const uniqueId = createId('input'); // Returns "input-abc123xyz" (client) or "input-ssr-1234567890" (server)
428
-
429
- // Class Name Utility
430
- const className = cn('base-class', condition && 'conditional-class', undefined);
431
- // Returns "base-class conditional-class" (filters out falsy values)
432
-
433
- // Form Utilities
434
- const form = document.querySelector('form') as HTMLFormElement;
435
- const data = getFormData(form); // Returns object with form data
436
-
437
- // Validation
438
- const isValidEmail = validateEmail('user@example.com'); // Returns true/false
439
- const isRequired = validateRequired('value'); // Returns true/false
440
-
441
- // Browser Detection (SSR-safe)
442
- if (isBrowser()) {
443
- // Safe to use window, document, localStorage, etc.
444
- }
445
-
446
- // Safe Browser APIs
447
- const window = safeWindow(); // Returns Window | undefined
448
- const document = safeDocument(); // Returns Document | undefined
449
- const storage = safeLocalStorage(); // Returns Storage | undefined
450
- ```
451
-
452
- ### Variant Utility Functions
453
-
454
- For custom components or advanced usage, you can use the built-in variant utility functions:
455
-
456
- ```typescript
457
- import {
458
- getInputVariantClasses,
459
- getCardVariantClasses,
460
- getVariantClasses
461
- } from 'zabi-components/lib/variant-utils';
462
-
463
- // For input components (Input, Textarea)
464
- const inputClass = getInputVariantClasses('success'); // Returns "input-variant-success"
465
-
466
- // For card components
467
- const cardClass = getCardVariantClasses('error'); // Returns "card-variant-error"
468
-
469
- // For custom components
470
- const borderClass = getVariantClasses('warning', 'border'); // Returns "variant-border-warning"
471
- const textClass = getVariantClasses('success', 'text'); // Returns "variant-text-success"
472
- const bgClass = getVariantClasses('info', 'bg'); // Returns "variant-bg-info"
473
- ```
474
-
475
- ### Dark Mode Support
476
-
477
- The semantic color system automatically adapts to dark mode through CSS custom properties. Simply add the `.dark` class to your document:
478
-
479
- ```javascript
480
- // Toggle dark mode
481
- document.documentElement.classList.toggle('dark');
482
- ```
483
-
484
- All components will automatically switch to their dark mode variants without any additional configuration.
485
-
486
- ## Component API
487
-
488
- ### Card Component
489
-
490
- ```svelte
491
- <Card
492
- title={string}
493
- image={string}
494
- interactive={boolean}
495
- variant="default" | "success" | "warning" | "error" | "info"
496
- size="sm" | "md" | "lg"
497
- className={string}
498
- on:click={(e) => console.log(e.detail.event)}
499
- >
500
- Custom Content
501
- </Card>
502
- ```
503
-
504
- **Props:**
505
- - `title`: Card title
506
- - `image`: Card image URL
507
- - `interactive`: Make card clickable (default: false)
508
- - `variant`: Card variant with semantic colors (default: "default")
509
- - `size`: Card size (default: "md")
510
- - `className`: Additional CSS classes
511
-
512
- **Events:**
513
- - `click`: Fired when interactive card is clicked - `{ detail: { event: MouseEvent } }`
44
+ ---
514
45
 
515
- ### Form Component
46
+ ## Import strategy
516
47
 
517
- ```svelte
518
- <Form
519
- method="get" | "post"
520
- action={string}
521
- className={string}
522
- on:submit={(e) => console.log('Form submitted')}
523
- >
524
- <div class="form-field">
525
- <label for="field" class="form-label">Label</label>
526
- <Input id="field" name="field" class="form-input" />
527
- </div>
528
- <div class="form-actions">
529
- <Button type="submit">Submit</Button>
530
- </div>
531
- </Form>
532
- ```
48
+ | Approach | When to use |
49
+ |----------|-------------|
50
+ | **Barrel** `import { … } from "zabi-components"` | **Default.** Smallest mental load; fine for most apps. |
51
+ | **Category** `zabi-components/atoms`, `/molecules`, `/organisms` | Larger bundles where you want imports to mirror structure, or you only pull one layer in a given file. |
52
+ | **Types** `zabi-components/types` | Shared prop unions / enums in your app code. |
53
+ | **Helpers** `zabi-components`, `zabi-components/lib/ssr-safe`, `lib/variant-utils` | Utilities the package publishes — not app internals. |
533
54
 
534
- **Props:**
535
- - `method`: Form method (default: "post")
536
- - `action`: Form action URL
537
- - `className`: Additional CSS classes
55
+ Stick to **documented package subpaths** from `package.json` `exports`. Do not reach into `node_modules/zabi-components/dist/...` by hand.
538
56
 
539
- **Events:**
540
- - `submit`: Native form submit event - use `FormData` to get form data
57
+ ---
541
58
 
542
- **CSS Classes:**
543
- - `.form-field`: Field container
544
- - `.form-label`: Field label
545
- - `.form-input`: Field input
546
- - `.form-actions`: Action buttons container
59
+ ## Mental model
547
60
 
548
- ### Layout Component
61
+ **Data-driven (start here)** — You pass **arrays or option lists**; the component renders rows and wires behavior (keyboard, selection, labels).
549
62
 
550
63
  ```svelte
551
- <Layout
552
- variant="main" | "sidebar" | "grid"
553
- className={string}
554
- >
555
- <div slot="header">Header Content</div>
556
- Main Content
557
- <div slot="footer">Footer Content</div>
558
- </Layout>
559
- ```
560
-
561
- **Props:**
562
- - `variant`: Layout type (default: "main")
563
- - `className`: Additional CSS classes
564
-
565
- **Slots:**
566
- - `header`: Header content
567
- - `default`: Main content
568
- - `footer`: Footer content
64
+ <script lang="ts">
65
+ import { List, RadioGroup } from "zabi-components";
569
66
 
570
- ### Navigation Component
67
+ let choice = $state<string | undefined>();
68
+ </script>
571
69
 
572
- ```svelte
573
- <Navigation
574
- variant="header" | "sidebar"
575
- items={Array<{label: string, href: string, icon?: any}>}
576
- currentPath={string}
577
- className={string}
578
- on:click={(e) => console.log('Navigation clicked')}
579
- />
70
+ <List items={[{ id: "a", label: "Alpha" }]} ariaLabel="Example" />
71
+ <RadioGroup legend="Pick one" options={[{ value: "x", label: "X" }]} bind:value={choice} />
580
72
  ```
581
73
 
582
- **Props:**
583
- - `variant`: Navigation type (default: "header")
584
- - `items`: Navigation items array
585
- - `currentPath`: Current active path
586
- - `className`: Additional CSS classes
587
-
588
- **Events:**
589
- - `click`: Native click event on navigation items
590
-
591
- ### NavigationMenu Component
592
-
593
- Advanced navigation menu system with compound components:
74
+ **Composable (advanced)** — You assemble **nested components** when layout and snippets matter more than a single props object.
594
75
 
595
76
  ```svelte
596
77
  <script lang="ts">
597
- import {
598
- NavigationMenu,
599
- NavigationMenuList,
600
- NavigationMenuItem,
601
- NavigationMenuTrigger,
602
- NavigationMenuContent,
603
- NavigationMenuLink
604
- } from 'zabi-components';
78
+ import {
79
+ Card,
80
+ CardHeader,
81
+ CardContent,
82
+ NavigationMenu,
83
+ NavigationMenuList,
84
+ NavigationMenuItem,
85
+ NavigationMenuTrigger,
86
+ } from "zabi-components";
605
87
  </script>
606
88
 
607
- <NavigationMenu>
608
- <NavigationMenuList>
609
- <NavigationMenuItem>
610
- <NavigationMenuTrigger>Products</NavigationMenuTrigger>
611
- <NavigationMenuContent>
612
- <NavigationMenuLink href="/products/web">Web</NavigationMenuLink>
613
- <NavigationMenuLink href="/products/mobile">Mobile</NavigationMenuLink>
614
- </NavigationMenuContent>
615
- </NavigationMenuItem>
616
- <NavigationMenuItem>
617
- <NavigationMenuLink href="/about">About</NavigationMenuLink>
618
- </NavigationMenuItem>
619
- </NavigationMenuList>
620
- </NavigationMenu>
621
- ```
622
-
623
- **Compound Components:**
624
- - `NavigationMenu`: Root container
625
- - `NavigationMenuList`: List wrapper
626
- - `NavigationMenuItem`: Individual menu item
627
- - `NavigationMenuTrigger`: Trigger for dropdown items
628
- - `NavigationMenuContent`: Dropdown content container
629
- - `NavigationMenuLink`: Navigation link component
630
-
631
- **Features:**
632
- - Keyboard navigation support
633
- - ARIA compliant
634
- - CSS-only positioning
635
- - Responsive design
636
-
637
- ### Section Component
638
-
639
- ```svelte
640
- <Section
641
- variant="default" | "primary" | "secondary"
642
- size="sm" | "md" | "lg" | "xl"
643
- className={string}
644
- >
645
- Section content
646
- </Section>
647
- ```
648
-
649
- **Props:**
650
- - `variant`: Section style variant (default: "default")
651
- - `size`: Section size (default: "md")
652
- - `className`: Additional CSS classes
653
-
654
- ### Button Component
655
-
656
- ```svelte
657
- <Button
658
- variant="primary" | "secondary" | "danger" | "ghost" | "outline" | "link"
659
- size="sm" | "md" | "lg"
660
- disabled={boolean}
661
- type="button" | "submit" | "reset"
662
- className={string}
663
- onclick={(e) => console.log('Button clicked')}
664
- >
665
- Button Content
666
- </Button>
667
- ```
668
-
669
- **Props:**
670
- - `variant`: Button style variant (default: "primary")
671
- - `primary`: Primary action button with solid background
672
- - `secondary`: Secondary action button
673
- - `danger`: Destructive action button (red)
674
- - `ghost`: Transparent button with hover effect
675
- - `outline`: Outlined button with border
676
- - `link`: Text button styled as a link
677
- - `size`: Button size (default: "md")
678
- - `disabled`: Disable the button (default: false)
679
- - `type`: HTML button type (default: "button")
680
- - `className`: Additional CSS classes
681
-
682
- **Events:**
683
- - `onclick`: Native click event - `MouseEvent`
684
-
685
- ### IconButton Component
686
-
687
- ```svelte
688
- <IconButton
689
- variant="primary" | "secondary" | "danger" | "ghost" | "outline" | "link"
690
- size="sm" | "md" | "lg"
691
- disabled={boolean}
692
- type="button" | "submit" | "reset"
693
- label={string}
694
- onclick={(e) => console.log('Icon clicked', e)}
695
- >
696
- <!-- Icon content -->
697
- </IconButton>
698
- ```
699
-
700
- **Props:**
701
- - `variant`: Icon button style (default: "primary")
702
- - `size`: Icon button size (default: "md")
703
- - `disabled`: Disable the button (default: false)
704
- - `type`: HTML button type (default: "button")
705
- - `label`: Accessible label for screen readers
706
-
707
- **Events:**
708
- - `onclick`: Native click event - `MouseEvent`
709
-
710
- ### Input Component
711
-
712
- ```svelte
713
- <Input
714
- value={string}
715
- type={string}
716
- label={string}
717
- placeholder={string}
718
- disabled={boolean}
719
- size="sm" | "md" | "lg"
720
- variant="default" | "success" | "warning" | "error"
721
- className={string}
722
- on:input={(e) => console.log('Input changed:', e.target.value)}
723
- on:change={(e) => console.log('Input changed:', e.target.value)}
724
- />
725
- ```
726
-
727
- **Props:**
728
- - `value`: Input value (controlled)
729
- - `type`: Input type (default: "text")
730
- - `label`: Input label
731
- - `placeholder`: Input placeholder
732
- - `disabled`: Disable the input (default: false)
733
- - `size`: Input size (default: "md")
734
- - `variant`: Input variant with semantic colors (default: "default")
735
- - `className`: Additional CSS classes
736
-
737
- **Events:**
738
- - `input`: Native input event - `InputEvent`
739
- - `change`: Native change event - `Event`
740
-
741
- ### Textarea Component
742
-
743
- ```svelte
744
- <Textarea
745
- value={string}
746
- label={string}
747
- placeholder={string}
748
- disabled={boolean}
749
- rows={number}
750
- size="sm" | "md" | "lg"
751
- variant="default" | "success" | "warning" | "error"
752
- className={string}
753
- on:input={(e) => console.log('Textarea changed:', e.target.value)}
754
- on:change={(e) => console.log('Textarea changed:', e.target.value)}
755
- />
756
- ```
757
-
758
- **Props:**
759
- - `value`: Textarea value (controlled)
760
- - `label`: Textarea label
761
- - `placeholder`: Textarea placeholder
762
- - `disabled`: Disable the textarea (default: false)
763
- - `rows`: Number of visible text lines (default: 4)
764
- - `size`: Textarea size (default: "md")
765
- - `variant`: Textarea variant with semantic colors (default: "default")
766
- - `className`: Additional CSS classes
767
-
768
- **Events:**
769
- - `input`: Native input event - `InputEvent`
770
- - `change`: Native change event - `Event`
771
-
772
- ### Card Component
773
-
774
- Card component supports two APIs: prop-based (backward compatible) and compound components (recommended).
775
-
776
- #### Prop-based API (Backward Compatible)
777
-
778
- ```svelte
779
- <Card
780
- title="Card Title"
781
- description="Card description"
782
- image="image-url.jpg"
783
- variant="default" | "elevated" | "outlined" | "flat"
784
- size="sm" | "md" | "lg"
785
- fullWidth={boolean}
786
- onclick={(e) => console.log('Card clicked', e)}
787
- >
788
- Additional Content
789
- </Card>
790
- ```
791
-
792
- #### Compound Component API (Recommended)
793
-
794
- ```svelte
795
- <Card variant="elevated">
796
- <CardHeader>
797
- <CardTitle>Card Title</CardTitle>
798
- <CardDescription>Card description</CardDescription>
799
- </CardHeader>
800
- <CardContent>
801
- Main content goes here
802
- </CardContent>
803
- <CardFooter>
804
- <Button variant="primary">Action</Button>
805
- </CardFooter>
89
+ <Card>
90
+ <CardHeader title="Title" />
91
+ <CardContent><p class="text-body">Main content.</p></CardContent>
806
92
  </Card>
807
- ```
808
-
809
- **Props:**
810
- - `variant`: Card style variant (default: "default")
811
- - `default`: Standard card with subtle shadow
812
- - `elevated`: Card with stronger shadow (elevated appearance)
813
- - `outlined`: Card with border, no shadow
814
- - `flat`: Card with no shadow, no border (minimal)
815
- - `size`: Card size (default: "md")
816
- - `fullWidth`: Whether card takes full width (default: true)
817
- - `title`: Card title (old API)
818
- - `description`: Card description (old API)
819
- - `image`: Card image URL (old API)
820
- - `onclick`: Click handler for interactive cards
821
-
822
- **Compound Components:**
823
- - `CardHeader`: Header section container
824
- - `CardContent`: Main content area
825
- - `CardFooter`: Footer section container
826
- - `CardTitle`: Title component (supports heading levels 1-6)
827
- - `CardDescription`: Description text component
828
-
829
- **Events:**
830
- - `onclick`: Native click event - `MouseEvent`
831
-
832
- **Keyboard Navigation (Interactive Cards):**
833
- - **Tab**: Focus the card
834
- - **Enter / Space**: Activate card click handler
835
-
836
- ### Alert Component
837
-
838
- ```svelte
839
- <Alert
840
- variant="info" | "success" | "warning" | "error"
841
- title={string}
842
- message={string}
843
- closable={boolean}
844
- className={string}
845
- onclick={(e) => console.log('Alert closed', e)}
846
- >
847
- Custom Alert Content
848
- </Alert>
849
- ```
850
-
851
- **Props:**
852
- - `variant`: Alert type (default: "info")
853
- - `title`: Alert title
854
- - `message`: Alert message
855
- - `closable`: Show close button (default: false)
856
- - `className`: Additional CSS classes
857
-
858
- **Slots:**
859
- - `default`: Custom alert content (overrides message prop)
860
-
861
- **Events:**
862
- - `close`: Fired when alert is closed - `{ detail: { value: true, event: Event } }`
863
-
864
- ## Modern CSS Features
865
-
866
- Zabi Components leverages modern CSS features for better performance and developer experience:
867
-
868
- ### Container Queries
869
- ```css
870
- .card {
871
- container-type: inline-size;
872
- }
873
-
874
- @container (min-width: 300px) {
875
- .card-content {
876
- display: flex;
877
- flex-direction: row;
878
- }
879
- }
880
- ```
881
-
882
- ### CSS Grid & Subgrid
883
- ```css
884
- .layout-grid {
885
- display: grid;
886
- grid-template-columns: subgrid;
887
- gap: 1rem;
888
- }
889
- ```
890
-
891
- ### CSS Logical Properties
892
- ```css
893
- .component {
894
- margin-inline-start: 1rem;
895
- padding-block: 0.5rem;
896
- border-inline-end: 1px solid;
897
- }
898
- ```
899
-
900
- ### CSS Cascade Layers
901
- ```css
902
- @layer base, components, utilities;
903
-
904
- @layer components {
905
- .card {
906
- /* Component styles */
907
- }
908
- }
909
- ```
910
-
911
- ## Theming
912
-
913
- Zabi Components uses CSS custom properties and Tailwind CSS for easy theming. You can customize the appearance by overriding these variables:
914
-
915
- ```css
916
- :root {
917
- /* Primary Colors */
918
- --zabi-primary: theme('colors.blue.600');
919
- --zabi-primary-hover: theme('colors.blue.700');
920
- --zabi-primary-active: theme('colors.blue.800');
921
-
922
- /* Secondary Colors */
923
- --zabi-secondary: theme('colors.stone.600');
924
- --zabi-secondary-hover: theme('colors.stone.700');
925
-
926
- /* Success Colors */
927
- --zabi-success: theme('colors.green.600');
928
- --zabi-success-hover: theme('colors.green.700');
929
-
930
- /* Warning Colors */
931
- --zabi-warning: theme('colors.yellow.600');
932
- --zabi-warning-hover: theme('colors.yellow.700');
933
-
934
- /* Error Colors */
935
- --zabi-error: theme('colors.red.600');
936
- --zabi-error-hover: theme('colors.red.700');
937
-
938
- /* Info Colors */
939
- --zabi-info: theme('colors.blue.600');
940
- --zabi-info-hover: theme('colors.blue.700');
941
-
942
- /* Surface Colors */
943
- --zabi-surface: theme('colors.white');
944
- --zabi-surface-hover: theme('colors.stone.50');
945
-
946
- /* Border Colors */
947
- --zabi-border: theme('colors.stone.300');
948
- --zabi-border-hover: theme('colors.stone.400');
949
- --zabi-border-focus: theme('colors.blue.500');
950
-
951
- /* Text Colors */
952
- --zabi-text: theme('colors.stone.900');
953
- --zabi-text-muted: theme('colors.stone.600');
954
- --zabi-text-placeholder: theme('colors.stone.400');
955
- --zabi-text-inverse: theme('colors.white');
956
- }
957
- ```
958
-
959
- ### Dark Mode
960
93
 
961
- Dark mode is automatically supported through CSS custom properties:
962
-
963
- ```css
964
- .dark {
965
- --zabi-surface: theme('colors.stone.800');
966
- --zabi-surface-hover: theme('colors.stone.700');
967
- --zabi-text: theme('colors.stone.200');
968
- --zabi-text-muted: theme('colors.stone.500');
969
- --zabi-border: theme('colors.stone.600');
970
- }
94
+ <NavigationMenu>
95
+ <NavigationMenuList>
96
+ <NavigationMenuItem>
97
+ <NavigationMenuTrigger>Products</NavigationMenuTrigger>
98
+ </NavigationMenuItem>
99
+ </NavigationMenuList>
100
+ </NavigationMenu>
971
101
  ```
972
102
 
973
- ## Event Handling
103
+ Wrong mental model: treating composable roots as optional — see **Common pitfalls**.
974
104
 
975
- Zabi Components now use **native DOM events** with **event forwarding** for maximum compatibility across frameworks.
976
-
977
- ### Event Forwarding
978
-
979
- All components use `{...$$restProps}` to forward native DOM events, making them compatible with React, Vue, Svelte, and vanilla JavaScript.
105
+ ---
980
106
 
981
- ```svelte
982
- <!-- All these work the same way -->
983
- <Button on:click={handleClick}>Click me</Button>
984
- <Input on:input={handleInput} on:change={handleChange} />
985
- <Modal on:click={handleClose} on:keydown={handleKeydown} />
986
- ```
107
+ ## Pattern examples
987
108
 
988
- ### Form Components
109
+ Components use **DOM-style props** (`onclick`, `oninput`), not legacy `on:click`.
989
110
 
990
- Form components use **controlled components** pattern instead of two-way binding:
111
+ **List** — data + optional selection:
991
112
 
992
113
  ```svelte
993
114
  <script lang="ts">
994
- let inputValue = '';
995
- let checkboxValue = false;
996
-
997
- function handleInput(event: Event) {
998
- inputValue = (event.target as HTMLInputElement).value;
999
- }
1000
-
1001
- function handleCheckbox(event: Event) {
1002
- checkboxValue = (event.target as HTMLInputElement).checked;
1003
- }
1004
- </script>
1005
-
1006
- <Input
1007
- value={inputValue}
1008
- on:input={handleInput}
1009
- label="Name"
1010
- />
1011
- <Checkbox
1012
- checked={checkboxValue}
1013
- on:change={handleCheckbox}
1014
- label="Subscribe"
1015
- />
1016
- ```
1017
-
1018
- ### Migration from Previous Versions
1019
-
1020
- **Before (v2.0.x):**
1021
- ```svelte
1022
- <Input bind:value={inputValue} />
1023
- <Button on:click={handleClick}>Click</Button>
1024
- <Modal bind:isOpen onclick={handleClose} />
1025
- ```
1026
-
1027
- **After (v2.1.x):**
1028
- ```svelte
1029
- <Input value={inputValue} on:input={(e) => inputValue = e.target.value} />
1030
- <Button on:click={handleClick}>Click</Button>
1031
- <Modal bind:isOpen on:click={handleClose} />
1032
- ```
1033
-
1034
- ### Benefits
1035
-
1036
- - ✅ **SSR Safe**: No more hydration errors in production
1037
- - ✅ **Cross-Framework**: Works in React, Vue, Svelte, vanilla JS
1038
- - ✅ **Standards Compliant**: Uses native DOM events
1039
- - ✅ **Better Performance**: Reduced JavaScript overhead
1040
-
1041
- ## TypeScript Support
1042
-
1043
- Full TypeScript definitions are included with comprehensive type safety:
1044
-
1045
- ### Event Types
1046
-
1047
- All components now use native DOM events with proper TypeScript typing:
115
+ import { List } from "zabi-components"; // or …/atoms
116
+ import { Home } from "@lucide/svelte";
1048
117
 
1049
- ```typescript
1050
- // Native event handlers with proper typing
1051
- function handleButtonClick(event: MouseEvent) {
1052
- console.log('Button clicked:', event);
1053
- }
1054
-
1055
- function handleInputChange(event: Event) {
1056
- const target = event.target as HTMLInputElement;
1057
- console.log('Input value:', target.value);
1058
- }
1059
-
1060
- function handleFormSubmit(event: SubmitEvent) {
1061
- const formData = new FormData(event.target as HTMLFormElement);
1062
- const data = Object.fromEntries(formData.entries());
1063
- console.log('Form data:', data);
1064
- }
1065
- ```
118
+ const items = [
119
+ { id: "1", label: "Home", icon: Home },
120
+ { id: "2", label: "Settings", href: "/settings" },
121
+ ];
122
+ </script>
1066
123
 
1067
- ### Component Props
1068
-
1069
- All components have proper prop typing with event forwarding:
1070
-
1071
- ```typescript
1072
- // All components support event forwarding
1073
- interface ButtonProps {
1074
- variant?: "primary" | "secondary" | "danger" | "ghost" | "outline" | "link";
1075
- size?: "sm" | "md" | "lg";
1076
- disabled?: boolean;
1077
- type?: "button" | "submit" | "reset";
1078
- className?: string;
1079
- // All native button events are forwarded via {...$$restProps}
1080
- }
1081
-
1082
- interface InputProps {
1083
- value?: string;
1084
- type?: string;
1085
- label?: string;
1086
- placeholder?: string;
1087
- disabled?: boolean;
1088
- size?: "sm" | "md" | "lg";
1089
- variant?: "default" | "success" | "warning" | "error";
1090
- className?: string;
1091
- // All native input events are forwarded via {...$$restProps}
1092
- }
124
+ <List items={items} selectedId="1" ariaLabel="Navigation" />
1093
125
  ```
1094
126
 
1095
- ## SSR Safety & SvelteKit Integration
1096
-
1097
- Zabi Components is **100% SSR-safe** and fully compatible with SvelteKit's server-side rendering. All components have been thoroughly tested to eliminate runtime errors and ensure proper hydration.
1098
-
1099
- ### ✅ **Zero Runtime Errors**
1100
-
1101
- All components are designed to work seamlessly in both server and client environments:
1102
-
1103
- - **No "Cannot read properties of null" errors**
1104
- - **Proper hydration without mismatches**
1105
- - **Safe browser API access**
1106
- - **Consistent behavior across SSR and client**
1107
-
1108
- ### 🛡️ **SSR-Safe Patterns**
1109
-
1110
- Components use consistent SSR-safe patterns:
127
+ **Modal** — `bind:isOpen`, body in the default slot, optional `{#snippet footer()}`:
1111
128
 
1112
129
  ```svelte
1113
130
  <script lang="ts">
1114
- import { onMount } from "svelte";
1115
- import { safeLocalStorage, safeDocument } from "zabi-components/lib/ssr-safe";
1116
-
1117
- let mounted = $state(false);
1118
-
1119
- onMount(() => {
1120
- mounted = true;
1121
- // Safe browser API access after mount
1122
- const storage = safeLocalStorage();
1123
- if (storage) {
1124
- // Use localStorage safely
1125
- }
1126
- });
1127
- </script>
1128
- ```
1129
-
1130
- ### 🔄 **SvelteKit Integration**
131
+ import { Modal, Button } from "zabi-components";
1131
132
 
1132
- Perfect integration with SvelteKit features:
1133
-
1134
- ```svelte
1135
- <script lang="ts">
1136
- import { goto } from '$app/navigation';
1137
- import { Button } from 'zabi-components';
133
+ let open = $state(false);
1138
134
  </script>
1139
135
 
1140
- <!-- SSR-safe navigation -->
1141
- <Button onclick={() => goto('/about')}>
1142
- Go to About
1143
- </Button>
1144
- ```
136
+ <Button onclick={() => (open = true)}>Open</Button>
1145
137
 
1146
- ### 🎯 **Key SSR Features**
1147
-
1148
- - **Safe ID Generation**: Prevents hydration mismatches
1149
- - **Browser API Guards**: All browser APIs are safely accessed
1150
- - **Consistent State**: Server and client state remain synchronized
1151
- - **Theme Persistence**: Dark mode works correctly on first load
1152
- - **Form Stability**: Input IDs remain consistent across hydration
1153
-
1154
- ### 📋 **SSR Best Practices**
1155
-
1156
- 1. **Use SvelteKit Navigation**: Always use `goto()` instead of `window.location.href`
1157
- 2. **Safe Browser Access**: Use provided SSR-safe utilities
1158
- 3. **Consistent IDs**: Let components handle ID generation internally
1159
- 4. **Theme Loading**: Components handle theme loading automatically
1160
-
1161
- ## Advanced Usage
1162
-
1163
- ### Custom Styling
1164
-
1165
- ```svelte
1166
- <Button
1167
- variant="primary"
1168
- size="lg"
1169
- className="w-full shadow-lg hover:shadow-xl"
1170
- on:click={(e) => console.log('Clicked!', e)}
1171
- >
1172
- Custom Button
1173
- </Button>
138
+ <Modal bind:isOpen={open} title="Confirm">
139
+ <p class="text-description">Continue?</p>
140
+ {#snippet footer()}
141
+ <Button variant="secondary" onclick={() => (open = false)}>Cancel</Button>
142
+ <Button onclick={() => (open = false)}>OK</Button>
143
+ {/snippet}
144
+ </Modal>
1174
145
  ```
1175
146
 
1176
- ### Form Integration
147
+ **RadioGroup** — `bind:value` or `defaultValue`:
1177
148
 
1178
149
  ```svelte
1179
150
  <script lang="ts">
1180
- import { Button, Input, Card, Alert } from 'zabi-components';
1181
-
1182
- interface FormData {
1183
- name: string;
1184
- email: string;
1185
- message: string;
1186
- }
1187
-
1188
- interface FormErrors {
1189
- name?: string;
1190
- email?: string;
1191
- message?: string;
1192
- }
1193
-
1194
- let formData: FormData = {
1195
- name: '',
1196
- email: '',
1197
- message: ''
1198
- };
1199
-
1200
- let errors: FormErrors = {};
1201
- let showSuccess = false;
1202
-
1203
- function validateForm(): boolean {
1204
- errors = {};
1205
- if (!formData.name) errors.name = 'Name is required';
1206
- if (!formData.email) errors.email = 'Email is required';
1207
- return Object.keys(errors).length === 0;
1208
- }
1209
-
1210
- function handleSubmit(event: SubmitEvent) {
1211
- if (validateForm()) {
1212
- showSuccess = true;
1213
- // Submit form
1214
- console.log('Form submitted:', formData);
1215
- }
1216
- }
1217
- </script>
1218
-
1219
- <Card>
1220
- <div slot="header">
1221
- <h2>Contact Form</h2>
1222
- </div>
1223
-
1224
- <form on:submit|preventDefault={handleSubmit}>
1225
- <Input
1226
- value={formData.name}
1227
- on:input={(e) => formData.name = e.target.value}
1228
- label="Name"
1229
- placeholder="Enter your name"
1230
- required
1231
- />
1232
-
1233
- <Input
1234
- value={formData.email}
1235
- type="email"
1236
- on:input={(e) => formData.email = e.target.value}
1237
- label="Email"
1238
- placeholder="Enter your email"
1239
- required
1240
- />
1241
-
1242
- <Input
1243
- value={formData.message}
1244
- on:input={(e) => formData.message = e.target.value}
1245
- label="Message"
1246
- placeholder="Enter your message"
1247
- />
1248
-
1249
- <Button type="submit" variant="primary">
1250
- Send Message
1251
- </Button>
1252
- </form>
1253
-
1254
- <div slot="footer">
1255
- {#if showSuccess}
1256
- <Alert variant="success" closable>
1257
- Message sent successfully!
1258
- </Alert>
1259
- {/if}
1260
- </div>
1261
- </Card>
1262
- ```
1263
-
1264
- ## Contributing
1265
-
1266
- 1. Fork the repository
1267
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
1268
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
1269
- 4. Push to the branch (`git push origin feature/amazing-feature`)
1270
- 5. Open a Pull Request
1271
-
1272
- ## License
151
+ import { RadioGroup } from "zabi-components";
1273
152
 
1274
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
1275
-
1276
- ## Changelog
1277
-
1278
- ### v5.0.21 (Latest) - Current Version
1279
-
1280
- See [CHANGELOG.md](./CHANGELOG.md) for the complete changelog.
1281
-
1282
- ### v5.0.18 - "Enhanced Components" Edition
1283
-
1284
- #### ✨ **Component Enhancements**
1285
- - **Card Compound Components**: Added CardHeader, CardContent, CardFooter, CardTitle, and CardDescription
1286
- - **Button Variants**: Added ghost, outline, and link variants
1287
- - **Badge Updates**: Added icon support and enhanced size variants
1288
- - **NavigationMenu**: Complete navigation menu system with compound components
1289
- - **Section Component**: New responsive section wrapper component
1290
- - **Accessibility**: Enhanced focus management and keyboard navigation across all components
1291
-
1292
- ### v4.0.0 - "Svelte 5 Runes" Edition
1293
-
1294
- #### 🚀 **MAJOR UPDATE** - Svelte 5 Migration
1295
-
1296
- This version migrates to Svelte 5 with runes syntax for better performance and developer experience.
1297
-
1298
- #### ✅ **What's New**
1299
- - **Svelte 5 Runes**: All components now use `$props`, `$derived`, and `$state`
1300
- - **Better Performance**: Improved reactivity and reduced bundle size
1301
- - **Enhanced TypeScript**: Better type inference and safety
1302
- - **Modern Syntax**: Cleaner, more intuitive component APIs
1303
-
1304
- #### 🔄 **Migration Required**
1305
- - **Svelte Version**: Requires Svelte 5.43.8 or later
1306
- - **Syntax Updates**: Components now use runes syntax
1307
- - **Event Handling**: Updated to use `oninput`, `onclick` instead of `on:input`, `on:click`
1308
-
1309
- #### 📋 **Breaking Changes**
1310
- 1. **Svelte Version**: Must upgrade to Svelte 5.43.8+
1311
- 2. **Event Syntax**: Use `oninput`, `onclick` instead of `on:input`, `on:click`
1312
- 3. **Component Props**: All components use Svelte 5 runes syntax
1313
-
1314
- ### v2.1.0 - "Cross-Framework Compatible" Edition
1315
-
1316
- #### 🚀 **MAJOR BREAKING CHANGES** - Event Handling Overhaul
1317
-
1318
- This is a **major breaking change** that affects how all components handle events. The refactoring eliminates SSR/production errors and makes components compatible with React, Vue, and vanilla JavaScript applications.
1319
-
1320
- #### ✅ **What's Fixed**
1321
- - **SSR/Production Errors**: Eliminated all `createEventDispatcher` hydration errors
1322
- - **Cross-Framework Compatibility**: Components now work in React, Vue, Svelte, and vanilla JS
1323
- - **Event Forwarding**: All components use `{...$$restProps}` for native DOM events
1324
- - **Standards Compliance**: Uses web standards instead of framework-specific events
1325
-
1326
- #### 🔄 **Migration Required**
1327
- - **Form Components**: Replace `bind:value` with `value` prop + event handlers
1328
- - **Event Names**: Some custom events replaced with native DOM events
1329
- - **Event Structure**: Simplified event structures across all components
1330
-
1331
- #### 📋 **Breaking Changes**
1332
- 1. **Form Components**: Must use `value` prop + event handlers instead of `bind:value`
1333
- 2. **Event Names**: Some custom events replaced with native DOM events
1334
- 3. **Event Structure**: Simplified event structures across all components
1335
- 4. **SSR Compatibility**: Components now work correctly in SSR environments
1336
-
1337
- See the [Migration Guide](#migration-from-previous-versions) above for detailed examples.
1338
-
1339
- ### v2.0.2 - "Less is More" Edition
1340
-
1341
- ## Development Setup
1342
-
1343
- ### Prerequisites
1344
- - Node.js 18+
1345
- - npm or yarn
1346
- - Svelte 5.43.8+ or SvelteKit 2+
1347
-
1348
- ### Local Development
1349
- ```bash
1350
- # Clone the repository
1351
- git clone https://github.com/sabnor/zabi-components.git
1352
- cd zabi-components
1353
-
1354
- # Install dependencies
1355
- npm install
1356
-
1357
- # Start development server
1358
- npm run dev
1359
-
1360
- # Build library
1361
- npm run build
1362
-
1363
- # Run type checking
1364
- npm run check
1365
-
1366
- # Run tests
1367
- npm run test
1368
- ```
1369
-
1370
- ### Project Structure
1371
- ```
1372
- src/
1373
- ├── components/
1374
- │ ├── atoms/ # Basic UI components
1375
- │ ├── molecules/ # Composite components
1376
- │ └── organisms/ # Complex components
1377
- ├── types/ # TypeScript definitions
1378
- ├── styles/ # CSS and styling
1379
- └── lib/ # Library exports
1380
- ```
1381
-
1382
- ## Troubleshooting
1383
-
1384
- ### Common Issues
1385
-
1386
- #### TypeScript Errors
1387
- If you see TypeScript errors with event handlers, ensure proper typing:
1388
-
1389
- ```typescript
1390
- // ✅ Correct - properly typed event handlers
1391
- function handleClick(event: CustomEvent<{ event: MouseEvent }>) {
1392
- console.log('Clicked:', event.detail.event);
1393
- }
1394
-
1395
- function handleFormSubmit(event: CustomEvent<{
1396
- data: Record<string, FormDataEntryValue>;
1397
- formData: FormData
1398
- }>) {
1399
- console.log('Form data:', event.detail.data);
1400
- }
1401
-
1402
- // ❌ Incorrect - missing proper typing
1403
- function handleClick(event: CustomEvent) {
1404
- console.log(event.detail.value); // May cause type errors
1405
- }
1406
- ```
153
+ let plan = $state<string | undefined>("pro");
154
+ </script>
1407
155
 
1408
- #### CSS @apply Warnings
1409
- If you see "Unknown at rule @apply" warnings in your IDE:
1410
-
1411
- 1. Install Tailwind CSS IntelliSense extension
1412
- 2. Add to your VS Code settings:
1413
- ```json
1414
- {
1415
- "css.customData": [".vscode/tailwind.json"],
1416
- "tailwindCSS.includeLanguages": {
1417
- "svelte": "html"
1418
- }
1419
- }
156
+ <RadioGroup legend="Plan" options={[{ value: "pro", label: "Pro" }]} bind:value={plan} />
1420
157
  ```
1421
158
 
1422
- #### Import Errors
1423
- If you encounter import errors, ensure you're using the latest version:
1424
-
1425
- ```bash
1426
- npm install zabi-components@latest
1427
- ```
1428
-
1429
- #### Runtime Errors
1430
- If you encounter runtime errors, ensure you have the correct peer dependencies:
1431
-
1432
- ```bash
1433
- npm install svelte@^5.43.8 @sveltejs/kit@^2.0.0
1434
- ```
159
+ ---
1435
160
 
1436
- ### Migration from Previous Versions
161
+ ## Design tokens (short)
1437
162
 
1438
- If you're upgrading from a previous version, note these changes:
163
+ | Token / class | Role |
164
+ |---------------|------|
165
+ | `surface-1` / `surface-2` | Layered backgrounds — prefer over raw neutrals so light/dark stay aligned. |
166
+ | `.focus-ring` / `focus-ring--nav` | Keyboard focus rings — don’t replace with `outline-none` unless you substitute an equivalent visible focus style. |
1439
167
 
1440
- 1. **Clean Components**: New Card, Form, Layout, Navigation components
1441
- 2. **Event Structure**: All events follow standardized structure
1442
- 3. **TypeScript**: Enhanced type definitions with proper event typing
1443
- 4. **Modern CSS**: Uses Container Queries, CSS Grid, and logical properties
168
+ Details: [THEME.md](./THEME.md).
1444
169
 
1445
- ## Performance & Best Practices
170
+ ---
1446
171
 
1447
- ### Performance Optimizations
1448
- - **Tree Shaking**: Import only what you need
1449
- - **CSS Containment**: Components use CSS containment for better performance
1450
- - **Efficient Animations**: Uses `will-change` and `transform` for smooth animations
1451
- - **Lazy Loading**: Components support lazy loading when needed
172
+ ## Constraints (do / don’t)
1452
173
 
1453
- ### Best Practices
174
+ **Consumers — imports**
1454
175
 
1455
- #### Component Usage
1456
- ```svelte
1457
- <!-- ✅ Good - Use semantic HTML -->
1458
- <Card title="User Profile" interactive on:click={handleClick}>
1459
- <p>User information</p>
1460
- </Card>
176
+ ```ts
177
+ // ✅ Stable public API
178
+ import { Button, Modal } from "zabi-components";
179
+ import type { ButtonVariant } from "zabi-components/types";
1461
180
 
1462
- <!-- ❌ Avoid - Unnecessary complexity -->
1463
- <div class="custom-card" on:click={handleClick}>
1464
- <h3>User Profile</h3>
1465
- <p>User information</p>
1466
- </div>
1467
- ```
1468
-
1469
- #### Event Handling
1470
- ```typescript
1471
- // ✅ Good - Proper event typing
1472
- function handleFormSubmit(event: CustomEvent<{
1473
- data: Record<string, FormDataEntryValue>;
1474
- formData: FormData
1475
- }>) {
1476
- // Handle form submission
1477
- console.log('Form data:', event.detail.data);
1478
- }
1479
-
1480
- // ❌ Avoid - Untyped events
1481
- function handleFormSubmit(event: any) {
1482
- console.log(event.detail); // No type safety
1483
- }
181
+ // ❌ Fragile / unsupported — may break on upgrades
182
+ import Button from "some-path/node_modules/zabi-components/dist/atoms/Button.svelte";
1484
183
  ```
1485
184
 
1486
- #### Styling
1487
- ```svelte
1488
- <!-- ✅ Good - Use component props and Tailwind -->
1489
- <Button variant="primary" size="lg" className="w-full">
1490
- Submit
1491
- </Button>
1492
-
1493
- <!-- ❌ Avoid - Inline styles -->
1494
- <button style="background: blue; width: 100%;">
1495
- Submit
1496
- </button>
1497
- ```
185
+ **Consumers — styling**
1498
186
 
1499
- ### Accessibility Guidelines
1500
- - Always provide proper labels and ARIA attributes
1501
- - Ensure keyboard navigation works correctly
1502
- - Use semantic HTML elements
1503
- - Test with screen readers
1504
- - Maintain proper color contrast ratios
187
+ Load theme CSS (Quick start). Unstyled components usually mean missing `@import "zabi-components/theme-only"` (and dark overrides if you use `.dark`).
1505
188
 
1506
- ## Compound Components
189
+ **Library code (contributors)**
1507
190
 
1508
- Zabi Components supports compound component patterns for flexible composition:
191
+ ```ts
192
+ // ❌ App routes are not part of the package graph
193
+ import { analytics } from "../../routes/lib/analytics";
1509
194
 
1510
- ### Card Compound Components
195
+ // ✅ Shared helpers live next to components
196
+ import { generateId } from "../util/ssr-safe.js";
1511
197
 
1512
- ```svelte
1513
- <script>
1514
- import { Card, CardHeader, CardContent, CardFooter, CardTitle, CardDescription, Button } from 'zabi-components';
1515
- </script>
198
+ // ❌ Packaging: escaping `dist/` layout (CI fails `npm run check`)
199
+ import type { Foo } from "../../types/variants";
1516
200
 
1517
- <Card variant="elevated">
1518
- <CardHeader>
1519
- <CardTitle>Card Title</CardTitle>
1520
- <CardDescription>
1521
- This is a description using compound components.
1522
- </CardDescription>
1523
- </CardHeader>
1524
- <CardContent>
1525
- <p>Main content area with flexible composition.</p>
1526
- </CardContent>
1527
- <CardFooter>
1528
- <Button variant="primary">Save</Button>
1529
- <Button variant="ghost">Cancel</Button>
1530
- </CardFooter>
1531
- </Card>
201
+ // ✅ Depth matches publish layout
202
+ import type { Foo } from "../types/variants.js";
1532
203
  ```
1533
204
 
1534
- ## Accessibility
1535
-
1536
- Zabi Components is built with accessibility in mind:
1537
-
1538
- ### WCAG 2.1 AA Compliance
1539
- - Comprehensive ARIA attributes
1540
- - Proper semantic HTML
1541
- - Keyboard navigation support
1542
- - Focus management
1543
- - Screen reader compatibility
205
+ ---
1544
206
 
1545
- ### Keyboard Navigation
1546
- - **Tab**: Navigate between interactive elements
1547
- - **Enter/Space**: Activate buttons and links
1548
- - **Arrow Keys**: Navigate within components (Tabs, Navigation, Dropdown)
1549
- - **Escape**: Close modals and overlays
1550
- - **Home/End**: Jump to first/last item in lists
207
+ ## Common pitfalls
1551
208
 
1552
- ### Focus Management
1553
- - Focus trap in modals
1554
- - Focus return after closing modals
1555
- - Visible focus indicators
1556
- - Logical tab order
209
+ | Issue | What goes wrong | Fix |
210
+ |-------|-----------------|-----|
211
+ | **Invalid import paths** | Build fails or types missing — deep `dist/` imports, wrong relative depth to `types/`. | Use `package.json` exports only; types from `zabi-components/types` or correct `../types/` inside `src/components`. |
212
+ | **Composable misuse** | Missing `NavigationMenu` / `NavigationMenuList` wrapper, or orphan `CardHeader` without `Card`. | Follow the documented parent chain; copy structure from Storybook or package demos. |
213
+ | **`outline-none` on custom controls** | WCAG failure — keyboard users see no focus. | Use `.focus-ring`, theme rings, or mirror the focus styles inputs/buttons use. |
214
+ | **Legacy Svelte events** | Handlers never run — this library uses `onclick`, not `on:click`. | Use `onclick={handler}` on components that expose it; use `oninput` / native props per component. |
1557
215
 
1558
- See [ACCESSIBILITY.md](./docs/ACCESSIBILITY.md) and [KEYBOARD_NAVIGATION.md](./docs/KEYBOARD_NAVIGATION.md) for detailed documentation.
1559
- See [DESIGN_SYSTEM_REMEDIATION_TRACKER.md](./docs/DESIGN_SYSTEM_REMEDIATION_TRACKER.md), [AUDIT_RUNBOOK.md](./docs/AUDIT_RUNBOOK.md), and [AUDIT_SCORECARD_TEMPLATE.md](./docs/AUDIT_SCORECARD_TEMPLATE.md) for audit and remediation workflows.
216
+ ---
1560
217
 
1561
- ## Variant System
218
+ ## Development (contributors)
1562
219
 
1563
- Zabi Components uses a consistent variant system:
220
+ | Topic | Rule |
221
+ |-------|------|
222
+ | Utilities | `src/components/util/` |
223
+ | New components | `atoms` / `molecules` / `organisms` by scope |
224
+ | Imports | Shallow relatives inside `components`; no `routes/` |
225
+ | CSS | Prefer Tailwind + tokens; avoid unnecessary `:global` |
1564
226
 
1565
- ### Semantic Variants
1566
- Used for state indication: `default`, `success`, `warning`, `error`, `info`
227
+ ---
1567
228
 
1568
- ### Style Variants
1569
- Used for visual appearance: Button (`primary`, `secondary`, `outline`, `link`, etc.), Card (`elevated`, `outlined`, `flat`)
229
+ ## Testing & quality
1570
230
 
1571
- ### Size Variants
1572
- Consistent across components: `sm`, `md`, `lg`
231
+ | Layer | Command | Purpose |
232
+ |-------|---------|---------|
233
+ | Unit / component | `npm run test` | Vitest + Testing Library — logic and regressions |
234
+ | Interaction | `npm run test:e2e` | Playwright — overlays, focus, keyboard flows |
1573
235
 
1574
- See [VARIANTS.md](./docs/VARIANTS.md) for complete variant documentation.
236
+ ---
1575
237
 
1576
- ## Support
238
+ ## More documentation
1577
239
 
1578
- For support, please open an issue on GitHub or contact the maintainers.
240
+ [THEME.md](./THEME.md) · [THEMING.md](./THEMING.md) · [docs/theme-imports.md](./docs/theme-imports.md) · [CHANGELOG.md](./CHANGELOG.md)
1579
241
 
1580
- ---
242
+ ## License
1581
243
 
1582
- Built with ❤️ using Svelte, TypeScript, and Tailwind CSS.
1583
- **Less is more** - Clean components that just work.
244
+ MIT — see [LICENSE](./LICENSE).