zabi-components 4.0.0 → 5.0.1

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 (89) hide show
  1. package/README.md +70 -2
  2. package/dist/SSRSafe.svelte +47 -0
  3. package/dist/SSRSafe.svelte.d.ts +11 -0
  4. package/dist/atoms/Badge.svelte +76 -0
  5. package/dist/atoms/Badge.svelte.d.ts +9 -0
  6. package/dist/atoms/Button.svelte +72 -0
  7. package/dist/atoms/Button.svelte.d.ts +13 -0
  8. package/dist/atoms/Card.svelte +59 -0
  9. package/dist/atoms/Card.svelte.d.ts +12 -0
  10. package/dist/atoms/Checkbox.svelte +60 -0
  11. package/dist/atoms/Checkbox.svelte.d.ts +10 -0
  12. package/dist/atoms/CodeBlock.svelte +125 -0
  13. package/dist/atoms/CodeBlock.svelte.d.ts +8 -0
  14. package/dist/atoms/ColorPicker.svelte +171 -0
  15. package/dist/atoms/ColorPicker.svelte.d.ts +9 -0
  16. package/dist/atoms/FeatureCard.svelte +74 -0
  17. package/dist/atoms/FeatureCard.svelte.d.ts +17 -0
  18. package/dist/atoms/Heading.svelte +5 -0
  19. package/dist/atoms/Heading.svelte.d.ts +7 -0
  20. package/dist/atoms/Input.svelte +98 -0
  21. package/dist/atoms/Input.svelte.d.ts +14 -0
  22. package/dist/atoms/OptimizedImage.svelte +32 -0
  23. package/dist/atoms/OptimizedImage.svelte.d.ts +13 -0
  24. package/dist/atoms/Progress.svelte +61 -0
  25. package/dist/atoms/Progress.svelte.d.ts +9 -0
  26. package/dist/atoms/Select.svelte +85 -0
  27. package/dist/atoms/Select.svelte.d.ts +16 -0
  28. package/dist/atoms/Skeleton.svelte +20 -0
  29. package/dist/atoms/Skeleton.svelte.d.ts +8 -0
  30. package/dist/atoms/Textarea.svelte +116 -0
  31. package/dist/atoms/Textarea.svelte.d.ts +14 -0
  32. package/dist/atoms/ThemeToggle.svelte +89 -0
  33. package/dist/atoms/ThemeToggle.svelte.d.ts +7 -0
  34. package/dist/atoms/Toast.svelte +58 -0
  35. package/dist/atoms/Toast.svelte.d.ts +9 -0
  36. package/dist/atoms/Toggle.svelte +94 -0
  37. package/dist/atoms/Toggle.svelte.d.ts +12 -0
  38. package/dist/atoms/Tooltip.svelte +188 -0
  39. package/dist/atoms/Tooltip.svelte.d.ts +12 -0
  40. package/dist/atoms/index.d.ts +4 -15
  41. package/dist/atoms/index.js +10 -664
  42. package/dist/components/atoms/index.d.ts +10 -0
  43. package/dist/components/atoms/index.d.ts.map +1 -0
  44. package/dist/components/index.d.ts +31 -0
  45. package/dist/components/index.d.ts.map +1 -0
  46. package/dist/components/molecules/index.d.ts +1 -0
  47. package/dist/components/molecules/index.d.ts.map +1 -0
  48. package/dist/components/organisms/index.d.ts +1 -0
  49. package/dist/components/organisms/index.d.ts.map +1 -0
  50. package/dist/index.d.ts +30 -15
  51. package/dist/index.js +74 -0
  52. package/dist/molecules/Alert.svelte +114 -0
  53. package/dist/molecules/Alert.svelte.d.ts +14 -0
  54. package/dist/molecules/ComponentDemo.svelte +96 -0
  55. package/dist/molecules/ComponentDemo.svelte.d.ts +13 -0
  56. package/dist/molecules/ContactForm.svelte +98 -0
  57. package/dist/molecules/ContactForm.svelte.d.ts +10 -0
  58. package/dist/molecules/Dropdown.svelte +128 -0
  59. package/dist/molecules/Dropdown.svelte.d.ts +11 -0
  60. package/dist/molecules/Form.svelte +37 -0
  61. package/dist/molecules/Form.svelte.d.ts +12 -0
  62. package/dist/molecules/ImageUpload.svelte +112 -0
  63. package/dist/molecules/ImageUpload.svelte.d.ts +14 -0
  64. package/dist/molecules/Modal.svelte +85 -0
  65. package/dist/molecules/Modal.svelte.d.ts +13 -0
  66. package/dist/molecules/SlideUp.svelte +73 -0
  67. package/dist/molecules/SlideUp.svelte.d.ts +12 -0
  68. package/dist/molecules/Tabs.svelte +68 -0
  69. package/dist/molecules/Tabs.svelte.d.ts +17 -0
  70. package/dist/molecules/index.d.ts +0 -11
  71. package/dist/molecules/index.js +2 -580
  72. package/dist/organisms/Navbar.svelte +99 -0
  73. package/dist/organisms/Navbar.svelte.d.ts +14 -0
  74. package/dist/organisms/Navigation.svelte +48 -0
  75. package/dist/organisms/Navigation.svelte.d.ts +15 -0
  76. package/dist/organisms/index.d.ts +0 -4
  77. package/dist/organisms/index.js +2 -104
  78. package/dist/routes/lib/ssr-safe.ts +57 -0
  79. package/dist/routes/lib/variant-utils.ts +98 -0
  80. package/dist/zabi-components.css +399 -1
  81. package/package.json +43 -18
  82. package/dist/CodeBlock-Bbv6JfD2.js +0 -422
  83. package/dist/ThemeToggle-Z2Ndc0if.js +0 -42
  84. package/dist/index/index.js +0 -51
  85. package/dist/molecules/KeyValueForm.types.d.ts +0 -11
  86. package/dist/props-BKbHJRuR.js +0 -2213
  87. package/dist/types/index.d.ts +0 -4
  88. package/dist/types/index.js +0 -1
  89. package/dist/vite.svg +0 -1
@@ -0,0 +1,31 @@
1
+ export { default as Toggle } from './atoms/Toggle.svelte';
2
+ export { default as Badge } from './atoms/Badge.svelte';
3
+ export { default as Button } from './atoms/Button.svelte';
4
+ export { default as Card } from './atoms/Card.svelte';
5
+ export { default as Input } from './atoms/Input.svelte';
6
+ export { default as Textarea } from './atoms/Textarea.svelte';
7
+ export { default as Select } from './atoms/Select.svelte';
8
+ export { default as ColorPicker } from './atoms/ColorPicker.svelte';
9
+ export { default as Heading } from './atoms/Heading.svelte';
10
+ export { default as Alert } from './molecules/Alert.svelte';
11
+ export { default as ComponentDemo } from './molecules/ComponentDemo.svelte';
12
+ export { default as ContactForm } from './molecules/ContactForm.svelte';
13
+ export { default as Dropdown } from './molecules/Dropdown.svelte';
14
+ export { default as Form } from './molecules/Form.svelte';
15
+ export { default as ImageUpload } from './molecules/ImageUpload.svelte';
16
+ export { default as Modal } from './molecules/Modal.svelte';
17
+ export { default as SlideUp } from './molecules/SlideUp.svelte';
18
+ export { default as Tabs } from './molecules/Tabs.svelte';
19
+ export { default as Navbar } from './organisms/Navbar.svelte';
20
+ export { default as Navigation } from './organisms/Navigation.svelte';
21
+ export declare const createId: (prefix?: string) => string;
22
+ export declare const cn: (...classes: (string | undefined | null | false)[]) => string;
23
+ export declare const getFormData: (form: HTMLFormElement) => Record<string, any>;
24
+ export declare const validateEmail: (email: string) => boolean;
25
+ export declare const validateRequired: (value: any) => boolean;
26
+ export declare const isBrowser: () => boolean;
27
+ export declare const safeWindow: () => Window | undefined;
28
+ export declare const safeDocument: () => Document | undefined;
29
+ export declare const safeLocalStorage: () => Storage | undefined;
30
+ export declare const generateId: (prefix?: string) => string;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAM5D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAM1D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAOtE,eAAO,MAAM,QAAQ,GAAI,SAAQ,MAAa,KAAG,MAMhD,CAAC;AAEF,eAAO,MAAM,EAAE,GAAI,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,KAAK,CAAC,EAAE,KAAG,MAClC,CAAC;AAGtC,eAAO,MAAM,WAAW,GAAI,MAAM,eAAe,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAGrE,CAAC;AAGF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,OAG7C,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,OAAO,GAAG,KAAG,OAE7C,CAAC;AAGF,eAAO,MAAM,SAAS,QAAO,OAE5B,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,MAAM,GAAG,SAEtC,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,QAAQ,GAAG,SAE1C,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAO,OAAO,GAAG,SAE7C,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,SAAQ,MAAa,KAAG,MAElD,CAAC"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/molecules/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/organisms/index.ts"],"names":[],"mappings":""}
package/dist/index.d.ts CHANGED
@@ -1,15 +1,30 @@
1
- // Main library entry point
2
- // Re-export all components from their respective categories
3
-
4
- // Atomic Components
5
- export * from './atoms/index.js';
6
-
7
- // Molecular Components
8
- export * from './molecules/index.js';
9
-
10
- // Organism Components
11
- export * from './organisms/index.js';
12
-
13
- // Re-export types
14
- export type { FieldConfig } from './molecules/KeyValueForm.types.js';
15
- export * from './types/index.js';
1
+ export { default as Toggle } from './atoms/Toggle.svelte';
2
+ export { default as Badge } from './atoms/Badge.svelte';
3
+ export { default as Button } from './atoms/Button.svelte';
4
+ export { default as Card } from './atoms/Card.svelte';
5
+ export { default as Input } from './atoms/Input.svelte';
6
+ export { default as Textarea } from './atoms/Textarea.svelte';
7
+ export { default as Select } from './atoms/Select.svelte';
8
+ export { default as ColorPicker } from './atoms/ColorPicker.svelte';
9
+ export { default as Heading } from './atoms/Heading.svelte';
10
+ export { default as Alert } from './molecules/Alert.svelte';
11
+ export { default as ComponentDemo } from './molecules/ComponentDemo.svelte';
12
+ export { default as ContactForm } from './molecules/ContactForm.svelte';
13
+ export { default as Dropdown } from './molecules/Dropdown.svelte';
14
+ export { default as Form } from './molecules/Form.svelte';
15
+ export { default as ImageUpload } from './molecules/ImageUpload.svelte';
16
+ export { default as Modal } from './molecules/Modal.svelte';
17
+ export { default as SlideUp } from './molecules/SlideUp.svelte';
18
+ export { default as Tabs } from './molecules/Tabs.svelte';
19
+ export { default as Navbar } from './organisms/Navbar.svelte';
20
+ export { default as Navigation } from './organisms/Navigation.svelte';
21
+ export declare const createId: (prefix?: string) => string;
22
+ export declare const cn: (...classes: (string | undefined | null | false)[]) => string;
23
+ export declare const getFormData: (form: HTMLFormElement) => Record<string, any>;
24
+ export declare const validateEmail: (email: string) => boolean;
25
+ export declare const validateRequired: (value: any) => boolean;
26
+ export declare const isBrowser: () => boolean;
27
+ export declare const safeWindow: () => Window | undefined;
28
+ export declare const safeDocument: () => Document | undefined;
29
+ export declare const safeLocalStorage: () => Storage | undefined;
30
+ export declare const generateId: (prefix?: string) => string;
package/dist/index.js ADDED
@@ -0,0 +1,74 @@
1
+ // Zabi Components - Clean & Simple Svelte Component Library
2
+ // Main library entry point - All components in one place
3
+ // ============================================================================
4
+ // ATOM COMPONENTS - Basic UI building blocks
5
+ // ============================================================================
6
+ // Form Controls - All SSR-safe components
7
+ export { default as Toggle } from './atoms/Toggle.svelte';
8
+ export { default as Badge } from './atoms/Badge.svelte';
9
+ export { default as Button } from './atoms/Button.svelte';
10
+ export { default as Card } from './atoms/Card.svelte';
11
+ export { default as Input } from './atoms/Input.svelte';
12
+ export { default as Textarea } from './atoms/Textarea.svelte';
13
+ export { default as Select } from './atoms/Select.svelte';
14
+ export { default as ColorPicker } from './atoms/ColorPicker.svelte';
15
+ export { default as Heading } from './atoms/Heading.svelte';
16
+ // ============================================================================
17
+ // MOLECULE COMPONENTS - Composite UI elements
18
+ // ============================================================================
19
+ export { default as Alert } from './molecules/Alert.svelte';
20
+ export { default as ComponentDemo } from './molecules/ComponentDemo.svelte';
21
+ export { default as ContactForm } from './molecules/ContactForm.svelte';
22
+ export { default as Dropdown } from './molecules/Dropdown.svelte';
23
+ export { default as Form } from './molecules/Form.svelte';
24
+ export { default as ImageUpload } from './molecules/ImageUpload.svelte';
25
+ export { default as Modal } from './molecules/Modal.svelte';
26
+ export { default as SlideUp } from './molecules/SlideUp.svelte';
27
+ export { default as Tabs } from './molecules/Tabs.svelte';
28
+ // ============================================================================
29
+ // ORGANISM COMPONENTS - Complex UI sections
30
+ // ============================================================================
31
+ export { default as Navbar } from './organisms/Navbar.svelte';
32
+ export { default as Navigation } from './organisms/Navigation.svelte';
33
+ // ============================================================================
34
+ // UTILITIES - Helper functions and utilities
35
+ // ============================================================================
36
+ // Simple utility functions
37
+ export const createId = (prefix = 'id') => {
38
+ if (typeof window !== 'undefined') {
39
+ return `${prefix}-${Math.random().toString(36).substr(2, 9)}`;
40
+ }
41
+ else {
42
+ return `${prefix}-ssr-${Date.now()}`;
43
+ }
44
+ };
45
+ export const cn = (...classes) => classes.filter(Boolean).join(' ');
46
+ // Form utilities
47
+ export const getFormData = (form) => {
48
+ const formData = new FormData(form);
49
+ return Object.fromEntries(formData.entries());
50
+ };
51
+ // Validation utilities
52
+ export const validateEmail = (email) => {
53
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
54
+ return emailRegex.test(email);
55
+ };
56
+ export const validateRequired = (value) => {
57
+ return value !== null && value !== undefined && value !== '';
58
+ };
59
+ // SSR-safe utilities
60
+ export const isBrowser = () => {
61
+ return typeof window !== 'undefined';
62
+ };
63
+ export const safeWindow = () => {
64
+ return isBrowser() ? window : undefined;
65
+ };
66
+ export const safeDocument = () => {
67
+ return isBrowser() ? document : undefined;
68
+ };
69
+ export const safeLocalStorage = () => {
70
+ return isBrowser() ? localStorage : undefined;
71
+ };
72
+ export const generateId = (prefix = 'id') => {
73
+ return createId(prefix);
74
+ };
@@ -0,0 +1,114 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ variant?: "info" | "success" | "warning" | "error";
4
+ title?: string;
5
+ message?: string;
6
+ closable?: boolean;
7
+ className?: string;
8
+ onclick?: (event: Event) => void;
9
+ }
10
+
11
+ let {
12
+ variant = "info",
13
+ title = "",
14
+ message = "",
15
+ closable = false,
16
+ className = "",
17
+ onclick,
18
+ children,
19
+ ...restProps
20
+ }: Props & { children?: any } = $props();
21
+
22
+ function handleDismiss(event: MouseEvent) {
23
+ // Call the parent's onclick handler if provided
24
+ if (onclick) {
25
+ onclick(event);
26
+ }
27
+ }
28
+
29
+ let alertClasses = $derived({
30
+ info: "bg-info-surface text-body border border-info",
31
+ success: "bg-success-surface text-success border border-success",
32
+ warning: "bg-warning-surface text-warning border border-warning",
33
+ error: "bg-error-surface text-error border border-error",
34
+ });
35
+
36
+ let alertRole = $derived(
37
+ variant === "success" || variant === "info" ? "status" : "alert",
38
+ );
39
+
40
+ let iconSvg = $derived({
41
+ info: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
42
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" />
43
+ </svg>`,
44
+ success: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
45
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
46
+ </svg>`,
47
+ warning: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
48
+ <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
49
+ </svg>`,
50
+ error: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
51
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
52
+ </svg>`,
53
+ });
54
+ </script>
55
+
56
+ <div
57
+ class="relative rounded-md p-4 border {alertClasses[
58
+ variant
59
+ ]} transition-all duration-200 motion-reduce:transition-none {className}"
60
+ role={alertRole}
61
+ aria-live={variant === "success" || variant === "info"
62
+ ? "polite"
63
+ : "assertive"}
64
+ aria-atomic="true"
65
+ {...restProps}
66
+ >
67
+ <!-- Dismiss button (X in top right) -->
68
+ {#if closable}
69
+ <button
70
+ onclick={handleDismiss}
71
+ class="absolute top-2 right-2 z-10 w-6 h-6 flex items-center justify-center rounded-full text-description hover:text-body transition-colors duration-200 motion-reduce:transition-none group focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2"
72
+ aria-label="Dismiss alert"
73
+ type="button"
74
+ >
75
+ <svg
76
+ class="w-4 h-4 text-current group-hover:scale-110 transition-transform duration-200 motion-reduce:transition-none"
77
+ fill="none"
78
+ stroke="currentColor"
79
+ viewBox="0 0 24 24"
80
+ >
81
+ <path
82
+ stroke-linecap="round"
83
+ stroke-linejoin="round"
84
+ stroke-width="2"
85
+ d="M6 18L18 6M6 6l12 12"
86
+ />
87
+ </svg>
88
+ </button>
89
+ {/if}
90
+
91
+ <!-- Content -->
92
+ <div class="flex items-start gap-3 {closable ? 'pr-8' : ''}">
93
+ <!-- Icon -->
94
+ <div class="shrink-0 mt-0.5">
95
+ {@html iconSvg[variant]}
96
+ </div>
97
+
98
+ <!-- Text content -->
99
+ <div class="flex-1 min-w-0">
100
+ {#if title}
101
+ <h4 class="font-semibold text-sm mb-1 text-headline">
102
+ {title}
103
+ </h4>
104
+ {/if}
105
+ {#if message}
106
+ <p class="text-sm leading-relaxed text-body">
107
+ {message}
108
+ </p>
109
+ {/if}
110
+ <!-- Default slot for custom content -->
111
+ {@render children?.()}
112
+ </div>
113
+ </div>
114
+ </div>
@@ -0,0 +1,14 @@
1
+ interface Props {
2
+ variant?: "info" | "success" | "warning" | "error";
3
+ title?: string;
4
+ message?: string;
5
+ closable?: boolean;
6
+ className?: string;
7
+ onclick?: (event: Event) => void;
8
+ }
9
+ type $$ComponentProps = Props & {
10
+ children?: any;
11
+ };
12
+ declare const Alert: import("svelte").Component<$$ComponentProps, {}, "">;
13
+ type Alert = ReturnType<typeof Alert>;
14
+ export default Alert;
@@ -0,0 +1,96 @@
1
+ <script lang="ts">
2
+ import CodeBlock from "../atoms/CodeBlock.svelte";
3
+
4
+ interface Props {
5
+ title: string;
6
+ description?: string;
7
+ code: string;
8
+ language?: string;
9
+ className?: string;
10
+ }
11
+
12
+ let {
13
+ title,
14
+ description = "",
15
+ code,
16
+ language = "svelte",
17
+ className = "",
18
+ children,
19
+ ...restProps
20
+ } = $props<Props & { children?: any }>();
21
+
22
+ let showCode = $state(false);
23
+ </script>
24
+
25
+ <div
26
+ class="component-demo bg-surface border border-border rounded-lg overflow-hidden {className}"
27
+ {...restProps}
28
+ >
29
+ <!-- Header -->
30
+ <div class="px-6 py-4 border-b border-border bg-surface-secondary">
31
+ <div class="flex items-center justify-between">
32
+ <div>
33
+ <h3 class="text-lg font-semibold text-text">{title}</h3>
34
+ {#if description}
35
+ <p class="text-sm text-text-secondary mt-1">
36
+ {description}
37
+ </p>
38
+ {/if}
39
+ </div>
40
+ <button
41
+ onclick={() => (showCode = !showCode)}
42
+ class="flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text hover:bg-surface rounded-md transition-colors duration-200"
43
+ aria-label={showCode ? "Show preview" : "Show code"}
44
+ >
45
+ {#if showCode}
46
+ <svg
47
+ class="w-4 h-4"
48
+ fill="none"
49
+ stroke="currentColor"
50
+ viewBox="0 0 24 24"
51
+ >
52
+ <path
53
+ stroke-linecap="round"
54
+ stroke-linejoin="round"
55
+ stroke-width="2"
56
+ d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
57
+ />
58
+ <path
59
+ stroke-linecap="round"
60
+ stroke-linejoin="round"
61
+ stroke-width="2"
62
+ d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
63
+ />
64
+ </svg>
65
+ Preview
66
+ {:else}
67
+ <svg
68
+ class="w-4 h-4"
69
+ fill="none"
70
+ stroke="currentColor"
71
+ viewBox="0 0 24 24"
72
+ >
73
+ <path
74
+ stroke-linecap="round"
75
+ stroke-linejoin="round"
76
+ stroke-width="2"
77
+ d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
78
+ />
79
+ </svg>
80
+ Code
81
+ {/if}
82
+ </button>
83
+ </div>
84
+ </div>
85
+
86
+ <!-- Content -->
87
+ <div class="p-6">
88
+ {#if showCode}
89
+ <CodeBlock {code} {language} />
90
+ {:else}
91
+ <div class="min-h-[100px] flex items-center justify-center">
92
+ {@render children?.()}
93
+ </div>
94
+ {/if}
95
+ </div>
96
+ </div>
@@ -0,0 +1,13 @@
1
+ interface Props {
2
+ title: string;
3
+ description?: string;
4
+ code: string;
5
+ language?: string;
6
+ className?: string;
7
+ }
8
+ type $$ComponentProps = Props & {
9
+ children?: any;
10
+ };
11
+ declare const ComponentDemo: import("svelte").Component<$$ComponentProps, {}, "">;
12
+ type ComponentDemo = ReturnType<typeof ComponentDemo>;
13
+ export default ComponentDemo;
@@ -0,0 +1,98 @@
1
+ <script lang="ts">
2
+ import Form from "./Form.svelte";
3
+ import Input from "../atoms/Input.svelte";
4
+ import Textarea from "../atoms/Textarea.svelte";
5
+ import Checkbox from "../atoms/Checkbox.svelte";
6
+ import Button from "../atoms/Button.svelte";
7
+ import type { ContactFormData } from "../../types/page.types";
8
+
9
+ interface Props {
10
+ className?: string;
11
+ onsubmit?: (event: SubmitEvent) => void;
12
+ }
13
+
14
+ let {
15
+ className = "",
16
+ children,
17
+ ...restProps
18
+ } = $props<Props & { children?: any }>();
19
+
20
+ let formData = $state<ContactFormData>({
21
+ name: "",
22
+ email: "",
23
+ message: "",
24
+ subscribe: false,
25
+ });
26
+
27
+ function handleFormSubmit(event: SubmitEvent) {
28
+ const formData = new FormData(event.target as HTMLFormElement);
29
+ const data: ContactFormData = {
30
+ name: (formData.get("name") as string) || "",
31
+ email: (formData.get("email") as string) || "",
32
+ message: (formData.get("message") as string) || "",
33
+ subscribe: formData.get("subscribe") === "on" || false,
34
+ };
35
+
36
+ // Form submission is now handled by the parent component
37
+ // through event forwarding. The data is available for processing.
38
+ console.log("Form submitted with data:", data);
39
+ }
40
+ </script>
41
+
42
+ <div class="max-w-md mx-auto {className}">
43
+ <div class="mb-6">
44
+ <h2 class="text-2xl font-bold text-headline mb-2">Get in Touch</h2>
45
+ <p class="text-description">
46
+ We'd love to hear from you. Send us a message and we'll respond as
47
+ soon as possible.
48
+ </p>
49
+ </div>
50
+
51
+ <Form onsubmit={handleFormSubmit} className="space-y-4">
52
+ <div class="space-y-4">
53
+ <Input
54
+ type="text"
55
+ name="name"
56
+ label="Name"
57
+ placeholder="Enter your name"
58
+ value={formData.name}
59
+ oninput={(e) =>
60
+ (formData.name = (e.target as HTMLInputElement).value)}
61
+ />
62
+ <Input
63
+ type="email"
64
+ name="email"
65
+ label="Email"
66
+ placeholder="Enter your email"
67
+ value={formData.email}
68
+ oninput={(e) =>
69
+ (formData.email = (e.target as HTMLInputElement).value)}
70
+ />
71
+ <Textarea
72
+ name="message"
73
+ label="Message"
74
+ placeholder="Enter your message"
75
+ rows={4}
76
+ value={formData.message}
77
+ oninput={(e) =>
78
+ (formData.message = (
79
+ e.target as HTMLTextAreaElement
80
+ ).value)}
81
+ />
82
+ <Checkbox
83
+ name="subscribe"
84
+ label="Subscribe to updates"
85
+ checked={formData.subscribe}
86
+ onchange={(e) =>
87
+ (formData.subscribe = (
88
+ e.target as HTMLInputElement
89
+ ).checked)}
90
+ />
91
+ </div>
92
+ <div class="pt-4">
93
+ <Button type="submit" variant="primary" size="md">
94
+ Send Message
95
+ </Button>
96
+ </div>
97
+ </Form>
98
+ </div>
@@ -0,0 +1,10 @@
1
+ interface Props {
2
+ className?: string;
3
+ onsubmit?: (event: SubmitEvent) => void;
4
+ }
5
+ type $$ComponentProps = Props & {
6
+ children?: any;
7
+ };
8
+ declare const ContactForm: import("svelte").Component<$$ComponentProps, {}, "">;
9
+ type ContactForm = ReturnType<typeof ContactForm>;
10
+ export default ContactForm;
@@ -0,0 +1,128 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ isOpen?: boolean;
4
+ placement?: "bottom-start" | "bottom-end" | "top-start" | "top-end";
5
+ }
6
+
7
+ let {
8
+ isOpen = false,
9
+ placement = "bottom-start",
10
+ children,
11
+ trigger,
12
+ ...restProps
13
+ }: Props & { children?: any; trigger?: any } = $props();
14
+ </script>
15
+
16
+ <div
17
+ class="dropdown-container group relative inline-block"
18
+ data-placement={placement}
19
+ >
20
+ {@render trigger?.()}
21
+
22
+ {#if isOpen}
23
+ <div
24
+ class="dropdown-content opacity-100 visible transform-none group-hover:opacity-100 group-hover:visible group-focus-within:opacity-100 group-focus-within:visible"
25
+ >
26
+ {@render children?.()}
27
+ </div>
28
+ {/if}
29
+ </div>
30
+
31
+ <style>
32
+ .dropdown-container {
33
+ position: relative;
34
+ display: inline-block;
35
+ }
36
+
37
+ .dropdown-content {
38
+ position: absolute;
39
+ z-index: 50;
40
+ background-color: white;
41
+ border: 1px solid #e5e7eb;
42
+ border-radius: 0.5rem;
43
+ box-shadow:
44
+ 0 10px 15px -3px rgba(0, 0, 0, 0.1),
45
+ 0 4px 6px -2px rgba(0, 0, 0, 0.05);
46
+ min-width: 12rem;
47
+ opacity: 0;
48
+ visibility: hidden;
49
+ transition:
50
+ opacity 0.2s ease-in-out,
51
+ visibility 0.2s ease-in-out,
52
+ transform 0.2s ease-in-out;
53
+ }
54
+
55
+ /* Positioning based on data-placement */
56
+ .dropdown-container[data-placement="bottom-start"] .dropdown-content {
57
+ top: calc(100% + 8px);
58
+ left: 0;
59
+ transform: translateY(4px);
60
+ }
61
+
62
+ .dropdown-container[data-placement="bottom-end"] .dropdown-content {
63
+ top: calc(100% + 8px);
64
+ right: 0;
65
+ transform: translateY(4px);
66
+ }
67
+
68
+ .dropdown-container[data-placement="top-start"] .dropdown-content {
69
+ bottom: calc(100% + 8px);
70
+ left: 0;
71
+ transform: translateY(-4px);
72
+ }
73
+
74
+ .dropdown-container[data-placement="top-end"] .dropdown-content {
75
+ bottom: calc(100% + 8px);
76
+ right: 0;
77
+ transform: translateY(-4px);
78
+ }
79
+
80
+ /* Show on hover/focus */
81
+ .dropdown-container:hover .dropdown-content,
82
+ .dropdown-container:focus-within .dropdown-content {
83
+ opacity: 1;
84
+ visibility: visible;
85
+ transform: translateY(0);
86
+ }
87
+
88
+ /* Arrow styling */
89
+ .dropdown-content::before {
90
+ content: "";
91
+ position: absolute;
92
+ width: 0;
93
+ height: 0;
94
+ border-style: solid;
95
+ border-width: 6px;
96
+ border-color: transparent;
97
+ }
98
+
99
+ .dropdown-container[data-placement="bottom-start"]
100
+ .dropdown-content::before,
101
+ .dropdown-container[data-placement="bottom-end"] .dropdown-content::before {
102
+ top: -6px;
103
+ border-bottom-color: white;
104
+ }
105
+
106
+ .dropdown-container[data-placement="top-start"] .dropdown-content::before,
107
+ .dropdown-container[data-placement="top-end"] .dropdown-content::before {
108
+ bottom: -6px;
109
+ border-top-color: white;
110
+ }
111
+
112
+ .dropdown-container[data-placement="bottom-start"]
113
+ .dropdown-content::before {
114
+ left: 1rem;
115
+ }
116
+
117
+ .dropdown-container[data-placement="bottom-end"] .dropdown-content::before {
118
+ right: 1rem;
119
+ }
120
+
121
+ .dropdown-container[data-placement="top-start"] .dropdown-content::before {
122
+ left: 1rem;
123
+ }
124
+
125
+ .dropdown-container[data-placement="top-end"] .dropdown-content::before {
126
+ right: 1rem;
127
+ }
128
+ </style>
@@ -0,0 +1,11 @@
1
+ interface Props {
2
+ isOpen?: boolean;
3
+ placement?: "bottom-start" | "bottom-end" | "top-start" | "top-end";
4
+ }
5
+ type $$ComponentProps = Props & {
6
+ children?: any;
7
+ trigger?: any;
8
+ };
9
+ declare const Dropdown: import("svelte").Component<$$ComponentProps, {}, "">;
10
+ type Dropdown = ReturnType<typeof Dropdown>;
11
+ export default Dropdown;