@marianmeres/stuic 2.65.0 → 3.0.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 (171) hide show
  1. package/README.md +292 -4
  2. package/dist/README.md +41 -18
  3. package/dist/actions/popover/README.md +19 -0
  4. package/dist/actions/popover/index.css +6 -9
  5. package/dist/actions/popover/popover.svelte.js +2 -2
  6. package/dist/actions/tooltip/README.md +18 -0
  7. package/dist/actions/tooltip/index.css +5 -8
  8. package/dist/actions/tooltip/tooltip.svelte.js +1 -1
  9. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +9 -10
  10. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +3 -3
  11. package/dist/components/AlertConfirmPrompt/Current.svelte +15 -17
  12. package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +5 -3
  13. package/dist/components/AlertConfirmPrompt/acp-icons.js +5 -4
  14. package/dist/components/AlertConfirmPrompt/index.css +62 -0
  15. package/dist/components/AssetsPreview/AssetsPreview.svelte +92 -73
  16. package/dist/components/AssetsPreview/AssetsPreview.svelte.d.ts +1 -0
  17. package/dist/components/AssetsPreview/index.css +59 -0
  18. package/dist/components/Avatar/Avatar.svelte +32 -18
  19. package/dist/components/Avatar/Avatar.svelte.d.ts +1 -0
  20. package/dist/components/Avatar/README.md +166 -0
  21. package/dist/components/Avatar/index.css +128 -0
  22. package/dist/components/Backdrop/Backdrop.svelte +8 -2
  23. package/dist/components/Backdrop/Backdrop.svelte.d.ts +1 -0
  24. package/dist/components/Backdrop/README.md +71 -6
  25. package/dist/components/Backdrop/index.css +29 -0
  26. package/dist/components/Button/Button.svelte +117 -124
  27. package/dist/components/Button/Button.svelte.d.ts +35 -23
  28. package/dist/components/Button/README.md +87 -21
  29. package/dist/components/Button/index.css +473 -9
  30. package/dist/components/Button/index.d.ts +1 -1
  31. package/dist/components/Button/index.js +1 -1
  32. package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte +7 -38
  33. package/dist/components/ButtonGroupRadio/README.md +82 -4
  34. package/dist/components/ButtonGroupRadio/index.css +152 -14
  35. package/dist/components/Collapsible/Collapsible.svelte +7 -7
  36. package/dist/components/Collapsible/Collapsible.svelte.d.ts +2 -2
  37. package/dist/components/Collapsible/README.md +34 -2
  38. package/dist/components/Collapsible/index.css +38 -0
  39. package/dist/components/CommandMenu/CommandMenu.svelte +13 -24
  40. package/dist/components/CommandMenu/README.md +39 -0
  41. package/dist/components/CommandMenu/index.css +45 -2
  42. package/dist/components/DismissibleMessage/DismissibleMessage.svelte +53 -50
  43. package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +6 -5
  44. package/dist/components/DismissibleMessage/README.md +93 -11
  45. package/dist/components/DismissibleMessage/index.css +122 -8
  46. package/dist/components/DismissibleMessage/index.d.ts +1 -1
  47. package/dist/components/DropdownMenu/DropdownMenu.svelte +14 -50
  48. package/dist/components/DropdownMenu/DropdownMenu.svelte.d.ts +6 -6
  49. package/dist/components/DropdownMenu/README.md +132 -0
  50. package/dist/components/DropdownMenu/index.css +231 -27
  51. package/dist/components/Input/FieldAssets.svelte +8 -5
  52. package/dist/components/Input/FieldCheckbox.svelte +7 -44
  53. package/dist/components/Input/FieldFile.svelte +1 -6
  54. package/dist/components/Input/FieldInput.svelte +1 -1
  55. package/dist/components/Input/FieldOptions.svelte +41 -38
  56. package/dist/components/Input/FieldRadios.svelte +7 -16
  57. package/dist/components/Input/FieldSelect.svelte +1 -1
  58. package/dist/components/Input/FieldSwitch.svelte +1 -5
  59. package/dist/components/Input/FieldTextarea.svelte +1 -1
  60. package/dist/components/Input/README.md +194 -0
  61. package/dist/components/Input/_internal/FieldRadioInternal.svelte +2 -40
  62. package/dist/components/Input/_internal/InputWrap.svelte +8 -48
  63. package/dist/components/Input/index.css +522 -127
  64. package/dist/components/ListItemButton/ListItemButton.svelte +37 -73
  65. package/dist/components/ListItemButton/ListItemButton.svelte.d.ts +1 -9
  66. package/dist/components/ListItemButton/README.md +100 -45
  67. package/dist/components/ListItemButton/index.css +175 -56
  68. package/dist/components/ListItemButton/index.d.ts +1 -1
  69. package/dist/components/ListItemButton/index.js +1 -1
  70. package/dist/components/Modal/Modal.svelte +2 -8
  71. package/dist/components/Modal/Modal.svelte.d.ts +1 -0
  72. package/dist/components/Modal/README.md +29 -0
  73. package/dist/components/Modal/index.css +36 -0
  74. package/dist/components/ModalDialog/ModalDialog.svelte +2 -21
  75. package/dist/components/ModalDialog/README.md +35 -0
  76. package/dist/components/ModalDialog/index.css +57 -0
  77. package/dist/components/Notifications/Notifications.svelte +44 -128
  78. package/dist/components/Notifications/Notifications.svelte.d.ts +9 -17
  79. package/dist/components/Notifications/README.md +186 -70
  80. package/dist/components/Notifications/index.css +212 -15
  81. package/dist/components/Progress/README.md +15 -0
  82. package/dist/components/Progress/_internal/Bar.svelte +2 -2
  83. package/dist/components/Progress/index.css +4 -4
  84. package/dist/components/Skeleton/Skeleton.svelte +3 -2
  85. package/dist/components/Skeleton/index.css +11 -14
  86. package/dist/components/Spinner/Spinner.svelte +2 -2
  87. package/dist/components/Spinner/SpinnerCircle.svelte +1 -1
  88. package/dist/components/Switch/README.md +15 -0
  89. package/dist/components/Switch/Switch.svelte +4 -7
  90. package/dist/components/Switch/Switch.svelte.d.ts +1 -1
  91. package/dist/components/Switch/SwitchButton.svelte +4 -5
  92. package/dist/components/Switch/index.css +3 -4
  93. package/dist/components/TabbedMenu/README.md +26 -21
  94. package/dist/components/TabbedMenu/TabbedMenu.svelte +5 -5
  95. package/dist/components/TabbedMenu/index.css +7 -22
  96. package/dist/components/ThemePreview/README.md +289 -0
  97. package/dist/components/ThemePreview/ThemePreview.svelte +341 -0
  98. package/dist/components/ThemePreview/ThemePreview.svelte.d.ts +33 -0
  99. package/dist/components/ThemePreview/index.css +493 -0
  100. package/dist/components/ThemePreview/index.d.ts +1 -0
  101. package/dist/components/ThemePreview/index.js +1 -0
  102. package/dist/components/TwCheck/TwCheck.svelte +4 -4
  103. package/dist/components/TwCheck/index.css +3 -2
  104. package/dist/components/TypeaheadInput/TypeaheadInput.svelte +1 -1
  105. package/dist/components/X/X.svelte +16 -4
  106. package/dist/components/X/X.svelte.d.ts +1 -0
  107. package/dist/icons/index.d.ts +1 -0
  108. package/dist/icons/index.js +1 -0
  109. package/dist/index.css +31 -16
  110. package/dist/index.d.ts +1 -0
  111. package/dist/index.js +1 -0
  112. package/dist/themes/blue-orange.css +163 -0
  113. package/dist/themes/blue-orange.d.ts +6 -0
  114. package/dist/themes/blue-orange.js +151 -0
  115. package/dist/themes/cyan-red.css +163 -0
  116. package/dist/themes/cyan-red.d.ts +6 -0
  117. package/dist/themes/cyan-red.js +151 -0
  118. package/dist/themes/cyan-slate.css +163 -0
  119. package/dist/themes/cyan-slate.d.ts +6 -0
  120. package/dist/themes/cyan-slate.js +151 -0
  121. package/dist/themes/emerald-pink.css +163 -0
  122. package/dist/themes/emerald-pink.d.ts +6 -0
  123. package/dist/themes/emerald-pink.js +151 -0
  124. package/dist/themes/fuchsia-emerald.css +163 -0
  125. package/dist/themes/fuchsia-emerald.d.ts +6 -0
  126. package/dist/themes/fuchsia-emerald.js +151 -0
  127. package/dist/themes/gray.css +163 -0
  128. package/dist/themes/gray.d.ts +6 -0
  129. package/dist/themes/gray.js +151 -0
  130. package/dist/themes/indigo-amber.css +163 -0
  131. package/dist/themes/indigo-amber.d.ts +6 -0
  132. package/dist/themes/indigo-amber.js +151 -0
  133. package/dist/themes/neutral.css +163 -0
  134. package/dist/themes/neutral.d.ts +6 -0
  135. package/dist/themes/neutral.js +151 -0
  136. package/dist/themes/pink-emerald.css +163 -0
  137. package/dist/themes/pink-emerald.d.ts +6 -0
  138. package/dist/themes/pink-emerald.js +151 -0
  139. package/dist/themes/purple-yellow.css +163 -0
  140. package/dist/themes/purple-yellow.d.ts +6 -0
  141. package/dist/themes/purple-yellow.js +151 -0
  142. package/dist/themes/rainbow.css +163 -0
  143. package/dist/themes/rainbow.d.ts +6 -0
  144. package/dist/themes/rainbow.js +156 -0
  145. package/dist/themes/red-blue.css +163 -0
  146. package/dist/themes/red-blue.d.ts +6 -0
  147. package/dist/themes/red-blue.js +151 -0
  148. package/dist/themes/red-cyan.css +163 -0
  149. package/dist/themes/red-cyan.d.ts +6 -0
  150. package/dist/themes/red-cyan.js +151 -0
  151. package/dist/themes/rose-teal.css +163 -0
  152. package/dist/themes/rose-teal.d.ts +6 -0
  153. package/dist/themes/rose-teal.js +151 -0
  154. package/dist/themes/sky-amber.css +163 -0
  155. package/dist/themes/sky-amber.d.ts +6 -0
  156. package/dist/themes/sky-amber.js +151 -0
  157. package/dist/themes/slate-cyan.css +163 -0
  158. package/dist/themes/slate-cyan.d.ts +6 -0
  159. package/dist/themes/slate-cyan.js +151 -0
  160. package/dist/themes/tailwind-color-pairs.md +31 -0
  161. package/dist/themes/teal-rose.css +163 -0
  162. package/dist/themes/teal-rose.d.ts +6 -0
  163. package/dist/themes/teal-rose.js +151 -0
  164. package/dist/themes/violet-lime.css +163 -0
  165. package/dist/themes/violet-lime.d.ts +6 -0
  166. package/dist/themes/violet-lime.js +151 -0
  167. package/dist/utils/design-tokens.d.ts +43 -0
  168. package/dist/utils/design-tokens.js +100 -0
  169. package/dist/utils/index.d.ts +1 -0
  170. package/dist/utils/index.js +1 -0
  171. package/package.json +22 -2
@@ -63,30 +63,23 @@
63
63
  let validation = $state<ValidationResult | undefined>();
64
64
  let invalid = $derived(validation && !validation?.valid);
65
65
 
66
- //
67
- let _classCommon = $derived(
68
- [invalid && "invalid", disabled && "disabled", required && "required", renderSize]
69
- .filter(Boolean)
70
- .join(" ")
71
- );
72
66
  // $inspect(value);
73
67
  </script>
74
68
 
75
69
  {#if _options.length}
76
- <div class={twMerge("stuic-radios", _classCommon)} {style}>
70
+ <div
71
+ class={twMerge("stuic-radios", invalid && "invalid", disabled && "disabled")}
72
+ data-size={renderSize}
73
+ {style}
74
+ >
77
75
  <div
78
76
  class={twMerge(
79
77
  "radios-box",
80
- _classCommon,
81
- "gap-y-2 grid rounded-md p-2 mb-8",
82
- "border border-neutral-300 dark:border-neutral-600",
83
- "bg-neutral-100 dark:bg-neutral-700",
84
- invalid && "border-input-accent-invalid dark:border-input-accent-invalid-dark",
78
+ "gap-y-2 grid p-2 mb-8",
85
79
  classProp
86
80
  )}
87
81
  >
88
82
  {#each _options as o, i}
89
- <!-- value={o.value || o.label} -->
90
83
  <FieldRadioInternal
91
84
  {name}
92
85
  bind:group={value}
@@ -114,9 +107,7 @@
114
107
  transition:slide={{ duration: 150 }}
115
108
  class={twMerge(
116
109
  "validation-box",
117
- _classCommon,
118
- `mt-1 px-2 text-sm text-input-accent dark:text-input-accent-dark
119
- tracking-tight`,
110
+ "mt-1 px-2 text-sm tracking-tight",
120
111
  classValidationBox
121
112
  )}
122
113
  >
@@ -137,7 +137,7 @@
137
137
  bind:value
138
138
  bind:this={input}
139
139
  {id}
140
- class={twMerge("form-input", renderSize, classInput)}
140
+ class={twMerge(classInput)}
141
141
  use:validateAction={() => ({
142
142
  enabled: !!validate,
143
143
  ...(typeof validate === "boolean" ? {} : validate),
@@ -111,14 +111,10 @@
111
111
  {classLabel}
112
112
  {classLabelBox}
113
113
  {classInputBox}
114
- classInputBoxWrap={twMerge(
115
- "border-0 focus-within:border-0 focus-within:dark:border-0 focus-within:ring-0",
116
- "bg-transparent dark:bg-transparent",
117
- classInputBoxWrap
118
- )}
119
114
  {classDescBox}
120
115
  {classBelowBox}
121
116
  {validation}
117
+ classInputBoxWrap={twMerge("input-wrap-transparent", classInputBoxWrap)}
122
118
  {style}
123
119
  >
124
120
  <Switch bind:checked {name} {required} {disabled} {validate} {setValidationResult} />
@@ -125,7 +125,7 @@
125
125
  bind:value
126
126
  bind:this={input}
127
127
  {id}
128
- class={twMerge("form-input min-h-16", renderSize, classInput)}
128
+ class={twMerge("min-h-16", classInput)}
129
129
  use:trim={() => ({
130
130
  enabled: useTrim,
131
131
  setValue: (v: string) => (value = v),
@@ -232,3 +232,197 @@ Validation is handled by the `validate` action. Pass `validate={true}` for defau
232
232
  }}
233
233
  />
234
234
  ```
235
+
236
+ ## CSS Variables
237
+
238
+ ### Component Tokens
239
+
240
+ Override globally in `:root` or locally via `style` prop:
241
+
242
+ | Variable | Default | Description |
243
+ |----------|---------|-------------|
244
+ | `--stuic-input-radius` | `--radius-md` | Border radius |
245
+ | `--stuic-input-font-family` | `--font-sans` | Font family |
246
+ | `--stuic-input-transition` | `150ms` | Transition duration |
247
+ | `--stuic-input-ring-width` | `4px` | Focus ring width |
248
+ | `--stuic-input-ring-color` | `--stuic-color-ring` | Focus ring color |
249
+ | `--stuic-input-accent` | `--stuic-color-primary` | Accent color |
250
+ | `--stuic-input-accent-error` | `--stuic-color-destructive` | Error/validation color |
251
+
252
+ ### Color Tokens
253
+
254
+ | Variable | Default | Description |
255
+ |----------|---------|-------------|
256
+ | `--stuic-input-bg` | `--stuic-color-input` | Background color |
257
+ | `--stuic-input-border` | `--stuic-color-border` | Border color |
258
+ | `--stuic-input-border-focus` | `--stuic-input-accent` | Border color on focus |
259
+ | `--stuic-input-text` | `--stuic-color-foreground` | Text color |
260
+ | `--stuic-input-placeholder` | `--stuic-color-muted-foreground` | Placeholder color |
261
+
262
+ ### Size Tokens
263
+
264
+ Each size (sm, md, lg) has corresponding tokens:
265
+
266
+ | Variable | sm | md | lg |
267
+ |----------|----|----|-----|
268
+ | `--stuic-input-padding-x-{size}` | `calc(--spacing * 2.5)` | `calc(--spacing * 3)` | `calc(--spacing * 4)` |
269
+ | `--stuic-input-padding-y-{size}` | `calc(--spacing * 2)` | `calc(--spacing * 2.5)` | `calc(--spacing * 3)` |
270
+ | `--stuic-input-font-size-{size}` | `--text-sm` | `--text-base` | `--text-lg` |
271
+ | `--stuic-input-min-height-{size}` | `2.5rem` | `2.75rem` | `3rem` |
272
+
273
+ ### Checkbox/Radio Tokens
274
+
275
+ | Variable | Default | Description |
276
+ |----------|---------|-------------|
277
+ | `--stuic-checkbox-size` | `1.25rem` | Checkbox size |
278
+ | `--stuic-checkbox-radius` | `--radius-sm` | Checkbox border radius |
279
+ | `--stuic-radio-size` | `1rem` | Radio button size |
280
+ | `--stuic-checkbox-bg` | `--stuic-color-muted` | Unchecked background |
281
+ | `--stuic-checkbox-border` | `--stuic-color-border` | Unchecked border |
282
+ | `--stuic-checkbox-checked-bg` | `--stuic-input-accent` | Checked background |
283
+ | `--stuic-checkbox-checked-border` | `--stuic-input-accent` | Checked border |
284
+
285
+ ### Range Input Tokens
286
+
287
+ | Variable | Default | Description |
288
+ |----------|---------|-------------|
289
+ | `--stuic-input-range-thumb-size` | `18px` | Slider thumb size |
290
+ | `--stuic-input-range-track-height` | `4px` | Track height |
291
+ | `--stuic-input-range-track-radius` | `18px` | Track border radius |
292
+ | `--stuic-input-range-track-bg` | `--stuic-color-muted` | Track background |
293
+
294
+ ### Customization Examples
295
+
296
+ ```css
297
+ /* Global: Make all inputs have pill shape */
298
+ :root {
299
+ --stuic-input-radius: 9999px;
300
+ }
301
+
302
+ /* Global: Custom accent color */
303
+ :root {
304
+ --stuic-input-accent: var(--color-violet-600);
305
+ }
306
+ ```
307
+
308
+ ```svelte
309
+ <!-- Local: Custom radius for one input -->
310
+ <FieldInput
311
+ label="Search"
312
+ style="--stuic-input-radius: 9999px;"
313
+ />
314
+ ```
315
+
316
+ ## Data Attributes
317
+
318
+ Components use data attributes for CSS styling:
319
+
320
+ - `data-size` - The size value ("sm", "md", "lg")
321
+
322
+ ## Class Props
323
+
324
+ | Prop | Target |
325
+ |------|--------|
326
+ | `class` | Root container |
327
+ | `classInput` | Input element |
328
+ | `classLabel` | Label element |
329
+ | `classLabelBox` | Label container |
330
+ | `classInputBox` | Input container (outer) |
331
+ | `classInputBoxWrap` | Input wrapper (inner, has border) |
332
+ | `classInputBoxWrapInvalid` | Input wrapper when invalid |
333
+ | `classDescBox` | Description container |
334
+ | `classBelowBox` | Below slot container |
335
+
336
+ ---
337
+
338
+ ## FieldOptions
339
+
340
+ A modal-based multi-select/single-select component with search functionality, typeahead support, and option grouping.
341
+
342
+ ### Props
343
+
344
+ | Prop | Type | Default | Description |
345
+ |------|------|---------|-------------|
346
+ | `value` | `string` | `"[]"` | JSON array of selected items (bindable) |
347
+ | `name` | `string` | - | Form field name |
348
+ | `getOptions` | `(q: string, current: Item[]) => Promise<{found: Item[]}>` | - | Async function to fetch options |
349
+ | `cardinality` | `number` | `Infinity` | Max selections (-1 for unlimited) |
350
+ | `allowUnknown` | `boolean` | `false` | Allow typing custom values |
351
+ | `renderOptionLabel` | `(item: Item) => string` | - | Custom option label renderer |
352
+ | `renderOptionGroup` | `(s: string) => string` | - | Custom optgroup label renderer |
353
+ | `renderValue` | `(stringifiedItems: string) => string` | - | Custom value display renderer |
354
+ | `showIconsCheckbox` | `boolean` | `true` | Show checkbox icons in multi-select |
355
+ | `showIconsRadio` | `boolean` | `false` | Show radio icons in single-select |
356
+ | `searchPlaceholder` | `string` | - | Custom search placeholder |
357
+ | `itemIdPropName` | `string` | `"id"` | Property name for item ID |
358
+ | `notifications` | `NotificationsStack` | - | Notification handler for errors |
359
+
360
+ ### Class Props
361
+
362
+ | Prop | Target |
363
+ |------|--------|
364
+ | `classOption` | Option item (ListItemButton) |
365
+ | `classOptionActive` | Active/selected option |
366
+ | `classOptgroup` | Option group label |
367
+ | `classModalField` | Modal field wrapper |
368
+
369
+ ### CSS Variables
370
+
371
+ #### Component Tokens
372
+
373
+ | Variable | Default | Description |
374
+ |----------|---------|-------------|
375
+ | `--stuic-field-options-divider` | `--stuic-color-border` | Divider/separator color |
376
+ | `--stuic-field-options-control-text` | `--stuic-color-muted-foreground` | Control button text color |
377
+ | `--stuic-field-options-control-text-hover` | `--stuic-color-foreground` | Control button hover text color |
378
+ | `--stuic-field-options-control-ring` | `--stuic-color-ring` | Control button focus ring |
379
+ | `--stuic-field-options-muted-text` | `--stuic-color-muted-foreground` | Muted/secondary text color |
380
+ | `--stuic-field-options-optgroup-text` | `--stuic-color-muted-foreground` | Option group label color |
381
+
382
+ ### Usage
383
+
384
+ ```svelte
385
+ <script lang="ts">
386
+ import { FieldOptions } from 'stuic';
387
+
388
+ let value = $state('[]');
389
+
390
+ async function getOptions(query: string, current: any[]) {
391
+ const response = await fetch(`/api/search?q=${query}`);
392
+ const data = await response.json();
393
+ return { found: data.items };
394
+ }
395
+ </script>
396
+
397
+ <FieldOptions
398
+ label="Select Tags"
399
+ name="tags"
400
+ bind:value
401
+ {getOptions}
402
+ cardinality={5}
403
+ allowUnknown
404
+ />
405
+ ```
406
+
407
+ ### Customization Examples
408
+
409
+ ```css
410
+ /* Make optgroup labels more prominent */
411
+ :root {
412
+ --stuic-field-options-optgroup-text: var(--stuic-color-primary);
413
+ }
414
+
415
+ /* Custom control button colors */
416
+ :root {
417
+ --stuic-field-options-control-text: var(--stuic-color-primary);
418
+ --stuic-field-options-control-text-hover: var(--stuic-color-primary-hover);
419
+ }
420
+ ```
421
+
422
+ ```svelte
423
+ <!-- Local customization -->
424
+ <FieldOptions
425
+ style="--stuic-field-options-divider: var(--color-red-500);"
426
+ ...
427
+ />
428
+ ```
@@ -69,21 +69,7 @@
69
69
  let id = getId();
70
70
  let idDesc = getId();
71
71
 
72
- //
73
- let _classCommon = $derived(
74
- [invalid && "invalid", disabled && "disabled", renderSize].filter(Boolean).join(" ")
75
- );
76
72
 
77
- const _preset = {
78
- labelBox: {
79
- label: {
80
- size: {
81
- sm: "text-sm mt-0.5",
82
- lg: "font-semibold",
83
- } as any,
84
- },
85
- },
86
- };
87
73
  </script>
88
74
 
89
75
  {#snippet snippetOrThc({ id, value }: { id: string; value?: SnippetWithId | THC })}
@@ -97,7 +83,6 @@
97
83
  <label
98
84
  class={twMerge(
99
85
  "radio-box",
100
- _classCommon,
101
86
  "flex items-start cursor-pointer pr-1",
102
87
  disabled && "cursor-not-allowed",
103
88
  classRadioBox
@@ -106,7 +91,6 @@
106
91
  <div
107
92
  class={twMerge(
108
93
  "input-box",
109
- _classCommon,
110
94
  "flex h-6 items-center ml-1",
111
95
  classInputBox
112
96
  )}
@@ -118,26 +102,7 @@
118
102
  bind:group
119
103
  {value}
120
104
  {name}
121
- class={twMerge(
122
- _classCommon,
123
- `size-4 rounded-full
124
- bg-neutral-100
125
- border-neutral-300
126
- text-input-accent dark:text-input-accent-dark
127
- cursor-pointer
128
-
129
- checked:border-input-accent checked:bg-input-accent
130
- checked:dark:border-input-accent-dark checked:dark:bg-input-accent-dark
131
-
132
- focus:border-input-accent
133
- focus:ring-4
134
- focus:ring-offset-0
135
- focus:ring-input-accent/20 focus:dark:ring-input-accent-dark/20
136
-
137
- disabled:cursor-not-allowed`,
138
- disabled && "cursor-not-allowed",
139
- classInput
140
- )}
105
+ class={twMerge(classInput)}
141
106
  aria-describedby={description ? idDesc : undefined}
142
107
  use:validateAction={() => ({
143
108
  enabled: !!validate,
@@ -149,14 +114,12 @@
149
114
  {...rest}
150
115
  />
151
116
  </div>
152
- <div class={twMerge("label-box", _classCommon, "ml-3 w-full", classLabelBox)}>
117
+ <div class={twMerge("label-box", "ml-3 w-full", classLabelBox)}>
153
118
  {#if label}
154
119
  <div
155
120
  class={twMerge(
156
121
  "label",
157
- _classCommon,
158
122
  "block w-full cursor-pointer",
159
- renderSize && _preset.labelBox.label.size[renderSize],
160
123
  required && "after:content-['*'] after:opacity-40 after:pl-1",
161
124
  classLabel
162
125
  )}
@@ -173,7 +136,6 @@
173
136
  id={idDesc}
174
137
  class={twMerge(
175
138
  "desc-box",
176
- _classCommon,
177
139
  "text-sm opacity-50 cursor-pointer font-normal",
178
140
  disabled && "cursor-not-allowed",
179
141
  classDescBox
@@ -87,28 +87,8 @@
87
87
  }
88
88
  });
89
89
 
90
- let _classCommon = $derived(
91
- [invalid && "invalid", disabled && "disabled", required && "required", size]
92
- .filter(Boolean)
93
- .join(" ")
94
- );
95
-
96
90
  let hasLabel = $derived(isTHCNotEmpty(label) || typeof label === "function");
97
91
 
98
- const _preset = {
99
- label: {
100
- size: {
101
- sm: "text-sm",
102
- lg: "font-semibold",
103
- } as any,
104
- },
105
- inputBox: {
106
- size: {
107
- sm: "text-sm",
108
- lg: "p-1",
109
- } as any,
110
- },
111
- };
112
92
  </script>
113
93
 
114
94
  {#snippet snippetOrThc({ id, value }: { id: string; value?: SnippetWithId | THC })}
@@ -122,20 +102,21 @@
122
102
  <div
123
103
  class={twMerge(
124
104
  "stuic-input",
125
- _classCommon,
126
105
  "mb-8",
106
+ invalid && "invalid",
107
+ disabled && "disabled",
127
108
  hasLabel && labelLeft && "flex",
128
109
  hasLabel && labelLeft && labelLeftWidth === "normal" && "width-normal",
129
110
  hasLabel && labelLeft && labelLeftWidth === "wide" && "width-wide",
130
111
  classProp
131
112
  )}
113
+ data-size={size}
132
114
  bind:clientWidth={width}
133
115
  {style}
134
116
  >
135
117
  <div
136
118
  class={twMerge(
137
119
  "label-box",
138
- _classCommon,
139
120
  "flex flex-1",
140
121
  labelLeft ? "left items-start mt-2" : "items-end",
141
122
  classLabelBox
@@ -145,11 +126,8 @@
145
126
  <label
146
127
  for={id}
147
128
  class={twMerge(
148
- "block",
149
- _classCommon,
150
- "flex-1 px-2 mb-1 text-base",
129
+ "block flex-1 px-2 mb-1 text-base",
151
130
  required && "after:content-['*'] after:opacity-40 after:pl-1",
152
- _preset.label.size[size],
153
131
  classLabel
154
132
  )}
155
133
  >
@@ -163,7 +141,6 @@
163
141
  <div
164
142
  class={twMerge(
165
143
  "input-box",
166
- _classCommon,
167
144
  hasLabel && labelLeft && labelLeftWidth === "normal" && "flex-3",
168
145
  hasLabel && labelLeft && labelLeftWidth === "wide" && "flex-2",
169
146
  classInputBox
@@ -172,23 +149,8 @@
172
149
  <div
173
150
  class={twMerge(
174
151
  "input-wrap",
175
- _classCommon,
176
- `rounded-md border border-neutral-300 dark:border-neutral-600
177
- bg-neutral-100 dark:bg-neutral-700
178
- focus-within:border-input-accent focus-within:dark:border-input-accent-dark
179
- focus-within:ring-input-accent/20 focus-within:dark:ring-input-accent-dark/20
180
- focus-within:ring-4`,
181
- disabled && "cursor-not-allowed opacity-50",
182
- _preset.inputBox.size[size],
183
- invalid
184
- ? twMerge(
185
- classInputBoxWrap,
186
- `border-input-accent-invalid dark:border-input-accent-invalid-dark
187
- focus-within:border-input-accent-invalid focus-within:dark:border-input-accent-invalid-dark
188
- focus-within:ring-input-accent-invalid/20 focus-within:dark:ring-input-accent-invalid-dark/20`,
189
- classInputBoxWrapInvalid
190
- )
191
- : classInputBoxWrap
152
+ classInputBoxWrap,
153
+ invalid && classInputBoxWrapInvalid
192
154
  )}
193
155
  >
194
156
  <div class="flex">
@@ -204,8 +166,7 @@
204
166
  transition:slide={{ duration: 150 }}
205
167
  class={twMerge(
206
168
  "validation-box",
207
- _classCommon,
208
- "my-1 text-sm px-2 text-input-accent-invalid dark:text-input-accent-invalid-dark",
169
+ "my-1 text-sm px-2",
209
170
  classValidationBox
210
171
  )}
211
172
  >
@@ -217,7 +178,6 @@
217
178
  <div
218
179
  class={twMerge(
219
180
  "desc-box",
220
- _classCommon,
221
181
  "mx-2 mt-1 text-sm opacity-50",
222
182
  classDescBox
223
183
  )}
@@ -236,7 +196,7 @@
236
196
  {/if}
237
197
 
238
198
  {#if below}
239
- <div class={twMerge("below-box", _classCommon, "mx-2 my-1", classBelowBox)}>
199
+ <div class={twMerge("below-box", "mx-2 my-1", classBelowBox)}>
240
200
  {@render snippetOrThc({ id, value: below })}
241
201
  </div>
242
202
  {/if}