@salmexio/ui 1.2.0 → 1.3.0

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 (78) hide show
  1. package/dist/feedback/Alert/Alert.svelte +4 -1
  2. package/dist/feedback/Alert/Alert.svelte.d.ts +1 -0
  3. package/dist/feedback/Alert/Alert.svelte.d.ts.map +1 -1
  4. package/dist/feedback/Spinner/Spinner.svelte +4 -1
  5. package/dist/feedback/Spinner/Spinner.svelte.d.ts +1 -0
  6. package/dist/feedback/Spinner/Spinner.svelte.d.ts.map +1 -1
  7. package/dist/forms/DatePicker/DatePicker.svelte +725 -0
  8. package/dist/forms/DatePicker/DatePicker.svelte.d.ts +48 -0
  9. package/dist/forms/DatePicker/DatePicker.svelte.d.ts.map +1 -0
  10. package/dist/forms/DatePicker/index.d.ts +2 -0
  11. package/dist/forms/DatePicker/index.d.ts.map +1 -0
  12. package/dist/forms/DatePicker/index.js +1 -0
  13. package/dist/forms/FormField/FormField.svelte +173 -0
  14. package/dist/forms/FormField/FormField.svelte.d.ts +46 -0
  15. package/dist/forms/FormField/FormField.svelte.d.ts.map +1 -0
  16. package/dist/forms/FormField/index.d.ts +2 -0
  17. package/dist/forms/FormField/index.d.ts.map +1 -0
  18. package/dist/forms/FormField/index.js +1 -0
  19. package/dist/forms/MultiSelect/MultiSelect.svelte +820 -0
  20. package/dist/forms/MultiSelect/MultiSelect.svelte.d.ts +69 -0
  21. package/dist/forms/MultiSelect/MultiSelect.svelte.d.ts.map +1 -0
  22. package/dist/forms/MultiSelect/index.d.ts +3 -0
  23. package/dist/forms/MultiSelect/index.d.ts.map +1 -0
  24. package/dist/forms/MultiSelect/index.js +1 -0
  25. package/dist/forms/PhoneInput/PhoneInput.svelte +591 -0
  26. package/dist/forms/PhoneInput/PhoneInput.svelte.d.ts +57 -0
  27. package/dist/forms/PhoneInput/PhoneInput.svelte.d.ts.map +1 -0
  28. package/dist/forms/PhoneInput/index.d.ts +4 -0
  29. package/dist/forms/PhoneInput/index.d.ts.map +1 -0
  30. package/dist/forms/PhoneInput/index.js +2 -0
  31. package/dist/forms/RadioGroup/RadioGroup.svelte +417 -0
  32. package/dist/forms/RadioGroup/RadioGroup.svelte.d.ts +62 -0
  33. package/dist/forms/RadioGroup/RadioGroup.svelte.d.ts.map +1 -0
  34. package/dist/forms/RadioGroup/index.d.ts +3 -0
  35. package/dist/forms/RadioGroup/index.d.ts.map +1 -0
  36. package/dist/forms/RadioGroup/index.js +1 -0
  37. package/dist/forms/SearchInput/SearchInput.svelte +788 -0
  38. package/dist/forms/SearchInput/SearchInput.svelte.d.ts +79 -0
  39. package/dist/forms/SearchInput/SearchInput.svelte.d.ts.map +1 -0
  40. package/dist/forms/SearchInput/index.d.ts +3 -0
  41. package/dist/forms/SearchInput/index.d.ts.map +1 -0
  42. package/dist/forms/SearchInput/index.js +1 -0
  43. package/dist/forms/Select/Select.svelte +14 -8
  44. package/dist/forms/Select/Select.svelte.d.ts +2 -0
  45. package/dist/forms/Select/Select.svelte.d.ts.map +1 -1
  46. package/dist/forms/TextInput/TextInput.svelte +38 -16
  47. package/dist/forms/TextInput/TextInput.svelte.d.ts +6 -0
  48. package/dist/forms/TextInput/TextInput.svelte.d.ts.map +1 -1
  49. package/dist/forms/Textarea/Textarea.svelte +7 -1
  50. package/dist/forms/Textarea/Textarea.svelte.d.ts +2 -0
  51. package/dist/forms/Textarea/Textarea.svelte.d.ts.map +1 -1
  52. package/dist/forms/TimePicker/TimePicker.svelte +417 -0
  53. package/dist/forms/TimePicker/TimePicker.svelte.d.ts +53 -0
  54. package/dist/forms/TimePicker/TimePicker.svelte.d.ts.map +1 -0
  55. package/dist/forms/TimePicker/index.d.ts +2 -0
  56. package/dist/forms/TimePicker/index.d.ts.map +1 -0
  57. package/dist/forms/TimePicker/index.js +1 -0
  58. package/dist/forms/index.d.ts +12 -0
  59. package/dist/forms/index.d.ts.map +1 -1
  60. package/dist/forms/index.js +8 -0
  61. package/dist/layout/Container/Container.svelte +3 -0
  62. package/dist/layout/Container/Container.svelte.d.ts +1 -0
  63. package/dist/layout/Container/Container.svelte.d.ts.map +1 -1
  64. package/dist/primitives/Badge/Badge.svelte +5 -1
  65. package/dist/primitives/Badge/Badge.svelte.d.ts +1 -0
  66. package/dist/primitives/Badge/Badge.svelte.d.ts.map +1 -1
  67. package/dist/primitives/Tooltip/Tooltip.svelte +30 -0
  68. package/dist/primitives/Tooltip/Tooltip.svelte.d.ts.map +1 -1
  69. package/dist/utils/accessibility.d.ts +16 -0
  70. package/dist/utils/accessibility.d.ts.map +1 -0
  71. package/dist/utils/accessibility.js +80 -0
  72. package/dist/utils/index.d.ts +2 -1
  73. package/dist/utils/index.d.ts.map +1 -1
  74. package/dist/utils/index.js +2 -1
  75. package/dist/utils/keyboard.d.ts +6 -0
  76. package/dist/utils/keyboard.d.ts.map +1 -1
  77. package/dist/utils/keyboard.js +15 -9
  78. package/package.json +21 -1
@@ -0,0 +1,57 @@
1
+ export interface Country {
2
+ code: string;
3
+ name: string;
4
+ dial: string;
5
+ flag: string;
6
+ }
7
+ export declare const DEFAULT_COUNTRIES: Country[];
8
+ type PhoneSize = 'sm' | 'md' | 'lg';
9
+ interface Props {
10
+ /** Visible label. */
11
+ label: string;
12
+ /** Phone number value (E.164 format: +1234567890). */
13
+ value?: string;
14
+ /** Default country code. */
15
+ defaultCountry?: string;
16
+ /** Available countries list. */
17
+ countries?: Country[];
18
+ /** Placeholder for the number field. */
19
+ placeholder?: string;
20
+ /** Size variant. */
21
+ size?: PhoneSize;
22
+ /** Required field. */
23
+ required?: boolean;
24
+ /** Disabled state. */
25
+ disabled?: boolean;
26
+ /** Error message. */
27
+ error?: string;
28
+ /** Hint text. */
29
+ hint?: string;
30
+ /** Hide the visible label. */
31
+ hideLabel?: boolean;
32
+ /** Reserve footer space even when empty. */
33
+ alwaysShowFooter?: boolean;
34
+ /** Additional CSS class. */
35
+ class?: string;
36
+ /** Called when value changes. */
37
+ onchange?: (value: string) => void;
38
+ /** Custom validation function. */
39
+ validate?: (value: string) => string | undefined;
40
+ /** Test ID. */
41
+ testId?: string;
42
+ }
43
+ /**
44
+ * PhoneInput
45
+ *
46
+ * INFRARED — International phone number input with country code selector,
47
+ * auto-formatting, and E.164 output. Zero external dependencies.
48
+ * Country list is curated for common use; extend via the countries prop.
49
+ *
50
+ * @example
51
+ * <PhoneInput label="Phone number" bind:value={phone} />
52
+ * <PhoneInput label="Mobile" defaultCountry="GB" />
53
+ */
54
+ declare const PhoneInput: import("svelte").Component<Props, {}, "value">;
55
+ type PhoneInput = ReturnType<typeof PhoneInput>;
56
+ export default PhoneInput;
57
+ //# sourceMappingURL=PhoneInput.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PhoneInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/PhoneInput/PhoneInput.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,iBAAiB,EAAE,OAAO,EA0BtC,CAAC;AAQF,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEpC,UAAU,KAAK;IACd,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;IACtB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,kCAAkC;IAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACjD,eAAe;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAqSD;;;;;;;;;;GAUG;AACH,QAAA,MAAM,UAAU,gDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { default as PhoneInput } from './PhoneInput.svelte';
2
+ export type { Country } from './PhoneInput.svelte';
3
+ export { DEFAULT_COUNTRIES } from './PhoneInput.svelte';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/forms/PhoneInput/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { default as PhoneInput } from './PhoneInput.svelte';
2
+ export { DEFAULT_COUNTRIES } from './PhoneInput.svelte';
@@ -0,0 +1,417 @@
1
+ <!--
2
+ @component RadioGroup
3
+
4
+ INFRARED — Accessible radio button group with fieldset/legend pattern.
5
+ Custom visuals using native <input type="radio"> for best a11y.
6
+ Supports descriptions, horizontal/vertical layout, sizes, and error states.
7
+
8
+ @example
9
+ <RadioGroup
10
+ label="Model"
11
+ options={[
12
+ { value: 'opus', label: 'Claude Opus', description: 'Most capable' },
13
+ { value: 'sonnet', label: 'Claude Sonnet', description: 'Balanced' },
14
+ { value: 'haiku', label: 'Claude Haiku', description: 'Fastest' },
15
+ ]}
16
+ bind:value={selectedModel}
17
+ />
18
+ -->
19
+ <script lang="ts" module>
20
+ export interface RadioOption {
21
+ value: string;
22
+ label: string;
23
+ description?: string;
24
+ disabled?: boolean;
25
+ }
26
+ </script>
27
+
28
+ <script lang="ts">
29
+ import { cn } from '../../utils/cn.js';
30
+ import { generateId } from '../../utils/keyboard.js';
31
+
32
+ type RadioSize = 'sm' | 'md' | 'lg';
33
+ type RadioOrientation = 'vertical' | 'horizontal';
34
+
35
+ interface Props {
36
+ /** Group label (rendered as legend). */
37
+ label: string;
38
+ /** Radio options. */
39
+ options: RadioOption[];
40
+ /** Currently selected value. */
41
+ value?: string;
42
+ /** HTML name attribute for the radio group. */
43
+ name?: string;
44
+ /** Required field. */
45
+ required?: boolean;
46
+ /** Disable all options. */
47
+ disabled?: boolean;
48
+ /** Error message. */
49
+ error?: string;
50
+ /** Hint text. */
51
+ hint?: string;
52
+ /** Size variant. */
53
+ size?: RadioSize;
54
+ /** Layout direction. */
55
+ orientation?: RadioOrientation;
56
+ /** Hide the legend visually. */
57
+ hideLabel?: boolean;
58
+ /** Reserve footer space even when empty. */
59
+ alwaysShowFooter?: boolean;
60
+ /** Additional CSS class. */
61
+ class?: string;
62
+ /** Change handler. */
63
+ onchange?: (value: string) => void;
64
+ /** Test ID. */
65
+ testId?: string;
66
+ }
67
+
68
+ let {
69
+ label,
70
+ options,
71
+ value = $bindable(''),
72
+ name = generateId('radio'),
73
+ required = false,
74
+ disabled = false,
75
+ error = '',
76
+ hint = '',
77
+ size = 'md',
78
+ orientation = 'vertical',
79
+ hideLabel = false,
80
+ alwaysShowFooter = true,
81
+ class: className = '',
82
+ onchange,
83
+ testId
84
+ }: Props = $props();
85
+
86
+ let hasInteracted = $state(false);
87
+
88
+ const showError = $derived(hasInteracted && !!error);
89
+ const errorId = $derived(`${name}-error`);
90
+ const hintId = $derived(`${name}-hint`);
91
+
92
+ const hasFooterContent = $derived(showError || !!hint);
93
+
94
+ function handleChange(optValue: string) {
95
+ value = optValue;
96
+ hasInteracted = true;
97
+ onchange?.(optValue);
98
+ }
99
+ </script>
100
+
101
+ <fieldset
102
+ class={cn(
103
+ 'sx-radio-group',
104
+ `sx-radio-${size}`,
105
+ disabled && 'sx-radio-disabled',
106
+ className
107
+ )}
108
+ {disabled}
109
+ aria-describedby={[showError && errorId, hint && hintId].filter(Boolean).join(' ') || undefined}
110
+ data-testid={testId}
111
+ >
112
+ <legend class={cn('sx-radio-legend', hideLabel && 'sx-sr-only')}>
113
+ {label}
114
+ {#if required}
115
+ <span class="sx-radio-required" aria-hidden="true">*</span>
116
+ {/if}
117
+ </legend>
118
+
119
+ <div class={cn('sx-radio-options', `sx-radio-${orientation}`)}>
120
+ {#each options as opt}
121
+ {@const optId = `${name}-${opt.value}`}
122
+ {@const isSelected = value === opt.value}
123
+ {@const isDisabled = disabled || !!opt.disabled}
124
+ {@const descId = opt.description ? `${optId}-desc` : undefined}
125
+ <label
126
+ for={optId}
127
+ class={cn(
128
+ 'sx-radio-option',
129
+ isSelected && 'sx-radio-option-selected',
130
+ isDisabled && 'sx-radio-option-disabled'
131
+ )}
132
+ >
133
+ <input
134
+ id={optId}
135
+ type="radio"
136
+ {name}
137
+ value={opt.value}
138
+ checked={isSelected}
139
+ disabled={isDisabled}
140
+ class="sx-radio-input"
141
+ aria-describedby={descId}
142
+ onchange={() => handleChange(opt.value)}
143
+ />
144
+ <span
145
+ class={cn(
146
+ 'sx-radio-circle',
147
+ isSelected && 'sx-radio-circle-checked',
148
+ showError && 'sx-radio-circle-error'
149
+ )}
150
+ aria-hidden="true"
151
+ >
152
+ {#if isSelected}
153
+ <span class="sx-radio-dot"></span>
154
+ {/if}
155
+ </span>
156
+ <span class="sx-radio-content">
157
+ <span class="sx-radio-text">{opt.label}</span>
158
+ {#if opt.description}
159
+ <span id={descId} class="sx-radio-description">{opt.description}</span>
160
+ {/if}
161
+ </span>
162
+ </label>
163
+ {/each}
164
+ </div>
165
+
166
+ {#if alwaysShowFooter || hasFooterContent}
167
+ <div class="sx-radio-footer">
168
+ {#if showError}
169
+ <p id={errorId} class="sx-radio-error" role="alert" aria-live="assertive">{error}</p>
170
+ {:else if hint}
171
+ <p id={hintId} class="sx-radio-hint">{hint}</p>
172
+ {/if}
173
+ </div>
174
+ {/if}
175
+ </fieldset>
176
+
177
+ <style>
178
+ .sx-radio-group {
179
+ display: flex;
180
+ flex-direction: column;
181
+ gap: var(--sx-space-2);
182
+ border: none;
183
+ padding: 0;
184
+ margin: 0;
185
+ }
186
+
187
+ .sx-radio-disabled {
188
+ opacity: 0.5;
189
+ }
190
+
191
+ .sx-radio-legend {
192
+ font-family: var(--sx-font-body);
193
+ font-weight: 500;
194
+ font-size: var(--sx-text-sm);
195
+ color: var(--sx-color-text-secondary);
196
+ padding: 0;
197
+ margin-bottom: var(--sx-space-1);
198
+ }
199
+
200
+ .sx-radio-required {
201
+ color: var(--sx-color-red);
202
+ margin-left: 2px;
203
+ }
204
+
205
+ .sx-sr-only {
206
+ position: absolute;
207
+ width: 1px;
208
+ height: 1px;
209
+ padding: 0;
210
+ margin: -1px;
211
+ overflow: hidden;
212
+ clip: rect(0, 0, 0, 0);
213
+ white-space: nowrap;
214
+ border: 0;
215
+ }
216
+
217
+ .sx-radio-options {
218
+ display: flex;
219
+ gap: var(--sx-space-2);
220
+ }
221
+
222
+ .sx-radio-vertical {
223
+ flex-direction: column;
224
+ }
225
+
226
+ .sx-radio-horizontal {
227
+ flex-direction: row;
228
+ flex-wrap: wrap;
229
+ }
230
+
231
+ /* Option row */
232
+ .sx-radio-option {
233
+ display: flex;
234
+ align-items: flex-start;
235
+ gap: var(--sx-space-2);
236
+ cursor: pointer;
237
+ user-select: none;
238
+ font-family: var(--sx-font-body);
239
+ padding: var(--sx-space-1) 0;
240
+ }
241
+
242
+ .sx-radio-option-disabled {
243
+ cursor: not-allowed;
244
+ }
245
+
246
+ /* Hidden native input */
247
+ .sx-radio-input {
248
+ position: absolute;
249
+ width: 1px;
250
+ height: 1px;
251
+ padding: 0;
252
+ margin: -1px;
253
+ overflow: hidden;
254
+ clip: rect(0, 0, 0, 0);
255
+ white-space: nowrap;
256
+ border: 0;
257
+ }
258
+
259
+ /* Custom radio circle */
260
+ .sx-radio-circle {
261
+ flex-shrink: 0;
262
+ display: flex;
263
+ align-items: center;
264
+ justify-content: center;
265
+ border-radius: 50%;
266
+ background: var(--sx-color-surface);
267
+ border: 1px solid var(--sx-color-border-strong);
268
+ box-shadow:
269
+ inset 0 1px 3px rgba(0, 0, 0, 0.3),
270
+ inset 0 0 0 1px rgba(0, 0, 0, 0.06);
271
+ transition:
272
+ background var(--sx-transition-fast),
273
+ border-color var(--sx-transition-fast),
274
+ box-shadow var(--sx-transition-fast);
275
+ }
276
+
277
+ .sx-radio-sm .sx-radio-circle {
278
+ width: 16px;
279
+ height: 16px;
280
+ }
281
+
282
+ .sx-radio-md .sx-radio-circle {
283
+ width: 20px;
284
+ height: 20px;
285
+ }
286
+
287
+ .sx-radio-lg .sx-radio-circle {
288
+ width: 24px;
289
+ height: 24px;
290
+ }
291
+
292
+ /* Hover */
293
+ .sx-radio-option:hover .sx-radio-circle:not(.sx-radio-circle-checked) {
294
+ border-color: var(--sx-color-border-hover);
295
+ }
296
+
297
+ /* Focus */
298
+ .sx-radio-input:focus-visible + .sx-radio-circle {
299
+ outline: 2px solid var(--sx-color-primary);
300
+ outline-offset: 2px;
301
+ box-shadow:
302
+ inset 0 1px 3px rgba(0, 0, 0, 0.3),
303
+ 0 0 12px -4px var(--sx-color-primary-ring);
304
+ }
305
+
306
+ /* Checked */
307
+ .sx-radio-circle-checked {
308
+ background: var(--sx-gradient-brand);
309
+ border-color: var(--sx-color-primary-ring);
310
+ box-shadow:
311
+ 0 1px 0 0 rgba(0, 0, 0, 0.15),
312
+ 0 0 6px -2px var(--sx-color-primary-ring);
313
+ }
314
+
315
+ .sx-radio-input:focus-visible + .sx-radio-circle-checked {
316
+ box-shadow:
317
+ 0 1px 0 0 rgba(0, 0, 0, 0.15),
318
+ 0 0 10px -2px var(--sx-color-primary-ring);
319
+ }
320
+
321
+ /* Error */
322
+ .sx-radio-circle-error:not(.sx-radio-circle-checked) {
323
+ border-color: var(--sx-color-red);
324
+ box-shadow:
325
+ inset 0 1px 3px rgba(0, 0, 0, 0.3),
326
+ 0 0 8px -4px rgba(220, 38, 38, 0.2);
327
+ }
328
+
329
+ /* Inner dot */
330
+ .sx-radio-dot {
331
+ width: 40%;
332
+ height: 40%;
333
+ border-radius: 50%;
334
+ background: #fff;
335
+ animation: sx-check-in var(--sx-duration-fast) var(--sx-ease-out) both;
336
+ }
337
+
338
+ /* Text */
339
+ .sx-radio-content {
340
+ display: flex;
341
+ flex-direction: column;
342
+ gap: 2px;
343
+ padding-top: 1px;
344
+ }
345
+
346
+ .sx-radio-text {
347
+ font-size: var(--sx-text-sm);
348
+ font-weight: 500;
349
+ color: var(--sx-color-text);
350
+ }
351
+
352
+ .sx-radio-description {
353
+ font-size: var(--sx-text-xs);
354
+ color: var(--sx-color-text-secondary);
355
+ }
356
+
357
+ /* Footer */
358
+ .sx-radio-footer {
359
+ min-height: 1.25rem;
360
+ }
361
+
362
+ .sx-radio-error {
363
+ font-size: var(--sx-text-xs);
364
+ font-weight: 500;
365
+ color: var(--sx-color-red);
366
+ margin: 0;
367
+ }
368
+
369
+ .sx-radio-hint {
370
+ font-size: var(--sx-text-xs);
371
+ color: var(--sx-color-text-secondary);
372
+ margin: 0;
373
+ }
374
+
375
+ /* Size adjustments */
376
+ .sx-radio-sm .sx-radio-text {
377
+ font-size: var(--sx-text-xs);
378
+ }
379
+
380
+ .sx-radio-sm .sx-radio-legend {
381
+ font-size: var(--sx-text-xs);
382
+ }
383
+
384
+ .sx-radio-lg .sx-radio-text {
385
+ font-size: var(--sx-text-base);
386
+ }
387
+
388
+ .sx-radio-lg .sx-radio-legend {
389
+ font-size: var(--sx-text-base);
390
+ }
391
+
392
+ @media (prefers-reduced-motion: reduce) {
393
+ .sx-radio-circle {
394
+ transition: none;
395
+ }
396
+
397
+ .sx-radio-dot {
398
+ animation: none;
399
+ }
400
+ }
401
+
402
+ @media (forced-colors: active) {
403
+ .sx-radio-input:focus-visible + .sx-radio-circle {
404
+ outline: 2px solid CanvasText;
405
+ outline-offset: 2px;
406
+ }
407
+
408
+ .sx-radio-circle-checked {
409
+ background: Highlight;
410
+ border-color: Highlight;
411
+ }
412
+
413
+ .sx-radio-dot {
414
+ background: HighlightText;
415
+ }
416
+ }
417
+ </style>
@@ -0,0 +1,62 @@
1
+ export interface RadioOption {
2
+ value: string;
3
+ label: string;
4
+ description?: string;
5
+ disabled?: boolean;
6
+ }
7
+ type RadioSize = 'sm' | 'md' | 'lg';
8
+ type RadioOrientation = 'vertical' | 'horizontal';
9
+ interface Props {
10
+ /** Group label (rendered as legend). */
11
+ label: string;
12
+ /** Radio options. */
13
+ options: RadioOption[];
14
+ /** Currently selected value. */
15
+ value?: string;
16
+ /** HTML name attribute for the radio group. */
17
+ name?: string;
18
+ /** Required field. */
19
+ required?: boolean;
20
+ /** Disable all options. */
21
+ disabled?: boolean;
22
+ /** Error message. */
23
+ error?: string;
24
+ /** Hint text. */
25
+ hint?: string;
26
+ /** Size variant. */
27
+ size?: RadioSize;
28
+ /** Layout direction. */
29
+ orientation?: RadioOrientation;
30
+ /** Hide the legend visually. */
31
+ hideLabel?: boolean;
32
+ /** Reserve footer space even when empty. */
33
+ alwaysShowFooter?: boolean;
34
+ /** Additional CSS class. */
35
+ class?: string;
36
+ /** Change handler. */
37
+ onchange?: (value: string) => void;
38
+ /** Test ID. */
39
+ testId?: string;
40
+ }
41
+ /**
42
+ * RadioGroup
43
+ *
44
+ * INFRARED — Accessible radio button group with fieldset/legend pattern.
45
+ * Custom visuals using native <input type="radio"> for best a11y.
46
+ * Supports descriptions, horizontal/vertical layout, sizes, and error states.
47
+ *
48
+ * @example
49
+ * <RadioGroup
50
+ * label="Model"
51
+ * options={[
52
+ * { value: 'opus', label: 'Claude Opus', description: 'Most capable' },
53
+ * { value: 'sonnet', label: 'Claude Sonnet', description: 'Balanced' },
54
+ * { value: 'haiku', label: 'Claude Haiku', description: 'Fastest' },
55
+ * ]}
56
+ * bind:value={selectedModel}
57
+ * />
58
+ */
59
+ declare const RadioGroup: import("svelte").Component<Props, {}, "value">;
60
+ type RadioGroup = ReturnType<typeof RadioGroup>;
61
+ export default RadioGroup;
62
+ //# sourceMappingURL=RadioGroup.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.svelte.d.ts","sourceRoot":"","sources":["../../../src/forms/RadioGroup/RadioGroup.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAOD,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACpC,KAAK,gBAAgB,GAAG,UAAU,GAAG,YAAY,CAAC;AAElD,UAAU,KAAK;IACd,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,wBAAwB;IACxB,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,eAAe;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAuGD;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,UAAU,gDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { default as RadioGroup } from './RadioGroup.svelte';
2
+ export type { RadioOption } from './RadioGroup.svelte';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/forms/RadioGroup/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1 @@
1
+ export { default as RadioGroup } from './RadioGroup.svelte';