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