@aspect-ops/exon-ui 0.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 (106) hide show
  1. package/dist/components/Badge/Badge.svelte +60 -0
  2. package/dist/components/Badge/Badge.svelte.d.ts +9 -0
  3. package/dist/components/Badge/index.d.ts +2 -0
  4. package/dist/components/Badge/index.js +1 -0
  5. package/dist/components/BottomNav/BottomNav.svelte +128 -0
  6. package/dist/components/BottomNav/BottomNav.svelte.d.ts +8 -0
  7. package/dist/components/BottomNav/BottomNavItem.svelte +133 -0
  8. package/dist/components/BottomNav/BottomNavItem.svelte.d.ts +8 -0
  9. package/dist/components/Breadcrumbs/BreadcrumbItem.svelte +65 -0
  10. package/dist/components/Breadcrumbs/BreadcrumbItem.svelte.d.ts +7 -0
  11. package/dist/components/Breadcrumbs/BreadcrumbSeparator.svelte +27 -0
  12. package/dist/components/Breadcrumbs/BreadcrumbSeparator.svelte.d.ts +7 -0
  13. package/dist/components/Breadcrumbs/Breadcrumbs.svelte +114 -0
  14. package/dist/components/Breadcrumbs/Breadcrumbs.svelte.d.ts +8 -0
  15. package/dist/components/Button/Button.svelte +209 -0
  16. package/dist/components/Button/Button.svelte.d.ts +14 -0
  17. package/dist/components/Button/index.d.ts +2 -0
  18. package/dist/components/Button/index.js +1 -0
  19. package/dist/components/Checkbox/Checkbox.svelte +166 -0
  20. package/dist/components/Checkbox/Checkbox.svelte.d.ts +16 -0
  21. package/dist/components/Checkbox/CheckboxGroup.svelte +55 -0
  22. package/dist/components/Checkbox/CheckboxGroup.svelte.d.ts +12 -0
  23. package/dist/components/Checkbox/index.d.ts +2 -0
  24. package/dist/components/Checkbox/index.js +2 -0
  25. package/dist/components/FormField/FormField.svelte +101 -0
  26. package/dist/components/FormField/FormField.svelte.d.ts +13 -0
  27. package/dist/components/FormField/index.d.ts +1 -0
  28. package/dist/components/FormField/index.js +1 -0
  29. package/dist/components/Icon/Icon.svelte +47 -0
  30. package/dist/components/Icon/Icon.svelte.d.ts +11 -0
  31. package/dist/components/Icon/index.d.ts +2 -0
  32. package/dist/components/Icon/index.js +1 -0
  33. package/dist/components/Link/Link.svelte +56 -0
  34. package/dist/components/Link/Link.svelte.d.ts +9 -0
  35. package/dist/components/Link/index.d.ts +2 -0
  36. package/dist/components/Link/index.js +1 -0
  37. package/dist/components/Menu/Menu.svelte +14 -0
  38. package/dist/components/Menu/Menu.svelte.d.ts +7 -0
  39. package/dist/components/Menu/MenuContent.svelte +71 -0
  40. package/dist/components/Menu/MenuContent.svelte.d.ts +10 -0
  41. package/dist/components/Menu/MenuItem.svelte +73 -0
  42. package/dist/components/Menu/MenuItem.svelte.d.ts +7 -0
  43. package/dist/components/Menu/MenuSeparator.svelte +19 -0
  44. package/dist/components/Menu/MenuSeparator.svelte.d.ts +6 -0
  45. package/dist/components/Menu/MenuSub.svelte +14 -0
  46. package/dist/components/Menu/MenuSub.svelte.d.ts +7 -0
  47. package/dist/components/Menu/MenuSubContent.svelte +60 -0
  48. package/dist/components/Menu/MenuSubContent.svelte.d.ts +7 -0
  49. package/dist/components/Menu/MenuSubTrigger.svelte +84 -0
  50. package/dist/components/Menu/MenuSubTrigger.svelte.d.ts +7 -0
  51. package/dist/components/Menu/MenuTrigger.svelte +32 -0
  52. package/dist/components/Menu/MenuTrigger.svelte.d.ts +7 -0
  53. package/dist/components/Navbar/NavItem.svelte +99 -0
  54. package/dist/components/Navbar/NavItem.svelte.d.ts +8 -0
  55. package/dist/components/Navbar/Navbar.svelte +243 -0
  56. package/dist/components/Navbar/Navbar.svelte.d.ts +10 -0
  57. package/dist/components/Radio/Radio.svelte +93 -0
  58. package/dist/components/Radio/Radio.svelte.d.ts +10 -0
  59. package/dist/components/Radio/RadioGroup.svelte +72 -0
  60. package/dist/components/Radio/RadioGroup.svelte.d.ts +14 -0
  61. package/dist/components/Radio/index.d.ts +2 -0
  62. package/dist/components/Radio/index.js +2 -0
  63. package/dist/components/Select/Select.svelte +251 -0
  64. package/dist/components/Select/Select.svelte.d.ts +17 -0
  65. package/dist/components/Select/index.d.ts +1 -0
  66. package/dist/components/Select/index.js +1 -0
  67. package/dist/components/Sidebar/Sidebar.svelte +48 -0
  68. package/dist/components/Sidebar/Sidebar.svelte.d.ts +7 -0
  69. package/dist/components/Sidebar/SidebarGroup.svelte +141 -0
  70. package/dist/components/Sidebar/SidebarGroup.svelte.d.ts +7 -0
  71. package/dist/components/Sidebar/SidebarItem.svelte +151 -0
  72. package/dist/components/Sidebar/SidebarItem.svelte.d.ts +8 -0
  73. package/dist/components/Switch/Switch.svelte +120 -0
  74. package/dist/components/Switch/Switch.svelte.d.ts +13 -0
  75. package/dist/components/Switch/index.d.ts +1 -0
  76. package/dist/components/Switch/index.js +1 -0
  77. package/dist/components/Tabs/TabContent.svelte +91 -0
  78. package/dist/components/Tabs/TabContent.svelte.d.ts +7 -0
  79. package/dist/components/Tabs/TabList.svelte +46 -0
  80. package/dist/components/Tabs/TabList.svelte.d.ts +7 -0
  81. package/dist/components/Tabs/TabTrigger.svelte +68 -0
  82. package/dist/components/Tabs/TabTrigger.svelte.d.ts +7 -0
  83. package/dist/components/Tabs/Tabs.svelte +69 -0
  84. package/dist/components/Tabs/Tabs.svelte.d.ts +7 -0
  85. package/dist/components/TextInput/TextInput.svelte +200 -0
  86. package/dist/components/TextInput/TextInput.svelte.d.ts +35 -0
  87. package/dist/components/TextInput/index.d.ts +1 -0
  88. package/dist/components/TextInput/index.js +1 -0
  89. package/dist/components/Textarea/Textarea.svelte +198 -0
  90. package/dist/components/Textarea/Textarea.svelte.d.ts +33 -0
  91. package/dist/components/Textarea/index.d.ts +1 -0
  92. package/dist/components/Textarea/index.js +1 -0
  93. package/dist/components/Typography/Typography.svelte +99 -0
  94. package/dist/components/Typography/Typography.svelte.d.ts +10 -0
  95. package/dist/components/Typography/index.d.ts +2 -0
  96. package/dist/components/Typography/index.js +1 -0
  97. package/dist/index.d.ts +37 -0
  98. package/dist/index.js +41 -0
  99. package/dist/styles/tokens.css +431 -0
  100. package/dist/test-setup.d.ts +1 -0
  101. package/dist/test-setup.js +1 -0
  102. package/dist/types/index.d.ts +129 -0
  103. package/dist/types/index.js +1 -0
  104. package/dist/types/navigation.d.ts +118 -0
  105. package/dist/types/navigation.js +1 -0
  106. package/package.json +130 -0
@@ -0,0 +1,209 @@
1
+ <script lang="ts">
2
+ import type { ButtonVariant, ButtonSize } from '../../types/index.js';
3
+
4
+ interface Props {
5
+ variant?: ButtonVariant;
6
+ size?: ButtonSize;
7
+ disabled?: boolean;
8
+ loading?: boolean;
9
+ fullWidth?: boolean;
10
+ class?: string;
11
+ onclick?: (e: MouseEvent) => void;
12
+ children?: import('svelte').Snippet;
13
+ }
14
+
15
+ let {
16
+ variant = 'primary',
17
+ size = 'md',
18
+ disabled = false,
19
+ loading = false,
20
+ fullWidth = false,
21
+ class: className = '',
22
+ onclick,
23
+ children
24
+ }: Props = $props();
25
+
26
+ const isDisabled = $derived(disabled || loading);
27
+ </script>
28
+
29
+ <button
30
+ class="btn btn--{variant} btn--{size} {fullWidth ? 'btn--full' : ''} {className}"
31
+ disabled={isDisabled}
32
+ aria-disabled={isDisabled}
33
+ aria-busy={loading}
34
+ {onclick}
35
+ >
36
+ {#if loading}
37
+ <span class="btn__spinner" aria-hidden="true"></span>
38
+ {/if}
39
+ <span class="btn__content" class:btn__content--hidden={loading}>
40
+ {#if children}
41
+ {@render children()}
42
+ {/if}
43
+ </span>
44
+ </button>
45
+
46
+ <style>
47
+ .btn {
48
+ position: relative;
49
+ display: inline-flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ gap: var(--space-sm, 0.5rem);
53
+ min-height: var(--touch-target-min, 44px);
54
+ padding: var(--space-sm, 0.5rem) var(--space-md, 1rem);
55
+ border: 1px solid transparent;
56
+ border-radius: var(--radius-md, 0.375rem);
57
+ font-family: inherit;
58
+ font-size: var(--text-sm, 0.875rem);
59
+ font-weight: 600;
60
+ line-height: 1;
61
+ cursor: pointer;
62
+ transition: all var(--transition-fast, 150ms ease);
63
+ -webkit-tap-highlight-color: transparent;
64
+ }
65
+
66
+ .btn:focus-visible {
67
+ outline: 2px solid var(--color-primary, #3b82f6);
68
+ outline-offset: 2px;
69
+ }
70
+
71
+ .btn:disabled {
72
+ opacity: 0.5;
73
+ cursor: not-allowed;
74
+ pointer-events: none;
75
+ }
76
+
77
+ /* Sizes */
78
+ .btn--sm {
79
+ min-height: var(--touch-target-min, 44px);
80
+ padding: var(--space-xs, 0.25rem) var(--space-sm, 0.5rem);
81
+ font-size: var(--text-xs, 0.75rem);
82
+ }
83
+
84
+ .btn--md {
85
+ min-height: var(--touch-target-min, 44px);
86
+ padding: var(--space-sm, 0.5rem) var(--space-md, 1rem);
87
+ font-size: var(--text-sm, 0.875rem);
88
+ }
89
+
90
+ .btn--lg {
91
+ min-height: 3.25rem;
92
+ padding: var(--space-md, 1rem) var(--space-lg, 1.5rem);
93
+ font-size: var(--text-base, 1rem);
94
+ }
95
+
96
+ /* Primary variant */
97
+ .btn--primary {
98
+ background: var(--color-primary, #3b82f6);
99
+ color: var(--color-text-inverse, #ffffff);
100
+ border-color: var(--color-primary, #3b82f6);
101
+ }
102
+
103
+ .btn--primary:hover:not(:disabled) {
104
+ background: var(--color-primary-hover, #2563eb);
105
+ border-color: var(--color-primary-hover, #2563eb);
106
+ }
107
+
108
+ .btn--primary:active:not(:disabled) {
109
+ background: var(--color-primary-active, #1d4ed8);
110
+ border-color: var(--color-primary-active, #1d4ed8);
111
+ }
112
+
113
+ /* Secondary variant */
114
+ .btn--secondary {
115
+ background: var(--color-secondary, #6b7280);
116
+ color: var(--color-text-inverse, #ffffff);
117
+ border-color: var(--color-secondary, #6b7280);
118
+ }
119
+
120
+ .btn--secondary:hover:not(:disabled) {
121
+ background: var(--color-secondary-hover, #4b5563);
122
+ border-color: var(--color-secondary-hover, #4b5563);
123
+ }
124
+
125
+ .btn--secondary:active:not(:disabled) {
126
+ background: var(--color-secondary-active, #374151);
127
+ border-color: var(--color-secondary-active, #374151);
128
+ }
129
+
130
+ /* Outline variant */
131
+ .btn--outline {
132
+ background: transparent;
133
+ color: var(--color-text, #1f2937);
134
+ border-color: var(--color-border, #e5e7eb);
135
+ }
136
+
137
+ .btn--outline:hover:not(:disabled) {
138
+ background: var(--color-bg-muted, #f3f4f6);
139
+ border-color: var(--color-border-hover, #d1d5db);
140
+ }
141
+
142
+ .btn--outline:active:not(:disabled) {
143
+ background: var(--color-border, #e5e7eb);
144
+ }
145
+
146
+ /* Ghost variant */
147
+ .btn--ghost {
148
+ background: transparent;
149
+ color: var(--color-text, #1f2937);
150
+ border-color: transparent;
151
+ }
152
+
153
+ .btn--ghost:hover:not(:disabled) {
154
+ background: var(--color-bg-muted, #f3f4f6);
155
+ }
156
+
157
+ .btn--ghost:active:not(:disabled) {
158
+ background: var(--color-border, #e5e7eb);
159
+ }
160
+
161
+ /* Destructive variant */
162
+ .btn--destructive {
163
+ background: var(--color-destructive, #ef4444);
164
+ color: var(--color-text-inverse, #ffffff);
165
+ border-color: var(--color-destructive, #ef4444);
166
+ }
167
+
168
+ .btn--destructive:hover:not(:disabled) {
169
+ background: var(--color-destructive-hover, #dc2626);
170
+ border-color: var(--color-destructive-hover, #dc2626);
171
+ }
172
+
173
+ .btn--destructive:active:not(:disabled) {
174
+ background: var(--color-destructive-active, #b91c1c);
175
+ border-color: var(--color-destructive-active, #b91c1c);
176
+ }
177
+
178
+ /* Full width */
179
+ .btn--full {
180
+ width: 100%;
181
+ }
182
+
183
+ /* Loading spinner */
184
+ .btn__spinner {
185
+ position: absolute;
186
+ width: 1em;
187
+ height: 1em;
188
+ border: 2px solid currentColor;
189
+ border-right-color: transparent;
190
+ border-radius: 50%;
191
+ animation: spin 0.6s linear infinite;
192
+ }
193
+
194
+ .btn__content {
195
+ display: inline-flex;
196
+ align-items: center;
197
+ gap: var(--space-sm, 0.5rem);
198
+ }
199
+
200
+ .btn__content--hidden {
201
+ visibility: hidden;
202
+ }
203
+
204
+ @keyframes spin {
205
+ to {
206
+ transform: rotate(360deg);
207
+ }
208
+ }
209
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { ButtonVariant, ButtonSize } from '../../types/index.js';
2
+ interface Props {
3
+ variant?: ButtonVariant;
4
+ size?: ButtonSize;
5
+ disabled?: boolean;
6
+ loading?: boolean;
7
+ fullWidth?: boolean;
8
+ class?: string;
9
+ onclick?: (e: MouseEvent) => void;
10
+ children?: import('svelte').Snippet;
11
+ }
12
+ declare const Button: import("svelte").Component<Props, {}, "">;
13
+ type Button = ReturnType<typeof Button>;
14
+ export default Button;
@@ -0,0 +1,2 @@
1
+ export { default as Button } from './Button.svelte';
2
+ export type { ButtonProps, ButtonVariant, ButtonSize } from '../../types/index.js';
@@ -0,0 +1 @@
1
+ export { default as Button } from './Button.svelte';
@@ -0,0 +1,166 @@
1
+ <script lang="ts">
2
+ import { Checkbox as CheckboxPrimitive } from 'bits-ui';
3
+
4
+ interface Props {
5
+ checked?: boolean;
6
+ indeterminate?: boolean;
7
+ value?: string;
8
+ name?: string;
9
+ id?: string;
10
+ disabled?: boolean;
11
+ required?: boolean;
12
+ error?: boolean;
13
+ class?: string;
14
+ onchange?: (checked: boolean) => void;
15
+ children?: import('svelte').Snippet;
16
+ }
17
+
18
+ let {
19
+ checked = $bindable(false),
20
+ indeterminate = false,
21
+ value,
22
+ name,
23
+ id,
24
+ disabled = false,
25
+ required = false,
26
+ error = false,
27
+ class: className = '',
28
+ onchange,
29
+ children
30
+ }: Props = $props();
31
+
32
+ function handleCheckedChange(newChecked: boolean) {
33
+ checked = newChecked;
34
+ onchange?.(newChecked);
35
+ }
36
+ </script>
37
+
38
+ <div class="checkbox-wrapper {className}">
39
+ <CheckboxPrimitive.Root
40
+ class="checkbox {error ? 'checkbox--error' : ''} {disabled ? 'checkbox--disabled' : ''}"
41
+ {checked}
42
+ {name}
43
+ {value}
44
+ {disabled}
45
+ {required}
46
+ {id}
47
+ aria-invalid={error}
48
+ aria-required={required}
49
+ onCheckedChange={handleCheckedChange}
50
+ >
51
+ {#snippet children({ checked: isChecked })}
52
+ <span class="checkbox__indicator">
53
+ {#if indeterminate}
54
+ <svg
55
+ width="12"
56
+ height="12"
57
+ viewBox="0 0 12 12"
58
+ fill="none"
59
+ xmlns="http://www.w3.org/2000/svg"
60
+ >
61
+ <path d="M2.5 6H9.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
62
+ </svg>
63
+ {:else if isChecked}
64
+ <svg
65
+ width="12"
66
+ height="12"
67
+ viewBox="0 0 12 12"
68
+ fill="none"
69
+ xmlns="http://www.w3.org/2000/svg"
70
+ >
71
+ <path
72
+ d="M2.5 6L5 8.5L9.5 3.5"
73
+ stroke="currentColor"
74
+ stroke-width="2"
75
+ stroke-linecap="round"
76
+ stroke-linejoin="round"
77
+ />
78
+ </svg>
79
+ {/if}
80
+ </span>
81
+ {/snippet}
82
+ </CheckboxPrimitive.Root>
83
+
84
+ {#if children}
85
+ <label for={id} class="checkbox__label" class:checkbox__label--disabled={disabled}>
86
+ {@render children()}
87
+ </label>
88
+ {/if}
89
+ </div>
90
+
91
+ <style>
92
+ .checkbox-wrapper {
93
+ display: inline-flex;
94
+ align-items: center;
95
+ gap: var(--space-sm, 0.5rem);
96
+ }
97
+
98
+ :global(.checkbox) {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ width: 1.25rem;
103
+ height: 1.25rem;
104
+ min-width: 1.25rem;
105
+ min-height: 1.25rem;
106
+ border: 2px solid var(--color-border, #e5e7eb);
107
+ border-radius: var(--radius-sm, 0.25rem);
108
+ background: var(--color-bg, #ffffff);
109
+ cursor: pointer;
110
+ transition:
111
+ border-color var(--transition-fast, 150ms ease),
112
+ background var(--transition-fast, 150ms ease),
113
+ box-shadow var(--transition-fast, 150ms ease);
114
+ -webkit-tap-highlight-color: transparent;
115
+ }
116
+
117
+ :global(.checkbox:focus-visible) {
118
+ outline: none;
119
+ border-color: var(--color-primary, #3b82f6);
120
+ box-shadow: 0 0 0 3px var(--color-primary-alpha, rgba(59, 130, 246, 0.1));
121
+ }
122
+
123
+ :global(.checkbox[data-state='checked']),
124
+ :global(.checkbox[data-state='indeterminate']) {
125
+ background: var(--color-primary, #3b82f6);
126
+ border-color: var(--color-primary, #3b82f6);
127
+ }
128
+
129
+ :global(.checkbox--disabled) {
130
+ opacity: 0.5;
131
+ cursor: not-allowed;
132
+ }
133
+
134
+ :global(.checkbox--error) {
135
+ border-color: var(--color-error, #ef4444);
136
+ }
137
+
138
+ :global(.checkbox--error[data-state='checked']),
139
+ :global(.checkbox--error[data-state='indeterminate']) {
140
+ background: var(--color-error, #ef4444);
141
+ border-color: var(--color-error, #ef4444);
142
+ }
143
+
144
+ .checkbox__indicator {
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ color: var(--color-text-inverse, #ffffff);
149
+ }
150
+
151
+ .checkbox__label {
152
+ font-family: inherit;
153
+ font-size: var(--text-sm, 0.875rem);
154
+ color: var(--color-text, #1f2937);
155
+ cursor: pointer;
156
+ user-select: none;
157
+ min-height: var(--touch-target-min, 44px);
158
+ display: flex;
159
+ align-items: center;
160
+ }
161
+
162
+ .checkbox__label--disabled {
163
+ opacity: 0.5;
164
+ cursor: not-allowed;
165
+ }
166
+ </style>
@@ -0,0 +1,16 @@
1
+ interface Props {
2
+ checked?: boolean;
3
+ indeterminate?: boolean;
4
+ value?: string;
5
+ name?: string;
6
+ id?: string;
7
+ disabled?: boolean;
8
+ required?: boolean;
9
+ error?: boolean;
10
+ class?: string;
11
+ onchange?: (checked: boolean) => void;
12
+ children?: import('svelte').Snippet;
13
+ }
14
+ declare const Checkbox: import("svelte").Component<Props, {}, "checked">;
15
+ type Checkbox = ReturnType<typeof Checkbox>;
16
+ export default Checkbox;
@@ -0,0 +1,55 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ values?: string[];
4
+ name?: string;
5
+ disabled?: boolean;
6
+ error?: boolean;
7
+ class?: string;
8
+ onchange?: (values: string[]) => void;
9
+ children?: import('svelte').Snippet;
10
+ }
11
+
12
+ let {
13
+ values = $bindable([]),
14
+ name,
15
+ disabled = false,
16
+ error = false,
17
+ class: className = '',
18
+ onchange,
19
+ children
20
+ }: Props = $props();
21
+
22
+ function handleCheckboxChange(value: string, checked: boolean | 'indeterminate') {
23
+ if (checked === true) {
24
+ values = [...values, value];
25
+ } else {
26
+ values = values.filter((v) => v !== value);
27
+ }
28
+ onchange?.(values);
29
+ }
30
+ </script>
31
+
32
+ <div
33
+ class="checkbox-group {error ? 'checkbox-group--error' : ''} {disabled
34
+ ? 'checkbox-group--disabled'
35
+ : ''} {className}"
36
+ role="group"
37
+ aria-disabled={disabled}
38
+ >
39
+ {#if children}
40
+ {@render children()}
41
+ {/if}
42
+ </div>
43
+
44
+ <style>
45
+ .checkbox-group {
46
+ display: flex;
47
+ flex-direction: column;
48
+ gap: var(--space-sm, 0.5rem);
49
+ }
50
+
51
+ .checkbox-group--disabled {
52
+ opacity: 0.5;
53
+ pointer-events: none;
54
+ }
55
+ </style>
@@ -0,0 +1,12 @@
1
+ interface Props {
2
+ values?: string[];
3
+ name?: string;
4
+ disabled?: boolean;
5
+ error?: boolean;
6
+ class?: string;
7
+ onchange?: (values: string[]) => void;
8
+ children?: import('svelte').Snippet;
9
+ }
10
+ declare const CheckboxGroup: import("svelte").Component<Props, {}, "values">;
11
+ type CheckboxGroup = ReturnType<typeof CheckboxGroup>;
12
+ export default CheckboxGroup;
@@ -0,0 +1,2 @@
1
+ export { default as Checkbox } from './Checkbox.svelte';
2
+ export { default as CheckboxGroup } from './CheckboxGroup.svelte';
@@ -0,0 +1,2 @@
1
+ export { default as Checkbox } from './Checkbox.svelte';
2
+ export { default as CheckboxGroup } from './CheckboxGroup.svelte';
@@ -0,0 +1,101 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ label?: string;
4
+ htmlFor?: string;
5
+ helperText?: string;
6
+ error?: string;
7
+ required?: boolean;
8
+ disabled?: boolean;
9
+ class?: string;
10
+ children?: import('svelte').Snippet;
11
+ }
12
+
13
+ let {
14
+ label,
15
+ htmlFor,
16
+ helperText,
17
+ error,
18
+ required = false,
19
+ disabled = false,
20
+ class: className = '',
21
+ children
22
+ }: Props = $props();
23
+
24
+ const hasError = $derived(!!error);
25
+ const describedById = $derived(htmlFor ? `${htmlFor}-description` : undefined);
26
+ const showDescription = $derived(hasError ? error : helperText);
27
+ </script>
28
+
29
+ <div class="form-field {className}" class:form-field--disabled={disabled}>
30
+ <label for={htmlFor} class="form-field__label">
31
+ {label}
32
+ {#if required}
33
+ <span class="form-field__required" aria-label="required">*</span>
34
+ {/if}
35
+ </label>
36
+
37
+ <div class="form-field__input">
38
+ {#if children}
39
+ {@render children()}
40
+ {/if}
41
+ </div>
42
+
43
+ {#if showDescription}
44
+ <div
45
+ id={describedById}
46
+ class="form-field__description"
47
+ class:form-field__description--error={hasError}
48
+ role={hasError ? 'alert' : undefined}
49
+ aria-live={hasError ? 'polite' : undefined}
50
+ >
51
+ {showDescription}
52
+ </div>
53
+ {/if}
54
+ </div>
55
+
56
+ <style>
57
+ .form-field {
58
+ display: flex;
59
+ flex-direction: column;
60
+ gap: var(--space-xs, 0.25rem);
61
+ width: 100%;
62
+ }
63
+
64
+ .form-field--disabled {
65
+ opacity: 0.5;
66
+ pointer-events: none;
67
+ }
68
+
69
+ .form-field__label {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: var(--space-xs, 0.25rem);
73
+ font-family: inherit;
74
+ font-size: var(--text-sm, 0.875rem);
75
+ font-weight: 600;
76
+ color: var(--color-text, #1f2937);
77
+ line-height: 1.5;
78
+ min-height: var(--touch-target-min, 44px);
79
+ }
80
+
81
+ .form-field__required {
82
+ color: var(--color-destructive, #ef4444);
83
+ font-weight: 700;
84
+ }
85
+
86
+ .form-field__input {
87
+ width: 100%;
88
+ }
89
+
90
+ .form-field__description {
91
+ font-family: inherit;
92
+ font-size: var(--text-sm, 0.875rem);
93
+ line-height: 1.5;
94
+ color: var(--color-text-muted, #6b7280);
95
+ }
96
+
97
+ .form-field__description--error {
98
+ color: var(--color-destructive, #ef4444);
99
+ font-weight: 500;
100
+ }
101
+ </style>
@@ -0,0 +1,13 @@
1
+ interface Props {
2
+ label?: string;
3
+ htmlFor?: string;
4
+ helperText?: string;
5
+ error?: string;
6
+ required?: boolean;
7
+ disabled?: boolean;
8
+ class?: string;
9
+ children?: import('svelte').Snippet;
10
+ }
11
+ declare const FormField: import("svelte").Component<Props, {}, "">;
12
+ type FormField = ReturnType<typeof FormField>;
13
+ export default FormField;
@@ -0,0 +1 @@
1
+ export { default as FormField } from './FormField.svelte';
@@ -0,0 +1 @@
1
+ export { default as FormField } from './FormField.svelte';
@@ -0,0 +1,47 @@
1
+ <script lang="ts">
2
+ import type { IconSize } from '../../types/index.js';
3
+
4
+ interface Props {
5
+ name: string;
6
+ size?: IconSize;
7
+ class?: string;
8
+ 'aria-label'?: string;
9
+ 'aria-hidden'?: boolean;
10
+ }
11
+
12
+ let {
13
+ name,
14
+ size = 'md',
15
+ class: className = '',
16
+ 'aria-label': ariaLabel,
17
+ 'aria-hidden': ariaHidden = !ariaLabel
18
+ }: Props = $props();
19
+
20
+ // Size map aligned with typography scale
21
+ const sizeMap: Record<IconSize, string> = {
22
+ xs: '0.75rem',
23
+ sm: '1rem',
24
+ md: '1.25rem',
25
+ lg: '1.5rem',
26
+ xl: '2rem'
27
+ };
28
+ </script>
29
+
30
+ <svg
31
+ class="icon icon--{size} {className}"
32
+ style="--icon-size: {sizeMap[size]}"
33
+ aria-label={ariaLabel}
34
+ aria-hidden={ariaHidden}
35
+ role={ariaLabel ? 'img' : undefined}
36
+ >
37
+ <use href="#{name}" />
38
+ </svg>
39
+
40
+ <style>
41
+ .icon {
42
+ width: var(--icon-size);
43
+ height: var(--icon-size);
44
+ fill: currentColor;
45
+ flex-shrink: 0;
46
+ }
47
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { IconSize } from '../../types/index.js';
2
+ interface Props {
3
+ name: string;
4
+ size?: IconSize;
5
+ class?: string;
6
+ 'aria-label'?: string;
7
+ 'aria-hidden'?: boolean;
8
+ }
9
+ declare const Icon: import("svelte").Component<Props, {}, "">;
10
+ type Icon = ReturnType<typeof Icon>;
11
+ export default Icon;
@@ -0,0 +1,2 @@
1
+ export { default as Icon } from './Icon.svelte';
2
+ export type { IconProps, IconSize } from '../../types/index.js';
@@ -0,0 +1 @@
1
+ export { default as Icon } from './Icon.svelte';