zabi-components 2.0.3 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,10 +9,12 @@ A clean, minimal Svelte component library built with TypeScript and Tailwind CSS
9
9
  ## Features
10
10
 
11
11
  - 🎯 **TypeScript First** - Full TypeScript support with comprehensive type definitions
12
- - 🎨 **Tailwind CSS Integration** - Built with Tailwind CSS for consistent styling
12
+ - 🎨 **Semantic Color System** - Built-in semantic colors with automatic dark mode support
13
+ - 🌙 **Dark Mode Ready** - Automatic dark mode switching with CSS custom properties
13
14
  - ♿ **Accessibility First** - ARIA compliant components with keyboard navigation support
14
15
  - 📱 **Responsive Design** - Mobile-first approach with responsive utilities
15
16
  - 🧩 **Clean API** - Simple, intuitive component APIs with minimal props
17
+ - 🔧 **Utility Functions** - Reusable variant utilities for consistent styling
16
18
  - 📦 **Tree Shakeable** - Import only what you need
17
19
  - ✅ **Production Ready** - Fully tested and optimized for production use
18
20
  - 🚀 **Modern CSS** - CSS-only positioning, animations, and interactions
@@ -59,11 +61,12 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
59
61
  ```svelte
60
62
  <script lang="ts">
61
63
  // Clean Components - Less is More
62
- import { Card, Form, Layout, Navigation, Button, Input } from 'zabi-components';
64
+ import { Card, Form, Layout, Navigation, Button, Input, Textarea } from 'zabi-components';
63
65
 
64
66
  let formData = {
65
67
  name: '',
66
68
  email: '',
69
+ message: '',
67
70
  };
68
71
 
69
72
  function handleFormSubmit(event: CustomEvent) {
@@ -88,17 +91,58 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
88
91
  </div>
89
92
 
90
93
  <main class="container mx-auto p-6">
91
- <Card title="Welcome" description="Clean components that just work" interactive on:click={handleCardClick} />
94
+ <!-- Semantic Color Variants -->
95
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-8">
96
+ <Card title="Default Card" variant="default">
97
+ This is a default card with semantic colors.
98
+ </Card>
99
+ <Card title="Success Card" variant="success">
100
+ This card indicates a successful action.
101
+ </Card>
102
+ <Card title="Warning Card" variant="warning">
103
+ This card shows a warning state.
104
+ </Card>
105
+ <Card title="Error Card" variant="error">
106
+ This card indicates an error state.
107
+ </Card>
108
+ <Card title="Info Card" variant="info">
109
+ This card provides informational content.
110
+ </Card>
111
+ </div>
92
112
 
93
113
  <Form on:submit={handleFormSubmit}>
94
114
  <div class="form-field">
95
- <label for="name" class="form-label">Name</label>
96
- <Input id="name" name="name" bind:value={formData.name} placeholder="Enter your name" />
115
+ <Input
116
+ id="name"
117
+ name="name"
118
+ bind:value={formData.name}
119
+ label="Name"
120
+ placeholder="Enter your name"
121
+ variant="default"
122
+ />
97
123
  </div>
98
124
 
99
125
  <div class="form-field">
100
- <label for="email" class="form-label">Email</label>
101
- <Input id="email" name="email" type="email" bind:value={formData.email} placeholder="Enter your email" />
126
+ <Input
127
+ id="email"
128
+ name="email"
129
+ type="email"
130
+ bind:value={formData.email}
131
+ label="Email"
132
+ placeholder="Enter your email"
133
+ variant="success"
134
+ />
135
+ </div>
136
+
137
+ <div class="form-field">
138
+ <Textarea
139
+ id="message"
140
+ name="message"
141
+ bind:value={formData.message}
142
+ label="Message"
143
+ placeholder="Enter your message"
144
+ variant="default"
145
+ />
102
146
  </div>
103
147
 
104
148
  <div class="form-actions">
@@ -145,6 +189,75 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
145
189
  | **ColorPicker** | Atom | Color selection | Simple color grid |
146
190
  | **SlideUp** | Molecule | Slide-up panel | CSS-only animations |
147
191
 
192
+ ## Semantic Color System
193
+
194
+ Zabi Components includes a comprehensive semantic color system that automatically supports dark mode and provides consistent styling across all components.
195
+
196
+ ### Available Variants
197
+
198
+ All components support these semantic color variants:
199
+
200
+ - **`default`** - Standard appearance with primary colors
201
+ - **`success`** - Green colors for positive states
202
+ - **`warning`** - Yellow/amber colors for caution states
203
+ - **`error`** - Red colors for error states
204
+ - **`info`** - Blue colors for informational states
205
+
206
+ ### Usage Examples
207
+
208
+ ```svelte
209
+ <!-- Input variants -->
210
+ <Input variant="default" label="Default Input" />
211
+ <Input variant="success" label="Success Input" />
212
+ <Input variant="warning" label="Warning Input" />
213
+ <Input variant="error" label="Error Input" />
214
+
215
+ <!-- Textarea variants -->
216
+ <Textarea variant="default" label="Default Textarea" />
217
+ <Textarea variant="success" label="Success Textarea" />
218
+
219
+ <!-- Card variants -->
220
+ <Card variant="default" title="Default Card" />
221
+ <Card variant="success" title="Success Card" />
222
+ <Card variant="warning" title="Warning Card" />
223
+ <Card variant="error" title="Error Card" />
224
+ <Card variant="info" title="Info Card" />
225
+ ```
226
+
227
+ ### Utility Functions
228
+
229
+ For custom components or advanced usage, you can use the built-in utility functions:
230
+
231
+ ```typescript
232
+ import {
233
+ getInputVariantClasses,
234
+ getCardVariantClasses,
235
+ getVariantClasses
236
+ } from 'zabi-components';
237
+
238
+ // For input components (Input, Textarea)
239
+ const inputClass = getInputVariantClasses('success'); // Returns "input-variant-success"
240
+
241
+ // For card components
242
+ const cardClass = getCardVariantClasses('error'); // Returns "card-variant-error"
243
+
244
+ // For custom components
245
+ const borderClass = getVariantClasses('warning', 'border'); // Returns "variant-border-warning"
246
+ const textClass = getVariantClasses('success', 'text'); // Returns "variant-text-success"
247
+ const bgClass = getVariantClasses('info', 'bg'); // Returns "variant-bg-info"
248
+ ```
249
+
250
+ ### Dark Mode Support
251
+
252
+ The semantic color system automatically adapts to dark mode through CSS custom properties. Simply add the `.dark` class to your document:
253
+
254
+ ```javascript
255
+ // Toggle dark mode
256
+ document.documentElement.classList.toggle('dark');
257
+ ```
258
+
259
+ All components will automatically switch to their dark mode variants without any additional configuration.
260
+
148
261
  ## Component API
149
262
 
150
263
  ### Card Component
@@ -152,11 +265,10 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
152
265
  ```svelte
153
266
  <Card
154
267
  title={string}
155
- subtitle={string}
156
- description={string}
157
268
  image={string}
158
- variant="default" | "elevated"
159
269
  interactive={boolean}
270
+ variant="default" | "success" | "warning" | "error" | "info"
271
+ size="sm" | "md" | "lg"
160
272
  className={string}
161
273
  on:click={(e) => console.log(e.detail.event)}
162
274
  >
@@ -166,11 +278,10 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
166
278
 
167
279
  **Props:**
168
280
  - `title`: Card title
169
- - `subtitle`: Card subtitle
170
- - `description`: Card description
171
281
  - `image`: Card image URL
172
- - `variant`: Card style variant (default: "default")
173
282
  - `interactive`: Make card clickable (default: false)
283
+ - `variant`: Card variant with semantic colors (default: "default")
284
+ - `size`: Card size (default: "md")
174
285
  - `className`: Additional CSS classes
175
286
 
176
287
  **Events:**
@@ -287,15 +398,10 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
287
398
  type={string}
288
399
  label={string}
289
400
  placeholder={string}
290
- required={boolean}
291
401
  disabled={boolean}
292
402
  size="sm" | "md" | "lg"
293
- variant="default" | "error" | "success"
294
- error={string}
295
- success={string}
296
- helpText={string}
403
+ variant="default" | "success" | "warning" | "error"
297
404
  className={string}
298
- id={string}
299
405
  on:input={(e) => console.log(e.detail.value, e.detail.event)}
300
406
  on:change={(e) => console.log(e.detail.value, e.detail.event)}
301
407
  />
@@ -306,15 +412,41 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
306
412
  - `type`: Input type (default: "text")
307
413
  - `label`: Input label
308
414
  - `placeholder`: Input placeholder
309
- - `required`: Mark as required (default: false)
310
415
  - `disabled`: Disable the input (default: false)
311
416
  - `size`: Input size (default: "md")
312
- - `variant`: Input variant (default: "default")
313
- - `error`: Error message
314
- - `success`: Success message
315
- - `helpText`: Helper text
417
+ - `variant`: Input variant with semantic colors (default: "default")
418
+ - `className`: Additional CSS classes
419
+
420
+ **Events:**
421
+ - `input`: Fired on input - `{ detail: { value: string, event: InputEvent } }`
422
+ - `change`: Fired on change - `{ detail: { value: string, event: Event } }`
423
+
424
+ ### Textarea Component
425
+
426
+ ```svelte
427
+ <Textarea
428
+ bind:value={string}
429
+ label={string}
430
+ placeholder={string}
431
+ disabled={boolean}
432
+ rows={number}
433
+ size="sm" | "md" | "lg"
434
+ variant="default" | "success" | "warning" | "error"
435
+ className={string}
436
+ on:input={(e) => console.log(e.detail.value, e.detail.event)}
437
+ on:change={(e) => console.log(e.detail.value, e.detail.event)}
438
+ />
439
+ ```
440
+
441
+ **Props:**
442
+ - `value`: Textarea value (bindable)
443
+ - `label`: Textarea label
444
+ - `placeholder`: Textarea placeholder
445
+ - `disabled`: Disable the textarea (default: false)
446
+ - `rows`: Number of visible text lines (default: 4)
447
+ - `size`: Textarea size (default: "md")
448
+ - `variant`: Textarea variant with semantic colors (default: "default")
316
449
  - `className`: Additional CSS classes
317
- - `id`: Input ID
318
450
 
319
451
  **Events:**
320
452
  - `input`: Fired on input - `{ detail: { value: string, event: InputEvent } }`
@@ -0,0 +1,276 @@
1
+ import { w as X, x as L, y as Y, u as O, z as P, A as B, B as Z, j as n, C as u, D as A, i as D, f as M, k as $, t as k, b as p, p as T, c as q, v as S, g as i, m as f, d as z, h as x, n as j, E as I, s as v, a as H, l as J, o as K } from "./props-D1U_TNgY.js";
2
+ function de(a, e) {
3
+ X(() => {
4
+ var t = a.getRootNode(), s = (
5
+ /** @type {ShadowRoot} */
6
+ t.host ? (
7
+ /** @type {ShadowRoot} */
8
+ t
9
+ ) : (
10
+ /** @type {Document} */
11
+ t.head ?? /** @type {Document} */
12
+ t.ownerDocument.head
13
+ )
14
+ );
15
+ if (!s.querySelector("#" + e.hash)) {
16
+ const r = document.createElement("style");
17
+ r.id = e.hash, r.textContent = e.code, s.appendChild(r);
18
+ }
19
+ });
20
+ }
21
+ function Q(a, e, t = e) {
22
+ var s = /* @__PURE__ */ new WeakSet();
23
+ L(a, "input", async (r) => {
24
+ var l = r ? a.defaultValue : a.value;
25
+ if (l = W(a) ? F(l) : l, t(l), B !== null && s.add(B), await Y(), l !== (l = e())) {
26
+ var b = a.selectionStart, d = a.selectionEnd;
27
+ a.value = l ?? "", d !== null && (a.selectionStart = b, a.selectionEnd = Math.min(d, a.value.length));
28
+ }
29
+ }), // If we are hydrating and the value has since changed,
30
+ // then use the updated value from the input instead.
31
+ // If defaultValue is set, then value == defaultValue
32
+ // TODO Svelte 6: remove input.value check and set to empty string?
33
+ O(e) == null && a.value && (t(W(a) ? F(a.value) : a.value), B !== null && s.add(B)), P(() => {
34
+ var r = e();
35
+ if (a === document.activeElement) {
36
+ var l = (
37
+ /** @type {Batch} */
38
+ Z ?? B
39
+ );
40
+ if (s.has(l))
41
+ return;
42
+ }
43
+ W(a) && r === F(a.value) || a.type === "date" && !r && !a.value || r !== a.value && (a.value = r ?? "");
44
+ });
45
+ }
46
+ function ee(a, e, t = e) {
47
+ L(a, "change", (s) => {
48
+ var r = s ? a.defaultChecked : a.checked;
49
+ t(r);
50
+ }), // If we are hydrating and the value has since changed,
51
+ // then use the update value from the input instead.
52
+ // If defaultChecked is set, then checked == defaultChecked
53
+ O(e) == null && t(a.checked), P(() => {
54
+ var s = e();
55
+ a.checked = !!s;
56
+ });
57
+ }
58
+ function W(a) {
59
+ var e = a.type;
60
+ return e === "number" || e === "range";
61
+ }
62
+ function F(a) {
63
+ return a === "" ? null : +a;
64
+ }
65
+ var ae = M("<button><!></button>");
66
+ function ce(a, e) {
67
+ q(e, !1);
68
+ const t = f(), s = f(), r = f();
69
+ let l = n(e, "variant", 8, "primary"), b = n(e, "size", 8, "md"), d = n(e, "disabled", 8, !1), c = n(e, "type", 8, "button");
70
+ u(() => {
71
+ }, () => {
72
+ v(t, {
73
+ sm: "px-3 py-1.5 text-sm",
74
+ md: "px-4 py-2 text-sm",
75
+ lg: "px-5 py-3 text-base"
76
+ });
77
+ }), u(() => {
78
+ }, () => {
79
+ v(s, {
80
+ primary: "bg-blue-600 text-white hover:bg-blue-700",
81
+ secondary: "bg-gray-600 text-white hover:bg-gray-700",
82
+ danger: "bg-red-600 text-white hover:bg-red-700"
83
+ });
84
+ }), u(
85
+ () => (i(t), S(b()), i(s), S(l())),
86
+ () => {
87
+ v(r, [
88
+ "inline-flex items-center justify-center font-medium rounded-md",
89
+ "disabled:opacity-50 disabled:cursor-not-allowed",
90
+ i(t)[b()],
91
+ i(s)[l()]
92
+ ].join(" "));
93
+ }
94
+ ), A(), D();
95
+ var m = ae(), _ = z(m);
96
+ $(_, e, "default", {}), k(() => {
97
+ x(m, "type", c()), j(m, 1, I(i(r))), m.disabled = d();
98
+ }), p(a, m), T();
99
+ }
100
+ function U(a) {
101
+ const e = {
102
+ default: "input-variant-default",
103
+ success: "input-variant-success",
104
+ warning: "input-variant-warning",
105
+ error: "input-variant-error",
106
+ info: "input-variant-info"
107
+ };
108
+ return e[a] || e.default;
109
+ }
110
+ function ue(a) {
111
+ const e = {
112
+ default: "card-variant-default",
113
+ success: "card-variant-success",
114
+ warning: "card-variant-warning",
115
+ error: "card-variant-error",
116
+ info: "card-variant-info"
117
+ };
118
+ return e[a] || e.default;
119
+ }
120
+ function G(a, e) {
121
+ const t = {
122
+ default: `variant-${e}-default`,
123
+ success: `variant-${e}-success`,
124
+ warning: `variant-${e}-warning`,
125
+ error: `variant-${e}-error`,
126
+ info: `variant-${e}-info`
127
+ };
128
+ return t[a] || t.default;
129
+ }
130
+ function fe(a) {
131
+ return {
132
+ border: G(a, "border"),
133
+ text: G(a, "text"),
134
+ bg: G(a, "bg")
135
+ };
136
+ }
137
+ function ve(a, e) {
138
+ return a.reduce((t, s) => (t[s] = `${e}-${s}`, t), {});
139
+ }
140
+ var te = M("<label> </label>"), se = M("<div><!> <input/></div>");
141
+ function be(a, e) {
142
+ q(e, !1);
143
+ const t = f(), s = f(), r = f(), l = f();
144
+ let b = n(e, "value", 12, ""), d = n(e, "type", 8, "text"), c = n(e, "label", 8, ""), m = n(e, "placeholder", 8, ""), _ = n(e, "disabled", 8, !1), g = n(e, "size", 8, "md"), h = n(e, "variant", 8, "default");
145
+ const C = `input-${Math.random().toString(36).substr(2, 9)}`;
146
+ u(() => {
147
+ }, () => {
148
+ v(t, {
149
+ sm: "px-3 py-1.5 text-sm",
150
+ md: "px-4 py-2 text-sm",
151
+ lg: "px-5 py-3 text-base"
152
+ });
153
+ }), u(() => S(h()), () => {
154
+ v(s, U(h()));
155
+ }), u(
156
+ () => (i(t), S(g()), i(s)),
157
+ () => {
158
+ v(r, [
159
+ "w-full rounded-md transition-colors duration-200",
160
+ "focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-surface",
161
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-disabled",
162
+ i(t)[g()],
163
+ i(s)
164
+ ].join(" "));
165
+ }
166
+ ), u(() => {
167
+ }, () => {
168
+ v(l, "block text-sm font-medium text-primary mb-1");
169
+ }), A(), D();
170
+ var V = se(), E = z(V);
171
+ {
172
+ var N = (w) => {
173
+ var y = te(), R = z(y);
174
+ k(() => {
175
+ x(y, "for", C), j(y, 1, I(i(l))), K(R, c());
176
+ }), p(w, y);
177
+ };
178
+ H(E, (w) => {
179
+ c() && w(N);
180
+ });
181
+ }
182
+ var o = J(E, 2);
183
+ k(() => {
184
+ x(o, "id", C), x(o, "type", d()), x(o, "placeholder", m()), o.disabled = _(), j(o, 1, I(i(r)));
185
+ }), Q(o, b), p(a, V), T();
186
+ }
187
+ var re = M("<label> </label>"), le = M("<div><!> <textarea></textarea></div>");
188
+ function me(a, e) {
189
+ q(e, !1);
190
+ const t = f(), s = f(), r = f(), l = f();
191
+ let b = n(e, "value", 12, ""), d = n(e, "label", 8, ""), c = n(e, "placeholder", 8, ""), m = n(e, "disabled", 8, !1), _ = n(e, "rows", 8, 4), g = n(e, "size", 8, "md"), h = n(e, "variant", 8, "default");
192
+ const C = `textarea-${Math.random().toString(36).substr(2, 9)}`;
193
+ u(() => {
194
+ }, () => {
195
+ v(t, {
196
+ sm: "px-3 py-1.5 text-sm",
197
+ md: "px-4 py-2 text-sm",
198
+ lg: "px-5 py-3 text-base"
199
+ });
200
+ }), u(() => S(h()), () => {
201
+ v(s, U(h()));
202
+ }), u(
203
+ () => (i(t), S(g()), i(s)),
204
+ () => {
205
+ v(r, [
206
+ "w-full rounded-md transition-colors duration-200",
207
+ "focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-surface",
208
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-disabled",
209
+ "resize-y",
210
+ i(t)[g()],
211
+ i(s)
212
+ ].join(" "));
213
+ }
214
+ ), u(() => {
215
+ }, () => {
216
+ v(l, "block text-sm font-medium text-primary mb-1");
217
+ }), A(), D();
218
+ var V = le(), E = z(V);
219
+ {
220
+ var N = (w) => {
221
+ var y = re(), R = z(y);
222
+ k(() => {
223
+ x(y, "for", C), j(y, 1, I(i(l))), K(R, d());
224
+ }), p(w, y);
225
+ };
226
+ H(E, (w) => {
227
+ d() && w(N);
228
+ });
229
+ }
230
+ var o = J(E, 2);
231
+ k(() => {
232
+ x(o, "id", C), x(o, "placeholder", c()), o.disabled = m(), x(o, "rows", _()), j(o, 1, I(i(r)));
233
+ }), Q(o, b), p(a, V), T();
234
+ }
235
+ var ne = M('<label class="text-sm font-medium cursor-pointer"> </label>'), ie = M('<div class="flex items-center gap-2"><input type="checkbox"/> <!></div>');
236
+ function xe(a, e) {
237
+ q(e, !1);
238
+ const t = f();
239
+ let s = n(e, "checked", 12, !1), r = n(e, "disabled", 8, !1), l = n(e, "label", 8, "");
240
+ const b = `checkbox-${Math.random().toString(36).substr(2, 9)}`;
241
+ u(() => {
242
+ }, () => {
243
+ v(t, [
244
+ "w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded",
245
+ "focus:ring-blue-500 focus:ring-2",
246
+ "disabled:opacity-50 disabled:cursor-not-allowed"
247
+ ].join(" "));
248
+ }), A(), D();
249
+ var d = ie(), c = z(d), m = J(c, 2);
250
+ {
251
+ var _ = (g) => {
252
+ var h = ne(), C = z(h);
253
+ k(() => {
254
+ x(h, "for", b), K(C, l());
255
+ }), p(g, h);
256
+ };
257
+ H(m, (g) => {
258
+ l() && g(_);
259
+ });
260
+ }
261
+ k(() => {
262
+ x(c, "id", b), c.disabled = r(), j(c, 1, I(i(t)));
263
+ }), ee(c, s), p(a, d), T();
264
+ }
265
+ export {
266
+ ce as B,
267
+ xe as C,
268
+ be as I,
269
+ me as T,
270
+ ue as a,
271
+ G as b,
272
+ fe as c,
273
+ ve as d,
274
+ de as e,
275
+ U as g
276
+ };