zabi-components 5.0.15 → 5.0.18
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 +175 -23
- package/dist/SSRSafe.svelte +0 -3
- package/dist/atoms/Badge.svelte +32 -47
- package/dist/atoms/Badge.svelte.d.ts +6 -5
- package/dist/atoms/Button.svelte +18 -17
- package/dist/atoms/Button.svelte.d.ts +3 -2
- package/dist/atoms/Card.svelte +74 -23
- package/dist/atoms/Card.svelte.d.ts +3 -1
- package/dist/atoms/CardContent.svelte +24 -0
- package/dist/atoms/CardContent.svelte.d.ts +8 -0
- package/dist/atoms/CardDescription.svelte +24 -0
- package/dist/atoms/CardDescription.svelte.d.ts +8 -0
- package/dist/atoms/CardFooter.svelte +24 -0
- package/dist/atoms/CardFooter.svelte.d.ts +8 -0
- package/dist/atoms/CardHeader.svelte +24 -0
- package/dist/atoms/CardHeader.svelte.d.ts +8 -0
- package/dist/atoms/CardTitle.svelte +33 -0
- package/dist/atoms/CardTitle.svelte.d.ts +9 -0
- package/dist/atoms/Checkbox.svelte +19 -20
- package/dist/atoms/CodeBlock.svelte +4 -7
- package/dist/atoms/ColorPicker.svelte +33 -65
- package/dist/atoms/FeatureCard.svelte +2 -12
- package/dist/atoms/FeatureCard.svelte.d.ts +0 -8
- package/dist/atoms/Heading.svelte +0 -2
- package/dist/atoms/Input.svelte +8 -17
- package/dist/atoms/Input.svelte.d.ts +3 -2
- package/dist/atoms/Progress.svelte +1 -4
- package/dist/atoms/Select.svelte +37 -28
- package/dist/atoms/Skeleton.svelte +1 -1
- package/dist/atoms/Textarea.svelte +5 -11
- package/dist/atoms/Textarea.svelte.d.ts +3 -1
- package/dist/atoms/ThemeToggle.svelte +5 -12
- package/dist/atoms/Toast.svelte +1 -2
- package/dist/atoms/Toggle.svelte +2 -10
- package/dist/atoms/Tooltip.svelte +123 -26
- package/dist/atoms/index.d.ts +5 -0
- package/dist/atoms/index.js +5 -1
- package/dist/components/atoms/index.d.ts +5 -0
- package/dist/components/atoms/index.d.ts.map +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/molecules/index.d.ts.map +1 -1
- package/dist/components/organisms/index.d.ts.map +1 -1
- package/dist/index.js +0 -23
- package/dist/molecules/Alert.svelte +9 -13
- package/dist/molecules/Alert.svelte.d.ts +2 -1
- package/dist/molecules/ComponentDemo.svelte +55 -64
- package/dist/molecules/ContactForm.svelte +21 -12
- package/dist/molecules/Dropdown.svelte +104 -8
- package/dist/molecules/Dropdown.svelte.d.ts +1 -0
- package/dist/molecules/Form.svelte +0 -1
- package/dist/molecules/ImageUpload.svelte +2 -6
- package/dist/molecules/Modal.svelte +30 -6
- package/dist/molecules/SlideUp.svelte +2 -4
- package/dist/molecules/Tabs.svelte +2 -4
- package/dist/molecules/index.js +0 -1
- package/dist/organisms/Navbar.svelte +1 -8
- package/dist/organisms/Navigation.svelte +0 -6
- package/dist/organisms/index.js +0 -1
- package/dist/routes/lib/variant-utils.ts +7 -5
- package/dist/zabi-components-colors.css +287 -211
- package/dist/zabi-components-theme-dark-only.css +158 -0
- package/dist/zabi-components-theme-dark.css +160 -0
- package/dist/zabi-components-theme-only.css +235 -0
- package/dist/zabi-components-theme.css +237 -0
- package/dist/zabi-components.css +575 -360
- package/package.json +15 -5
package/README.md
CHANGED
|
@@ -40,6 +40,57 @@ npm install svelte@^5.38.10
|
|
|
40
40
|
npm install @sveltejs/kit@^2.0.0 # Optional, for SvelteKit projects
|
|
41
41
|
```
|
|
42
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):**
|
|
59
|
+
|
|
60
|
+
```css
|
|
61
|
+
/* app.css */
|
|
62
|
+
@import 'zabi-components/theme';
|
|
63
|
+
@import 'zabi-components/dist/zabi-components.css';
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### With Dark Mode
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
@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';
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Extending the Theme
|
|
76
|
+
|
|
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
|
+
|
|
43
94
|
## Import Methods
|
|
44
95
|
|
|
45
96
|
Zabi Components supports multiple import patterns:
|
|
@@ -168,16 +219,16 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
|
|
|
168
219
|
|
|
169
220
|
| Component | Category | Description | Key Features |
|
|
170
221
|
|-----------|----------|-------------|--------------|
|
|
171
|
-
| **Card** | Atom | Clean card container | Simple, interactive, image support |
|
|
222
|
+
| **Card** | Atom | Clean card container | Simple, interactive, image support, compound components, 4 variants |
|
|
172
223
|
| **Form** | Molecule | Simple form wrapper | FormData handling, clean API |
|
|
173
224
|
| **Layout** | Molecule | Page layout system | Header, main, footer slots |
|
|
174
225
|
| **Navigation** | Organism | Clean navigation | Header/sidebar variants, active state |
|
|
175
|
-
| **Button** | Atom | Action button |
|
|
226
|
+
| **Button** | Atom | Action button | 6 variants (primary, secondary, danger, ghost, outline, link) |
|
|
176
227
|
| **Input** | Atom | Form input | Essential props, accessibility |
|
|
177
228
|
| **Badge** | Atom | Status indicator | 5 color variants, closable |
|
|
178
|
-
| **Modal** | Molecule | Overlay dialog |
|
|
229
|
+
| **Modal** | Molecule | Overlay dialog | Focus trap, keyboard navigation, focus return |
|
|
179
230
|
| **Tabs** | Molecule | Tab navigation | Keyboard navigation, 2 variants |
|
|
180
|
-
| **Dropdown** | Molecule | Dropdown menu | CSS-only positioning |
|
|
231
|
+
| **Dropdown** | Molecule | Dropdown menu | CSS-only positioning, keyboard navigation, ARIA support |
|
|
181
232
|
| **ImageUpload** | Molecule | File upload | Direct selection, preview |
|
|
182
233
|
| **Navbar** | Organism | Navigation bar | Mobile menu, responsive |
|
|
183
234
|
|
|
@@ -461,35 +512,67 @@ All components will automatically switch to their dark mode variants without any
|
|
|
461
512
|
|
|
462
513
|
### Card Component
|
|
463
514
|
|
|
515
|
+
Card component supports two APIs: prop-based (backward compatible) and compound components (recommended).
|
|
516
|
+
|
|
517
|
+
#### Prop-based API (Backward Compatible)
|
|
518
|
+
|
|
464
519
|
```svelte
|
|
465
520
|
<Card
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
521
|
+
title="Card Title"
|
|
522
|
+
description="Card description"
|
|
523
|
+
image="image-url.jpg"
|
|
524
|
+
variant="default" | "elevated" | "outlined" | "flat"
|
|
525
|
+
size="sm" | "md" | "lg"
|
|
526
|
+
fullWidth={boolean}
|
|
527
|
+
onclick={(e) => console.log('Card clicked', e)}
|
|
472
528
|
>
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
529
|
+
Additional Content
|
|
530
|
+
</Card>
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
#### Compound Component API (Recommended)
|
|
534
|
+
|
|
535
|
+
```svelte
|
|
536
|
+
<Card variant="elevated">
|
|
537
|
+
<CardHeader>
|
|
538
|
+
<CardTitle>Card Title</CardTitle>
|
|
539
|
+
<CardDescription>Card description</CardDescription>
|
|
540
|
+
</CardHeader>
|
|
541
|
+
<CardContent>
|
|
542
|
+
Main content goes here
|
|
543
|
+
</CardContent>
|
|
544
|
+
<CardFooter>
|
|
545
|
+
<Button variant="primary">Action</Button>
|
|
546
|
+
</CardFooter>
|
|
476
547
|
</Card>
|
|
477
548
|
```
|
|
478
549
|
|
|
479
550
|
**Props:**
|
|
480
551
|
- `variant`: Card style variant (default: "default")
|
|
481
|
-
- `
|
|
482
|
-
- `
|
|
483
|
-
- `
|
|
484
|
-
- `
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
- `
|
|
488
|
-
- `
|
|
489
|
-
- `
|
|
552
|
+
- `default`: Standard card with subtle shadow
|
|
553
|
+
- `elevated`: Card with stronger shadow (elevated appearance)
|
|
554
|
+
- `outlined`: Card with border, no shadow
|
|
555
|
+
- `flat`: Card with no shadow, no border (minimal)
|
|
556
|
+
- `size`: Card size (default: "md")
|
|
557
|
+
- `fullWidth`: Whether card takes full width (default: true)
|
|
558
|
+
- `title`: Card title (old API)
|
|
559
|
+
- `description`: Card description (old API)
|
|
560
|
+
- `image`: Card image URL (old API)
|
|
561
|
+
- `onclick`: Click handler for interactive cards
|
|
562
|
+
|
|
563
|
+
**Compound Components:**
|
|
564
|
+
- `CardHeader`: Header section container
|
|
565
|
+
- `CardContent`: Main content area
|
|
566
|
+
- `CardFooter`: Footer section container
|
|
567
|
+
- `CardTitle`: Title component (supports heading levels 1-6)
|
|
568
|
+
- `CardDescription`: Description text component
|
|
490
569
|
|
|
491
570
|
**Events:**
|
|
492
|
-
- `
|
|
571
|
+
- `onclick`: Native click event - `MouseEvent`
|
|
572
|
+
|
|
573
|
+
**Keyboard Navigation (Interactive Cards):**
|
|
574
|
+
- **Tab**: Focus the card
|
|
575
|
+
- **Enter / Space**: Activate card click handler
|
|
493
576
|
|
|
494
577
|
### Alert Component
|
|
495
578
|
|
|
@@ -1147,6 +1230,75 @@ function handleFormSubmit(event: any) {
|
|
|
1147
1230
|
- Test with screen readers
|
|
1148
1231
|
- Maintain proper color contrast ratios
|
|
1149
1232
|
|
|
1233
|
+
## Compound Components
|
|
1234
|
+
|
|
1235
|
+
Zabi Components supports compound component patterns for flexible composition:
|
|
1236
|
+
|
|
1237
|
+
### Card Compound Components
|
|
1238
|
+
|
|
1239
|
+
```svelte
|
|
1240
|
+
<script>
|
|
1241
|
+
import { Card, CardHeader, CardContent, CardFooter, CardTitle, CardDescription, Button } from 'zabi-components';
|
|
1242
|
+
</script>
|
|
1243
|
+
|
|
1244
|
+
<Card variant="elevated">
|
|
1245
|
+
<CardHeader>
|
|
1246
|
+
<CardTitle>Card Title</CardTitle>
|
|
1247
|
+
<CardDescription>
|
|
1248
|
+
This is a description using compound components.
|
|
1249
|
+
</CardDescription>
|
|
1250
|
+
</CardHeader>
|
|
1251
|
+
<CardContent>
|
|
1252
|
+
<p>Main content area with flexible composition.</p>
|
|
1253
|
+
</CardContent>
|
|
1254
|
+
<CardFooter>
|
|
1255
|
+
<Button variant="primary">Save</Button>
|
|
1256
|
+
<Button variant="ghost">Cancel</Button>
|
|
1257
|
+
</CardFooter>
|
|
1258
|
+
</Card>
|
|
1259
|
+
```
|
|
1260
|
+
|
|
1261
|
+
## Accessibility
|
|
1262
|
+
|
|
1263
|
+
Zabi Components is built with accessibility in mind:
|
|
1264
|
+
|
|
1265
|
+
### WCAG 2.1 AA Compliance
|
|
1266
|
+
- Comprehensive ARIA attributes
|
|
1267
|
+
- Proper semantic HTML
|
|
1268
|
+
- Keyboard navigation support
|
|
1269
|
+
- Focus management
|
|
1270
|
+
- Screen reader compatibility
|
|
1271
|
+
|
|
1272
|
+
### Keyboard Navigation
|
|
1273
|
+
- **Tab**: Navigate between interactive elements
|
|
1274
|
+
- **Enter/Space**: Activate buttons and links
|
|
1275
|
+
- **Arrow Keys**: Navigate within components (Tabs, Navigation, Dropdown)
|
|
1276
|
+
- **Escape**: Close modals and overlays
|
|
1277
|
+
- **Home/End**: Jump to first/last item in lists
|
|
1278
|
+
|
|
1279
|
+
### Focus Management
|
|
1280
|
+
- Focus trap in modals
|
|
1281
|
+
- Focus return after closing modals
|
|
1282
|
+
- Visible focus indicators
|
|
1283
|
+
- Logical tab order
|
|
1284
|
+
|
|
1285
|
+
See [ACCESSIBILITY.md](./docs/ACCESSIBILITY.md) and [KEYBOARD_NAVIGATION.md](./docs/KEYBOARD_NAVIGATION.md) for detailed documentation.
|
|
1286
|
+
|
|
1287
|
+
## Variant System
|
|
1288
|
+
|
|
1289
|
+
Zabi Components uses a consistent variant system:
|
|
1290
|
+
|
|
1291
|
+
### Semantic Variants
|
|
1292
|
+
Used for state indication: `default`, `success`, `warning`, `error`, `info`
|
|
1293
|
+
|
|
1294
|
+
### Style Variants
|
|
1295
|
+
Used for visual appearance: Button (`primary`, `secondary`, `outline`, `link`, etc.), Card (`elevated`, `outlined`, `flat`)
|
|
1296
|
+
|
|
1297
|
+
### Size Variants
|
|
1298
|
+
Consistent across components: `sm`, `md`, `lg`
|
|
1299
|
+
|
|
1300
|
+
See [VARIANTS.md](./docs/VARIANTS.md) for complete variant documentation.
|
|
1301
|
+
|
|
1150
1302
|
## Support
|
|
1151
1303
|
|
|
1152
1304
|
For support, please open an issue on GitHub or contact the maintainers.
|
package/dist/SSRSafe.svelte
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
<!-- SSR-safe wrapper component for zabi-components -->
|
|
2
1
|
<script lang="ts">
|
|
3
2
|
import { onMount } from "svelte";
|
|
4
3
|
|
|
@@ -33,7 +32,6 @@
|
|
|
33
32
|
{@render children?.()}
|
|
34
33
|
</FallbackComponent>
|
|
35
34
|
{:else}
|
|
36
|
-
<!-- Fallback content for SSR -->
|
|
37
35
|
<div class="zabi-ssr-fallback">
|
|
38
36
|
{@render children?.()}
|
|
39
37
|
</div>
|
|
@@ -41,7 +39,6 @@
|
|
|
41
39
|
|
|
42
40
|
<style>
|
|
43
41
|
.zabi-ssr-fallback {
|
|
44
|
-
/* Minimal styling for SSR fallback */
|
|
45
42
|
display: contents;
|
|
46
43
|
}
|
|
47
44
|
</style>
|
package/dist/atoms/Badge.svelte
CHANGED
|
@@ -1,96 +1,81 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
Badge Component - SSR-safe and robust
|
|
3
|
-
|
|
4
|
-
A simple badge component with proper SSR handling and defensive programming
|
|
5
|
-
to prevent DOM access errors during hydration and rapid state changes.
|
|
6
|
-
-->
|
|
7
1
|
<script lang="ts">
|
|
8
2
|
import { Check, AlertTriangle, X, Info } from "@lucide/svelte";
|
|
9
|
-
|
|
3
|
+
import type {
|
|
4
|
+
ExtendedSemanticVariant,
|
|
5
|
+
SizeVariant,
|
|
6
|
+
} from "../../types/variants.js";
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
variant?: ExtendedSemanticVariant;
|
|
10
|
+
size?: SizeVariant;
|
|
11
|
+
text: string;
|
|
12
|
+
showIcon?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
let {
|
|
11
16
|
variant = "default",
|
|
12
17
|
size = "md",
|
|
13
18
|
text = "",
|
|
14
|
-
showIcon =
|
|
15
|
-
}:
|
|
16
|
-
variant?:
|
|
17
|
-
| "default"
|
|
18
|
-
| "success"
|
|
19
|
-
| "warning"
|
|
20
|
-
| "error"
|
|
21
|
-
| "info"
|
|
22
|
-
| "neutral"
|
|
23
|
-
| "energetic";
|
|
24
|
-
size?: "sm" | "md" | "lg";
|
|
25
|
-
text: string;
|
|
26
|
-
showIcon?: boolean;
|
|
27
|
-
} = $props();
|
|
19
|
+
showIcon = false,
|
|
20
|
+
}: Props = $props();
|
|
28
21
|
|
|
29
|
-
// Class computation using conditional logic with full class names
|
|
30
22
|
const classes = $derived(() => {
|
|
31
23
|
const baseClasses =
|
|
32
|
-
"inline-flex items-center font-medium border rounded-
|
|
24
|
+
"inline-flex items-center font-medium border rounded-xs";
|
|
33
25
|
|
|
34
|
-
// Size classes - using full class names
|
|
35
26
|
const sizeClass =
|
|
36
27
|
size === "sm"
|
|
37
28
|
? "px-2 py-0.5 text-xs"
|
|
38
29
|
: size === "lg"
|
|
39
30
|
? "px-4 py-2 text-base"
|
|
40
|
-
: "px-3 py-1 text-sm";
|
|
31
|
+
: "px-3 py-1 text-sm";
|
|
41
32
|
|
|
42
|
-
// Variant classes - using semantic color system with improved WCAG contrast
|
|
43
|
-
// Using colored backgrounds with white text for better contrast ratios (4.5:1+)
|
|
44
|
-
// Using darker shades for warning and energetic to ensure WCAG AA compliance
|
|
45
|
-
// Note: Using text-white instead of text-inverse to ensure light text in both light and dark modes
|
|
46
33
|
const variantClass =
|
|
47
34
|
variant === "success"
|
|
48
|
-
? "bg-success border-success text-
|
|
35
|
+
? "bg-success border-success text-card"
|
|
49
36
|
: variant === "warning"
|
|
50
|
-
? "bg-warning border-warning text-
|
|
37
|
+
? "bg-warning border-warning text-card"
|
|
51
38
|
: variant === "error"
|
|
52
|
-
? "bg-error border-error text-
|
|
39
|
+
? "bg-error border-error text-card"
|
|
53
40
|
: variant === "info"
|
|
54
|
-
? "bg-info border-info text-
|
|
41
|
+
? "bg-info border-info text-card"
|
|
55
42
|
: variant === "neutral"
|
|
56
|
-
? "bg-neutral border-neutral text-
|
|
43
|
+
? "bg-neutral border-neutral text-card"
|
|
57
44
|
: variant === "energetic"
|
|
58
|
-
? "bg-energetic border-energetic text-
|
|
59
|
-
: "bg-secondary border-secondary text-
|
|
45
|
+
? "bg-energetic border-energetic text-card"
|
|
46
|
+
: "bg-secondary border-secondary text-card";
|
|
60
47
|
|
|
61
48
|
return `${baseClasses} ${sizeClass} ${variantClass}`.trim();
|
|
62
49
|
});
|
|
63
50
|
|
|
64
|
-
// Icon size based on badge size
|
|
65
51
|
const iconSize = $derived(() => {
|
|
66
|
-
return size === "sm" ? 12 : size === "lg" ? 20 : 16;
|
|
52
|
+
return size === "sm" ? 12 : size === "lg" ? 20 : 16;
|
|
67
53
|
});
|
|
68
54
|
|
|
69
|
-
// Icon spacing class
|
|
70
55
|
const iconSpacingClass = $derived(() => {
|
|
71
|
-
return size === "sm" ? "mr-1" : size === "lg" ? "mr-2" : "mr-1.5";
|
|
56
|
+
return size === "sm" ? "mr-1" : size === "lg" ? "mr-2" : "mr-1.5";
|
|
72
57
|
});
|
|
73
58
|
</script>
|
|
74
59
|
|
|
75
60
|
<span class={classes()}>
|
|
76
61
|
{#if showIcon}
|
|
77
62
|
{#if variant === "success"}
|
|
78
|
-
<Check size={iconSize()} class="{iconSpacingClass()} text-
|
|
63
|
+
<Check size={iconSize()} class="{iconSpacingClass()} text-card" />
|
|
79
64
|
{:else if variant === "warning"}
|
|
80
65
|
<AlertTriangle
|
|
81
66
|
size={iconSize()}
|
|
82
|
-
class="{iconSpacingClass()} text-
|
|
67
|
+
class="{iconSpacingClass()} text-card"
|
|
83
68
|
/>
|
|
84
69
|
{:else if variant === "error"}
|
|
85
|
-
<X size={iconSize()} class="{iconSpacingClass()} text-
|
|
70
|
+
<X size={iconSize()} class="{iconSpacingClass()} text-card" />
|
|
86
71
|
{:else if variant === "info"}
|
|
87
|
-
<Info size={iconSize()} class="{iconSpacingClass()} text-
|
|
72
|
+
<Info size={iconSize()} class="{iconSpacingClass()} text-card" />
|
|
88
73
|
{:else if variant === "neutral"}
|
|
89
|
-
<Info size={iconSize()} class="{iconSpacingClass()} text-
|
|
74
|
+
<Info size={iconSize()} class="{iconSpacingClass()} text-card" />
|
|
90
75
|
{:else if variant === "energetic"}
|
|
91
|
-
<Info size={iconSize()} class="{iconSpacingClass()} text-
|
|
76
|
+
<Info size={iconSize()} class="{iconSpacingClass()} text-card" />
|
|
92
77
|
{:else}
|
|
93
|
-
<Info size={iconSize()} class="{iconSpacingClass()} text-
|
|
78
|
+
<Info size={iconSize()} class="{iconSpacingClass()} text-card" />
|
|
94
79
|
{/if}
|
|
95
80
|
{/if}
|
|
96
81
|
{text}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { ExtendedSemanticVariant, SizeVariant } from "../../types/variants.js";
|
|
2
|
+
interface Props {
|
|
3
|
+
variant?: ExtendedSemanticVariant;
|
|
4
|
+
size?: SizeVariant;
|
|
4
5
|
text: string;
|
|
5
6
|
showIcon?: boolean;
|
|
6
|
-
}
|
|
7
|
-
declare const Badge: import("svelte").Component
|
|
7
|
+
}
|
|
8
|
+
declare const Badge: import("svelte").Component<Props, {}, "">;
|
|
8
9
|
type Badge = ReturnType<typeof Badge>;
|
|
9
10
|
export default Badge;
|
package/dist/atoms/Button.svelte
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
|
+
import type { ButtonVariant, SizeVariant } from "../../types/variants.js";
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
|
-
variant?:
|
|
6
|
-
size?:
|
|
6
|
+
variant?: ButtonVariant;
|
|
7
|
+
size?: SizeVariant;
|
|
7
8
|
disabled?: boolean;
|
|
8
9
|
type?: "button" | "submit" | "reset";
|
|
9
10
|
text?: string;
|
|
@@ -22,7 +23,6 @@
|
|
|
22
23
|
...restProps
|
|
23
24
|
}: Props = $props();
|
|
24
25
|
|
|
25
|
-
// Size classes matching M3 design specifications
|
|
26
26
|
const sizeClass = $derived(() => {
|
|
27
27
|
if (size === "sm") {
|
|
28
28
|
return {
|
|
@@ -32,46 +32,47 @@
|
|
|
32
32
|
leading: "leading-5",
|
|
33
33
|
tracking: "tracking-[0.1px]",
|
|
34
34
|
radius: "rounded-lg",
|
|
35
|
-
gap: "gap-2"
|
|
35
|
+
gap: "gap-2",
|
|
36
36
|
};
|
|
37
37
|
} else if (size === "lg") {
|
|
38
38
|
return {
|
|
39
|
-
padding: "px-
|
|
40
|
-
text: "text-
|
|
39
|
+
padding: "px-8 py-4",
|
|
40
|
+
text: "text-lg",
|
|
41
41
|
font: "font-normal",
|
|
42
42
|
leading: "leading-8",
|
|
43
43
|
tracking: "tracking-normal",
|
|
44
|
-
radius: "rounded-
|
|
45
|
-
gap: "gap-3"
|
|
44
|
+
radius: "rounded-xl",
|
|
45
|
+
gap: "gap-3",
|
|
46
46
|
};
|
|
47
47
|
} else {
|
|
48
|
-
// default md
|
|
49
48
|
return {
|
|
50
|
-
padding: "px-
|
|
49
|
+
padding: "px-5 py-3",
|
|
51
50
|
text: "text-base",
|
|
52
51
|
font: "font-medium",
|
|
53
52
|
leading: "leading-6",
|
|
54
53
|
tracking: "tracking-[0.15px]",
|
|
55
54
|
radius: "rounded-lg",
|
|
56
|
-
gap: "gap-2"
|
|
55
|
+
gap: "gap-2",
|
|
57
56
|
};
|
|
58
57
|
}
|
|
59
58
|
});
|
|
60
59
|
|
|
61
|
-
// Variant classes using semantic action colors
|
|
62
60
|
const variantClass = $derived(() => {
|
|
63
61
|
return variant === "primary"
|
|
64
|
-
? "bg-action-primary text-
|
|
62
|
+
? "bg-action-primary text-action-primary hover:bg-action-primary-hover active:bg-action-primary-active focus:ring-2 focus:ring-brand-500 focus:ring-offset-2"
|
|
65
63
|
: variant === "secondary"
|
|
66
|
-
? "bg-
|
|
64
|
+
? "bg-action-secondary text-headline hover:bg-action-secondary-hover active:bg-action-secondary-active focus:ring-2 focus:ring-brand-500 focus:ring-offset-2"
|
|
67
65
|
: variant === "danger"
|
|
68
66
|
? "bg-action-danger text-inverse hover:bg-action-danger-hover active:bg-action-danger-active focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
|
69
67
|
: variant === "ghost"
|
|
70
|
-
? "bg-transparent text-headline hover:bg-
|
|
71
|
-
:
|
|
68
|
+
? "bg-transparent text-headline hover:bg-base-100 active:bg-base-200 focus:ring-2 focus:ring-base-500 focus:ring-offset-2 disabled:text-disabled"
|
|
69
|
+
: variant === "outline"
|
|
70
|
+
? "bg-transparent border-2 border-action-primary text-headline hover:bg-action-secondary hover:text-action-primary active:bg-action-primary-active active:text-action-primary focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 disabled:border-disabled disabled:text-disabled"
|
|
71
|
+
: variant === "link"
|
|
72
|
+
? "text-brand-700 active:text-brand-700 underline-offset-4 hover:underline focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 disabled:text-disabled disabled:no-underline"
|
|
73
|
+
: "bg-action-primary text-action-primary hover:bg-action-primary-hover active:bg-action-primary-active focus:ring-2 focus:ring-brand-500 focus:ring-offset-2";
|
|
72
74
|
});
|
|
73
75
|
|
|
74
|
-
// Button classes matching M3 design pattern
|
|
75
76
|
const buttonClasses = $derived(() => {
|
|
76
77
|
const sizeStyles = sizeClass();
|
|
77
78
|
const baseClasses =
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
|
+
import type { ButtonVariant, SizeVariant } from "../../types/variants.js";
|
|
2
3
|
interface Props {
|
|
3
|
-
variant?:
|
|
4
|
-
size?:
|
|
4
|
+
variant?: ButtonVariant;
|
|
5
|
+
size?: SizeVariant;
|
|
5
6
|
disabled?: boolean;
|
|
6
7
|
type?: "button" | "submit" | "reset";
|
|
7
8
|
text?: string;
|
package/dist/atoms/Card.svelte
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
|
+
import type { CardVariant, SizeVariant } from "../../types/variants.js";
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
title?: string;
|
|
6
7
|
description?: string;
|
|
7
8
|
image?: string;
|
|
8
9
|
onclick?: (event: MouseEvent) => void | Promise<void>;
|
|
9
|
-
size?:
|
|
10
|
+
size?: SizeVariant;
|
|
11
|
+
variant?: CardVariant;
|
|
10
12
|
fullWidth?: boolean;
|
|
11
13
|
children?: Snippet;
|
|
12
14
|
}
|
|
@@ -17,24 +19,48 @@
|
|
|
17
19
|
image = "",
|
|
18
20
|
onclick,
|
|
19
21
|
size = "md",
|
|
22
|
+
variant = "default",
|
|
20
23
|
fullWidth = true,
|
|
21
24
|
children,
|
|
22
25
|
...restProps
|
|
23
26
|
}: Props = $props();
|
|
24
27
|
|
|
25
28
|
const sizeClass = $derived(() => {
|
|
26
|
-
return size === "sm" ? "p-4" : size === "lg" ? "p-8" : "p-6";
|
|
29
|
+
return size === "sm" ? "p-4" : size === "lg" ? "p-8" : "p-6";
|
|
27
30
|
});
|
|
28
31
|
|
|
32
|
+
const variantClasses = $derived(() => {
|
|
33
|
+
switch (variant) {
|
|
34
|
+
case "elevated":
|
|
35
|
+
return "bg-card shadow-lg";
|
|
36
|
+
case "outlined":
|
|
37
|
+
return "bg-card border-2 border-base-200 shadow-none";
|
|
38
|
+
case "flat":
|
|
39
|
+
return "bg-card shadow-none border-none";
|
|
40
|
+
default:
|
|
41
|
+
return "bg-card shadow-sm";
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const useOldAPI = $derived(title !== "" || description !== "" || image !== "");
|
|
46
|
+
|
|
29
47
|
const cardClasses = $derived(() => {
|
|
30
48
|
const baseClasses =
|
|
31
|
-
|
|
49
|
+
`rounded-lg transition-all duration-200 ${variantClasses()}`;
|
|
32
50
|
const interactiveClasses = onclick
|
|
33
|
-
?
|
|
51
|
+
? variant === "elevated"
|
|
52
|
+
? "cursor-pointer hover:shadow-xl hover:bg-card-hover"
|
|
53
|
+
: variant === "outlined"
|
|
54
|
+
? "cursor-pointer hover:border-brand-500 hover:bg-card-hover"
|
|
55
|
+
: variant === "flat"
|
|
56
|
+
? "cursor-pointer hover:bg-card-hover"
|
|
57
|
+
: "cursor-pointer hover:shadow-lg hover:bg-card-hover"
|
|
34
58
|
: "";
|
|
35
59
|
const widthClasses = fullWidth ? "w-full" : "";
|
|
60
|
+
const minWidthClass = useOldAPI ? "min-w-64" : "";
|
|
61
|
+
const paddingClass = useOldAPI ? sizeClass() : "";
|
|
36
62
|
|
|
37
|
-
return `${baseClasses} ${interactiveClasses} ${widthClasses} ${
|
|
63
|
+
return `${baseClasses} ${interactiveClasses} ${widthClasses} ${minWidthClass} ${paddingClass}`.trim();
|
|
38
64
|
});
|
|
39
65
|
|
|
40
66
|
const titleClasses = $derived(() => {
|
|
@@ -43,7 +69,6 @@
|
|
|
43
69
|
} else if (size === "lg") {
|
|
44
70
|
return "text-2xl font-medium mb-4 text-headline";
|
|
45
71
|
} else {
|
|
46
|
-
// default md
|
|
47
72
|
return "text-xl font-medium mb-3 text-headline";
|
|
48
73
|
}
|
|
49
74
|
});
|
|
@@ -54,30 +79,56 @@
|
|
|
54
79
|
} else if (size === "lg") {
|
|
55
80
|
return "text-base text-description mb-5";
|
|
56
81
|
} else {
|
|
57
|
-
// default md
|
|
58
82
|
return "text-sm text-description mb-4";
|
|
59
83
|
}
|
|
60
84
|
});
|
|
85
|
+
|
|
86
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
87
|
+
if (onclick && (event.key === "Enter" || event.key === " ")) {
|
|
88
|
+
event.preventDefault();
|
|
89
|
+
onclick(event as unknown as MouseEvent);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const cardRole = $derived(onclick ? "button" : undefined);
|
|
94
|
+
const cardTabIndex = $derived(onclick ? 0 : undefined);
|
|
95
|
+
const cardAriaLabel = $derived(onclick && title ? title : undefined);
|
|
61
96
|
</script>
|
|
62
97
|
|
|
63
|
-
<div
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
{
|
|
98
|
+
<div
|
|
99
|
+
class={cardClasses()}
|
|
100
|
+
{onclick}
|
|
101
|
+
role={cardRole}
|
|
102
|
+
tabindex={cardTabIndex}
|
|
103
|
+
aria-label={cardAriaLabel}
|
|
104
|
+
onkeydown={handleKeydown}
|
|
105
|
+
{...restProps}
|
|
106
|
+
>
|
|
107
|
+
{#if useOldAPI}
|
|
108
|
+
<!-- Old API: Using title/description/image props -->
|
|
109
|
+
{#if image}
|
|
110
|
+
<img
|
|
111
|
+
src={image}
|
|
112
|
+
alt={title}
|
|
113
|
+
class="w-full h-48 object-cover rounded-lg mb-4"
|
|
114
|
+
/>
|
|
115
|
+
{/if}
|
|
71
116
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
117
|
+
{#if title}
|
|
118
|
+
<h3 class={titleClasses()}>{title}</h3>
|
|
119
|
+
{/if}
|
|
75
120
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
121
|
+
{#if description}
|
|
122
|
+
<p class={descriptionClasses()}>{description}</p>
|
|
123
|
+
{/if}
|
|
79
124
|
|
|
80
|
-
|
|
81
|
-
|
|
125
|
+
{#if children}
|
|
126
|
+
{@render children()}
|
|
127
|
+
{/if}
|
|
128
|
+
{:else}
|
|
129
|
+
<!-- New API: Using compound components (CardHeader, CardContent, CardFooter) -->
|
|
130
|
+
{#if children}
|
|
131
|
+
{@render children()}
|
|
132
|
+
{/if}
|
|
82
133
|
{/if}
|
|
83
134
|
</div>
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
|
+
import type { CardVariant, SizeVariant } from "../../types/variants.js";
|
|
2
3
|
interface Props {
|
|
3
4
|
title?: string;
|
|
4
5
|
description?: string;
|
|
5
6
|
image?: string;
|
|
6
7
|
onclick?: (event: MouseEvent) => void | Promise<void>;
|
|
7
|
-
size?:
|
|
8
|
+
size?: SizeVariant;
|
|
9
|
+
variant?: CardVariant;
|
|
8
10
|
fullWidth?: boolean;
|
|
9
11
|
children?: Snippet;
|
|
10
12
|
}
|