zabi-components 5.0.17 → 5.0.19
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 +124 -23
- package/dist/SSRSafe.svelte +0 -3
- package/dist/atoms/Badge.svelte +19 -34
- package/dist/atoms/Badge.svelte.d.ts +6 -5
- package/dist/atoms/Button.svelte +10 -9
- 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 +0 -4
- package/dist/atoms/CodeBlock.svelte +0 -3
- package/dist/atoms/ColorPicker.svelte +33 -65
- package/dist/atoms/FeatureCard.svelte +0 -10
- package/dist/atoms/FeatureCard.svelte.d.ts +0 -8
- package/dist/atoms/Heading.svelte +0 -2
- package/dist/atoms/Input.svelte +3 -12
- package/dist/atoms/Input.svelte.d.ts +3 -2
- package/dist/atoms/Progress.svelte +0 -3
- package/dist/atoms/Select.svelte +0 -14
- package/dist/atoms/Textarea.svelte +3 -9
- package/dist/atoms/Textarea.svelte.d.ts +3 -1
- package/dist/atoms/ThemeToggle.svelte +0 -7
- package/dist/atoms/Toast.svelte +0 -1
- package/dist/atoms/Toggle.svelte +0 -6
- package/dist/atoms/Tooltip.svelte +0 -12
- 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 +3 -13
- package/dist/molecules/Alert.svelte.d.ts +2 -1
- package/dist/molecules/ComponentDemo.svelte +0 -2
- package/dist/molecules/ContactForm.svelte +21 -12
- package/dist/molecules/Dropdown.svelte +100 -6
- package/dist/molecules/Dropdown.svelte.d.ts +1 -0
- package/dist/molecules/Form.svelte +0 -1
- package/dist/molecules/ImageUpload.svelte +0 -4
- package/dist/molecules/Modal.svelte +29 -5
- package/dist/molecules/SlideUp.svelte +0 -2
- package/dist/molecules/Tabs.svelte +0 -2
- package/dist/molecules/index.js +0 -1
- package/dist/organisms/Navbar.svelte +0 -7
- package/dist/organisms/Navigation.svelte +0 -6
- package/dist/organisms/index.js +0 -1
- package/dist/routes/lib/focus-utils.d.ts +23 -0
- package/dist/routes/lib/focus-utils.ts +112 -0
- package/dist/routes/lib/variant-utils.ts +3 -1
- package/dist/zabi-components-colors.css +246 -178
- package/dist/zabi-components-theme-dark-only.css +11 -2
- package/dist/zabi-components-theme-dark.css +11 -2
- package/dist/zabi-components-theme-only.css +32 -24
- package/dist/zabi-components-theme.css +32 -24
- package/dist/zabi-components.css +259 -83
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -219,16 +219,16 @@ import type { ButtonEvents, InputEvents } from 'zabi-components/types';
|
|
|
219
219
|
|
|
220
220
|
| Component | Category | Description | Key Features |
|
|
221
221
|
|-----------|----------|-------------|--------------|
|
|
222
|
-
| **Card** | Atom | Clean card container | Simple, interactive, image support |
|
|
222
|
+
| **Card** | Atom | Clean card container | Simple, interactive, image support, compound components, 4 variants |
|
|
223
223
|
| **Form** | Molecule | Simple form wrapper | FormData handling, clean API |
|
|
224
224
|
| **Layout** | Molecule | Page layout system | Header, main, footer slots |
|
|
225
225
|
| **Navigation** | Organism | Clean navigation | Header/sidebar variants, active state |
|
|
226
|
-
| **Button** | Atom | Action button |
|
|
226
|
+
| **Button** | Atom | Action button | 6 variants (primary, secondary, danger, ghost, outline, link) |
|
|
227
227
|
| **Input** | Atom | Form input | Essential props, accessibility |
|
|
228
228
|
| **Badge** | Atom | Status indicator | 5 color variants, closable |
|
|
229
|
-
| **Modal** | Molecule | Overlay dialog |
|
|
229
|
+
| **Modal** | Molecule | Overlay dialog | Focus trap, keyboard navigation, focus return |
|
|
230
230
|
| **Tabs** | Molecule | Tab navigation | Keyboard navigation, 2 variants |
|
|
231
|
-
| **Dropdown** | Molecule | Dropdown menu | CSS-only positioning |
|
|
231
|
+
| **Dropdown** | Molecule | Dropdown menu | CSS-only positioning, keyboard navigation, ARIA support |
|
|
232
232
|
| **ImageUpload** | Molecule | File upload | Direct selection, preview |
|
|
233
233
|
| **Navbar** | Organism | Navigation bar | Mobile menu, responsive |
|
|
234
234
|
|
|
@@ -512,35 +512,67 @@ All components will automatically switch to their dark mode variants without any
|
|
|
512
512
|
|
|
513
513
|
### Card Component
|
|
514
514
|
|
|
515
|
+
Card component supports two APIs: prop-based (backward compatible) and compound components (recommended).
|
|
516
|
+
|
|
517
|
+
#### Prop-based API (Backward Compatible)
|
|
518
|
+
|
|
515
519
|
```svelte
|
|
516
520
|
<Card
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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)}
|
|
523
528
|
>
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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>
|
|
527
547
|
</Card>
|
|
528
548
|
```
|
|
529
549
|
|
|
530
550
|
**Props:**
|
|
531
551
|
- `variant`: Card style variant (default: "default")
|
|
532
|
-
- `
|
|
533
|
-
- `
|
|
534
|
-
- `
|
|
535
|
-
- `
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
- `
|
|
539
|
-
- `
|
|
540
|
-
- `
|
|
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
|
|
541
569
|
|
|
542
570
|
**Events:**
|
|
543
|
-
- `
|
|
571
|
+
- `onclick`: Native click event - `MouseEvent`
|
|
572
|
+
|
|
573
|
+
**Keyboard Navigation (Interactive Cards):**
|
|
574
|
+
- **Tab**: Focus the card
|
|
575
|
+
- **Enter / Space**: Activate card click handler
|
|
544
576
|
|
|
545
577
|
### Alert Component
|
|
546
578
|
|
|
@@ -1198,6 +1230,75 @@ function handleFormSubmit(event: any) {
|
|
|
1198
1230
|
- Test with screen readers
|
|
1199
1231
|
- Maintain proper color contrast ratios
|
|
1200
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
|
+
|
|
1201
1302
|
## Support
|
|
1202
1303
|
|
|
1203
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,48 +1,35 @@
|
|
|
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
35
|
? "bg-success border-success text-card"
|
|
@@ -56,19 +43,17 @@
|
|
|
56
43
|
? "bg-neutral border-neutral text-card"
|
|
57
44
|
: variant === "energetic"
|
|
58
45
|
? "bg-energetic border-energetic text-card"
|
|
59
|
-
: "bg-secondary border-secondary 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
|
|
|
@@ -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 {
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
gap: "gap-3",
|
|
46
46
|
};
|
|
47
47
|
} else {
|
|
48
|
-
// default md
|
|
49
48
|
return {
|
|
50
49
|
padding: "px-5 py-3",
|
|
51
50
|
text: "text-base",
|
|
@@ -58,20 +57,22 @@
|
|
|
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
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"
|
|
71
|
-
:
|
|
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
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
className?: string;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
className = "",
|
|
11
|
+
children,
|
|
12
|
+
...restProps
|
|
13
|
+
}: Props = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div
|
|
17
|
+
class="p-6 pt-0 {className}"
|
|
18
|
+
{...restProps}
|
|
19
|
+
>
|
|
20
|
+
{#if children}
|
|
21
|
+
{@render children()}
|
|
22
|
+
{/if}
|
|
23
|
+
</div>
|
|
24
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
className?: string;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
className = "",
|
|
11
|
+
children,
|
|
12
|
+
...restProps
|
|
13
|
+
}: Props = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<p
|
|
17
|
+
class="text-sm text-description {className}"
|
|
18
|
+
{...restProps}
|
|
19
|
+
>
|
|
20
|
+
{#if children}
|
|
21
|
+
{@render children()}
|
|
22
|
+
{/if}
|
|
23
|
+
</p>
|
|
24
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
interface Props {
|
|
3
|
+
className?: string;
|
|
4
|
+
children?: Snippet;
|
|
5
|
+
}
|
|
6
|
+
declare const CardDescription: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type CardDescription = ReturnType<typeof CardDescription>;
|
|
8
|
+
export default CardDescription;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
className?: string;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
className = "",
|
|
11
|
+
children,
|
|
12
|
+
...restProps
|
|
13
|
+
}: Props = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<footer
|
|
17
|
+
class="flex items-center p-6 pt-0 {className}"
|
|
18
|
+
{...restProps}
|
|
19
|
+
>
|
|
20
|
+
{#if children}
|
|
21
|
+
{@render children()}
|
|
22
|
+
{/if}
|
|
23
|
+
</footer>
|
|
24
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
className?: string;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
className = "",
|
|
11
|
+
children,
|
|
12
|
+
...restProps
|
|
13
|
+
}: Props = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<header
|
|
17
|
+
class="flex flex-col space-y-1.5 p-6 {className}"
|
|
18
|
+
{...restProps}
|
|
19
|
+
>
|
|
20
|
+
{#if children}
|
|
21
|
+
{@render children()}
|
|
22
|
+
{/if}
|
|
23
|
+
</header>
|
|
24
|
+
|