@marianmeres/stuic 2.66.0 → 3.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 (208) hide show
  1. package/README.md +292 -4
  2. package/dist/README.md +41 -18
  3. package/dist/actions/index.d.ts +1 -0
  4. package/dist/actions/index.js +1 -0
  5. package/dist/actions/popover/README.md +19 -0
  6. package/dist/actions/popover/index.css +6 -9
  7. package/dist/actions/popover/popover.svelte.js +2 -2
  8. package/dist/actions/tooltip/README.md +18 -0
  9. package/dist/actions/tooltip/index.css +5 -8
  10. package/dist/actions/tooltip/tooltip.svelte.js +1 -1
  11. package/dist/actions/typeahead.svelte.d.ts +53 -0
  12. package/dist/actions/typeahead.svelte.js +328 -0
  13. package/dist/base.css +17 -0
  14. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +10 -10
  15. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +4 -3
  16. package/dist/components/AlertConfirmPrompt/Current.svelte +15 -18
  17. package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +4 -3
  18. package/dist/components/AlertConfirmPrompt/acp-icons.js +5 -4
  19. package/dist/components/AlertConfirmPrompt/index.css +66 -0
  20. package/dist/components/AssetsPreview/AssetsPreview.svelte +91 -73
  21. package/dist/components/AssetsPreview/index.css +61 -0
  22. package/dist/components/Avatar/Avatar.svelte +31 -18
  23. package/dist/components/Avatar/README.md +166 -0
  24. package/dist/components/Avatar/index.css +130 -0
  25. package/dist/components/Backdrop/Backdrop.svelte +7 -2
  26. package/dist/components/Backdrop/README.md +71 -6
  27. package/dist/components/Backdrop/index.css +31 -0
  28. package/dist/components/Button/Button.svelte +116 -124
  29. package/dist/components/Button/Button.svelte.d.ts +35 -24
  30. package/dist/components/Button/README.md +87 -21
  31. package/dist/components/Button/index.css +475 -9
  32. package/dist/components/Button/index.d.ts +1 -1
  33. package/dist/components/Button/index.js +1 -1
  34. package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte +7 -39
  35. package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte.d.ts +0 -1
  36. package/dist/components/ButtonGroupRadio/README.md +82 -4
  37. package/dist/components/ButtonGroupRadio/index.css +158 -14
  38. package/dist/components/Collapsible/Collapsible.svelte +7 -7
  39. package/dist/components/Collapsible/Collapsible.svelte.d.ts +2 -2
  40. package/dist/components/Collapsible/README.md +34 -2
  41. package/dist/components/Collapsible/index.css +40 -0
  42. package/dist/components/CommandMenu/CommandMenu.svelte +18 -26
  43. package/dist/components/CommandMenu/CommandMenu.svelte.d.ts +0 -1
  44. package/dist/components/CommandMenu/README.md +39 -0
  45. package/dist/components/CommandMenu/index.css +47 -2
  46. package/dist/components/DismissibleMessage/DismissibleMessage.svelte +53 -51
  47. package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +6 -6
  48. package/dist/components/DismissibleMessage/README.md +93 -11
  49. package/dist/components/DismissibleMessage/index.css +128 -8
  50. package/dist/components/DismissibleMessage/index.d.ts +1 -1
  51. package/dist/components/DropdownMenu/DropdownMenu.svelte +14 -51
  52. package/dist/components/DropdownMenu/DropdownMenu.svelte.d.ts +6 -7
  53. package/dist/components/DropdownMenu/README.md +132 -0
  54. package/dist/components/DropdownMenu/index.css +258 -52
  55. package/dist/components/Input/FieldAssets.svelte +8 -5
  56. package/dist/components/Input/FieldCheckbox.svelte +7 -44
  57. package/dist/components/Input/FieldFile.svelte +1 -6
  58. package/dist/components/Input/FieldInput.svelte +9 -1
  59. package/dist/components/Input/FieldInput.svelte.d.ts +2 -0
  60. package/dist/components/Input/FieldOptions.svelte +42 -39
  61. package/dist/components/Input/FieldRadios.svelte +7 -16
  62. package/dist/components/Input/FieldSelect.svelte +1 -1
  63. package/dist/components/Input/FieldSwitch.svelte +1 -5
  64. package/dist/components/Input/FieldTextarea.svelte +1 -1
  65. package/dist/components/Input/README.md +194 -0
  66. package/dist/components/Input/_internal/FieldRadioInternal.svelte +2 -40
  67. package/dist/components/Input/_internal/InputWrap.svelte +8 -48
  68. package/dist/components/Input/index.css +524 -116
  69. package/dist/components/KbdShortcut/KbdShortcut.svelte +4 -12
  70. package/dist/components/KbdShortcut/README.md +34 -0
  71. package/dist/components/KbdShortcut/index.css +55 -0
  72. package/dist/components/ListItemButton/ListItemButton.svelte +37 -74
  73. package/dist/components/ListItemButton/ListItemButton.svelte.d.ts +1 -10
  74. package/dist/components/ListItemButton/README.md +100 -45
  75. package/dist/components/ListItemButton/index.css +173 -52
  76. package/dist/components/ListItemButton/index.d.ts +1 -1
  77. package/dist/components/ListItemButton/index.js +1 -1
  78. package/dist/components/Modal/Modal.svelte +1 -8
  79. package/dist/components/Modal/README.md +29 -0
  80. package/dist/components/Modal/index.css +38 -0
  81. package/dist/components/ModalDialog/ModalDialog.svelte +2 -21
  82. package/dist/components/ModalDialog/README.md +35 -0
  83. package/dist/components/ModalDialog/index.css +59 -0
  84. package/dist/components/Nav/Nav.svelte +732 -0
  85. package/dist/components/Nav/Nav.svelte.d.ts +110 -0
  86. package/dist/components/Nav/README.md +334 -0
  87. package/dist/components/Nav/index.css +318 -0
  88. package/dist/components/Nav/index.d.ts +1 -0
  89. package/dist/components/Nav/index.js +1 -0
  90. package/dist/components/Notifications/Notifications.svelte +44 -129
  91. package/dist/components/Notifications/Notifications.svelte.d.ts +9 -18
  92. package/dist/components/Notifications/README.md +186 -70
  93. package/dist/components/Notifications/index.css +212 -15
  94. package/dist/components/Notifications/notifications-stack.svelte.d.ts +4 -0
  95. package/dist/components/Notifications/notifications-stack.svelte.js +8 -0
  96. package/dist/components/Progress/Progress.svelte +4 -2
  97. package/dist/components/Progress/Progress.svelte.d.ts +1 -0
  98. package/dist/components/Progress/README.md +97 -11
  99. package/dist/components/Progress/_internal/Bar.svelte +4 -15
  100. package/dist/components/Progress/_internal/Bar.svelte.d.ts +1 -1
  101. package/dist/components/Progress/_internal/Circle.svelte +30 -2
  102. package/dist/components/Progress/_internal/Circle.svelte.d.ts +1 -0
  103. package/dist/components/Progress/index.css +50 -4
  104. package/dist/components/Skeleton/README.md +152 -0
  105. package/dist/components/Skeleton/Skeleton.svelte +9 -9
  106. package/dist/components/Skeleton/Skeleton.svelte.d.ts +0 -1
  107. package/dist/components/Skeleton/index.css +72 -45
  108. package/dist/components/Spinner/README.md +149 -37
  109. package/dist/components/Spinner/Spinner.svelte +14 -38
  110. package/dist/components/Spinner/Spinner.svelte.d.ts +2 -1
  111. package/dist/components/Spinner/SpinnerCircle.svelte +6 -34
  112. package/dist/components/Spinner/SpinnerCircle.svelte.d.ts +1 -0
  113. package/dist/components/Spinner/SpinnerCircleOscillate.svelte +10 -5
  114. package/dist/components/Spinner/SpinnerUnicode.svelte +3 -1
  115. package/dist/components/Spinner/SpinnerUnicode.svelte.d.ts +1 -0
  116. package/dist/components/Spinner/index.css +104 -0
  117. package/dist/components/Switch/README.md +45 -14
  118. package/dist/components/Switch/Switch.svelte +23 -48
  119. package/dist/components/Switch/Switch.svelte.d.ts +4 -2
  120. package/dist/components/Switch/index.css +121 -4
  121. package/dist/components/Switch/index.d.ts +1 -2
  122. package/dist/components/Switch/index.js +1 -2
  123. package/dist/components/TabbedMenu/README.md +37 -21
  124. package/dist/components/TabbedMenu/TabbedMenu.svelte +5 -46
  125. package/dist/components/TabbedMenu/TabbedMenu.svelte.d.ts +0 -1
  126. package/dist/components/TabbedMenu/index.css +84 -17
  127. package/dist/components/ThemePreview/README.md +289 -0
  128. package/dist/components/ThemePreview/ThemePreview.svelte +394 -0
  129. package/dist/components/ThemePreview/ThemePreview.svelte.d.ts +35 -0
  130. package/dist/components/ThemePreview/index.css +509 -0
  131. package/dist/components/ThemePreview/index.d.ts +1 -0
  132. package/dist/components/ThemePreview/index.js +1 -0
  133. package/dist/components/TwCheck/README.md +32 -13
  134. package/dist/components/TwCheck/TwCheck.svelte +11 -9
  135. package/dist/components/TwCheck/TwCheck.svelte.d.ts +0 -1
  136. package/dist/components/TwCheck/index.css +17 -2
  137. package/dist/components/TypeaheadInput/TypeaheadInput.svelte +20 -188
  138. package/dist/components/TypeaheadInput/TypeaheadInput.svelte.d.ts +4 -2
  139. package/dist/components/X/X.svelte +12 -5
  140. package/dist/components/X/X.svelte.d.ts +1 -0
  141. package/dist/icons/index.d.ts +1 -0
  142. package/dist/icons/index.js +1 -0
  143. package/dist/index.css +46 -26
  144. package/dist/index.d.ts +2 -0
  145. package/dist/index.js +2 -0
  146. package/dist/themes/blue-orange.css +217 -0
  147. package/dist/themes/blue-orange.d.ts +6 -0
  148. package/dist/themes/blue-orange.js +175 -0
  149. package/dist/themes/cyan-red.css +217 -0
  150. package/dist/themes/cyan-red.d.ts +6 -0
  151. package/dist/themes/cyan-red.js +175 -0
  152. package/dist/themes/cyan-slate.css +217 -0
  153. package/dist/themes/cyan-slate.d.ts +6 -0
  154. package/dist/themes/cyan-slate.js +175 -0
  155. package/dist/themes/emerald-pink.css +217 -0
  156. package/dist/themes/emerald-pink.d.ts +6 -0
  157. package/dist/themes/emerald-pink.js +175 -0
  158. package/dist/themes/fuchsia-emerald.css +217 -0
  159. package/dist/themes/fuchsia-emerald.d.ts +6 -0
  160. package/dist/themes/fuchsia-emerald.js +175 -0
  161. package/dist/themes/gray.css +217 -0
  162. package/dist/themes/gray.d.ts +6 -0
  163. package/dist/themes/gray.js +175 -0
  164. package/dist/themes/indigo-amber.css +217 -0
  165. package/dist/themes/indigo-amber.d.ts +6 -0
  166. package/dist/themes/indigo-amber.js +175 -0
  167. package/dist/themes/neutral.css +217 -0
  168. package/dist/themes/neutral.d.ts +6 -0
  169. package/dist/themes/neutral.js +175 -0
  170. package/dist/themes/pink-emerald.css +217 -0
  171. package/dist/themes/pink-emerald.d.ts +6 -0
  172. package/dist/themes/pink-emerald.js +175 -0
  173. package/dist/themes/purple-yellow.css +217 -0
  174. package/dist/themes/purple-yellow.d.ts +6 -0
  175. package/dist/themes/purple-yellow.js +175 -0
  176. package/dist/themes/rainbow.css +217 -0
  177. package/dist/themes/rainbow.d.ts +6 -0
  178. package/dist/themes/rainbow.js +180 -0
  179. package/dist/themes/red-blue.css +217 -0
  180. package/dist/themes/red-blue.d.ts +6 -0
  181. package/dist/themes/red-blue.js +175 -0
  182. package/dist/themes/red-cyan.css +217 -0
  183. package/dist/themes/red-cyan.d.ts +6 -0
  184. package/dist/themes/red-cyan.js +175 -0
  185. package/dist/themes/rose-teal.css +217 -0
  186. package/dist/themes/rose-teal.d.ts +6 -0
  187. package/dist/themes/rose-teal.js +175 -0
  188. package/dist/themes/sky-amber.css +217 -0
  189. package/dist/themes/sky-amber.d.ts +6 -0
  190. package/dist/themes/sky-amber.js +175 -0
  191. package/dist/themes/slate-cyan.css +217 -0
  192. package/dist/themes/slate-cyan.d.ts +6 -0
  193. package/dist/themes/slate-cyan.js +175 -0
  194. package/dist/themes/tailwind-color-pairs.md +31 -0
  195. package/dist/themes/teal-rose.css +217 -0
  196. package/dist/themes/teal-rose.d.ts +6 -0
  197. package/dist/themes/teal-rose.js +175 -0
  198. package/dist/themes/violet-lime.css +217 -0
  199. package/dist/themes/violet-lime.d.ts +6 -0
  200. package/dist/themes/violet-lime.js +175 -0
  201. package/dist/utils/design-tokens.d.ts +43 -0
  202. package/dist/utils/design-tokens.js +127 -0
  203. package/dist/utils/index.d.ts +1 -0
  204. package/dist/utils/index.js +1 -0
  205. package/dist/utils/storage-abstraction.js +1 -1
  206. package/package.json +14 -11
  207. package/dist/components/Switch/SwitchButton.svelte +0 -135
  208. package/dist/components/Switch/SwitchButton.svelte.d.ts +0 -21
@@ -93,6 +93,45 @@ The command menu uses `ModalDialog` internally with top-aligned positioning:
93
93
  - **Mobile**: Input at top of screen with 1rem margins from edges
94
94
  - **Desktop (md+)**: Input positioned at ~20% from top, max-width 768px, centered horizontally
95
95
 
96
+ ## CSS Variables
97
+
98
+ All styling can be customized via CSS variables. Define them on a parent element or in `:root` to override defaults.
99
+
100
+ ### Structure Tokens
101
+
102
+ | Variable | Default | Description |
103
+ |----------|---------|-------------|
104
+ | `--stuic-command-menu-transition` | `150ms` | Transition duration for hover/focus states |
105
+ | `--stuic-command-menu-options-max-height` | `15rem` | Maximum height of options container |
106
+
107
+ ### Color Tokens
108
+
109
+ | Variable | Default | Description |
110
+ |----------|---------|-------------|
111
+ | `--stuic-command-menu-divider-color` | `var(--stuic-color-border)` | Border color between input and options |
112
+ | `--stuic-command-menu-group-header-color` | `var(--stuic-color-muted-foreground)` | Option group header text color |
113
+ | `--stuic-command-menu-group-header-font-size` | `var(--text-xs)` | Option group header font size |
114
+
115
+ ### Custom Theme Example
116
+
117
+ ```svelte
118
+ <div style="
119
+ --stuic-command-menu-divider-color: var(--color-blue-200);
120
+ ">
121
+ <CommandMenu ... />
122
+ </div>
123
+ ```
124
+
125
+ ### Global Theme Override
126
+
127
+ ```css
128
+ /* In your app.css */
129
+ :root {
130
+ --stuic-command-menu-options-max-height: 20rem;
131
+ --stuic-command-menu-group-header-color: var(--color-indigo-500);
132
+ }
133
+ ```
134
+
96
135
  ## Keyboard Navigation
97
136
 
98
137
  - **Arrow Up/Down**: Navigate options
@@ -1,3 +1,48 @@
1
- /* Override ListItemButton defaults for CommandMenu context */
2
- .stuic-command-menu-options .stuic-list-item-button {
1
+ /* =============================================================================
2
+ COMMAND MENU COMPONENT TOKENS
3
+ Override globally: :root { --stuic-command-menu-divider-color: red; }
4
+ Override locally: <div style="--stuic-command-menu-divider-color: blue;">
5
+ ============================================================================= */
6
+
7
+ :root {
8
+ /* Structure */
9
+ --stuic-command-menu-transition: 150ms;
10
+ --stuic-command-menu-options-max-height: 15rem;
11
+
12
+ /* Colors */
13
+ --stuic-command-menu-divider-color: var(--stuic-color-border);
14
+ --stuic-command-menu-group-header-color: var(--stuic-color-muted-foreground);
15
+ --stuic-command-menu-group-header-font-size: var(--text-xs);
16
+
17
+ /* Muted/placeholder states (align with FieldOptions) */
18
+ --stuic-command-menu-muted-text: var(--stuic-color-muted-foreground);
19
+ }
20
+
21
+ @layer components {
22
+ /* =============================================================================
23
+ BASE STYLES
24
+ ============================================================================= */
25
+
26
+ /* Options container */
27
+ .stuic-command-menu-options {
28
+ scrollbar-width: thin;
29
+ max-height: var(--stuic-command-menu-options-max-height);
30
+ border-top-color: var(--stuic-command-menu-divider-color);
31
+ }
32
+
33
+ /* Option group header */
34
+ .stuic-command-menu-group-header {
35
+ color: var(--stuic-command-menu-group-header-color);
36
+ font-size: var(--stuic-command-menu-group-header-font-size);
37
+ }
38
+
39
+ /* Muted elements (search icon) */
40
+ .stuic-command-menu-muted {
41
+ color: var(--stuic-command-menu-muted-text);
42
+ }
43
+
44
+ /* Placeholder/loading states (spinner) */
45
+ .stuic-command-menu-placeholder {
46
+ color: var(--stuic-command-menu-muted-text);
47
+ }
3
48
  }
@@ -1,92 +1,94 @@
1
1
  <script lang="ts" module>
2
- import type { TW_COLORS } from "../../types.js";
3
2
  import type { THC } from "../Thc/Thc.svelte";
4
3
 
4
+ export type MessageIntent = "destructive" | "warning" | "success" | "info";
5
+
5
6
  export interface Props {
6
7
  class?: string;
7
8
  classContent?: string;
8
- classDismiss?: string;
9
- classX?: string;
10
- message: THC | Error;
11
- theme?: TW_COLORS;
9
+ classIcon?: string;
10
+ message: THC | Error | undefined | null;
11
+ intent?: MessageIntent;
12
12
  forceAsHtml?: boolean;
13
13
  duration?: number;
14
14
  onDismiss?: (() => void) | null | false;
15
+ withIcon?: boolean;
16
+ iconFn?: (() => string) | false;
15
17
  }
16
18
  </script>
17
19
 
18
20
  <script lang="ts">
19
21
  import { slide } from "svelte/transition";
20
- import Thc, { isTHCNotEmpty } from "../Thc/Thc.svelte";
21
- import X from "../X/X.svelte";
22
22
  import { twMerge } from "../../utils/tw-merge.js";
23
+ import Thc, { isTHCNotEmpty } from "../Thc/Thc.svelte";
24
+ import Button from "../Button/Button.svelte";
25
+ import {
26
+ iconAlertWarning,
27
+ iconAlertSuccess,
28
+ iconAlertInfo,
29
+ iconAlertError,
30
+ } from "../../icons/index.js";
23
31
 
24
- import "./index.css";
32
+
33
+ const INTENT_ICONS: Record<MessageIntent, () => string> = {
34
+ destructive: () => iconAlertError({ size: 29 }),
35
+ warning: () => iconAlertWarning({ size: 29 }),
36
+ success: () => iconAlertSuccess({ size: 29 }),
37
+ info: () => iconAlertInfo({ size: 29 }),
38
+ };
25
39
 
26
40
  let {
27
41
  class: classProps,
28
42
  classContent,
29
- classDismiss,
30
- classX,
43
+ classIcon,
31
44
  message,
32
- theme,
45
+ intent,
33
46
  forceAsHtml = true,
34
47
  duration = 150,
35
48
  onDismiss = () => (message = ""),
49
+ withIcon,
50
+ iconFn,
36
51
  }: Props = $props();
37
52
 
38
- let _message = $derived(`${message}`);
53
+ let _message = $derived(message ? String(message) : "");
39
54
  let _show = $derived(isTHCNotEmpty(_message));
55
+
56
+ let _iconHtml = $derived.by(() => {
57
+ if (iconFn === false) return "";
58
+ if (typeof iconFn === "function") return iconFn();
59
+ if (withIcon && intent) return INTENT_ICONS[intent]?.();
60
+ return "";
61
+ });
40
62
  </script>
41
63
 
42
64
  {#if _show}
43
65
  <div
44
- class={twMerge(
45
- "stuic-dismissible-message",
46
- `mb-4 rounded flex text-sm
47
- bg-dismiss-bg dark:bg-dismiss-bg-dark
48
- border-dismiss-border dark:border-dismiss-border-dark
49
- text-dismiss-text dark:text-dismiss-text-dark`,
50
- classProps
51
- )}
52
- style={theme
53
- ? `
54
- --color-dismiss-bg: var(--color-${theme}-100);
55
- --color-dismiss-bg-dark: var(--color-${theme}-700);
56
-
57
- --color-dismiss-text: var(--color-${theme}-800);
58
- --color-dismiss-text-dark: var(--color-${theme}-50);
59
-
60
- --color-dismiss-border: var(--color-${theme}-500);
61
- --color-dismiss-border-dark: var(--color-${theme}-500);
62
- `
63
- : ``}
66
+ class={twMerge("stuic-dismissible-message", "mb-4", classProps)}
67
+ data-intent={intent}
64
68
  transition:slide={{ duration }}
65
69
  >
66
- <div class={twMerge("content", "flex-1 px-4 py-3", classContent)}>
70
+ {#if _iconHtml}
71
+ <div class={twMerge("icon", classIcon)}>
72
+ {@html _iconHtml}
73
+ </div>
74
+ {/if}
75
+
76
+ <div class={twMerge("content", classContent)}>
67
77
  <Thc thc={_message} {forceAsHtml} />
68
78
  </div>
69
79
 
70
80
  {#if typeof onDismiss === "function"}
71
- <button
72
- onclick={() => onDismiss()}
73
- class={twMerge(
74
- "dismiss",
75
- `hover:bg-neutral-950/5 dark:hover:bg-neutral-950/20
76
- focus-visible:bg-neutral-950/5 focus-visible:hover:bg-neutral-950/20 focus-visible:ring-0
77
- rounded rounded-l-none
78
- px-3
79
- flex items-center justify-center
80
- group`,
81
- classDismiss
82
- )}
83
- type="button"
84
- >
85
- <X
86
- class={twMerge("x", "opacity-75 group-hover:opacity-100", classX)}
87
- strokeWidth={1.5}
81
+ <div class="dismiss">
82
+ <Button
83
+ x
84
+ class="text-inherit!"
85
+ variant="ghost"
86
+ roundedFull
87
+ size="sm"
88
+ type="button"
89
+ onclick={() => onDismiss()}
88
90
  />
89
- </button>
91
+ </div>
90
92
  {/if}
91
93
  </div>
92
94
  {/if}
@@ -1,17 +1,17 @@
1
- import type { TW_COLORS } from "../../types.js";
2
1
  import type { THC } from "../Thc/Thc.svelte";
2
+ export type MessageIntent = "destructive" | "warning" | "success" | "info";
3
3
  export interface Props {
4
4
  class?: string;
5
5
  classContent?: string;
6
- classDismiss?: string;
7
- classX?: string;
8
- message: THC | Error;
9
- theme?: TW_COLORS;
6
+ classIcon?: string;
7
+ message: THC | Error | undefined | null;
8
+ intent?: MessageIntent;
10
9
  forceAsHtml?: boolean;
11
10
  duration?: number;
12
11
  onDismiss?: (() => void) | null | false;
12
+ withIcon?: boolean;
13
+ iconFn?: (() => string) | false;
13
14
  }
14
- import "./index.css";
15
15
  declare const DismissibleMessage: import("svelte").Component<Props, {}, "">;
16
16
  type DismissibleMessage = ReturnType<typeof DismissibleMessage>;
17
17
  export default DismissibleMessage;
@@ -1,20 +1,18 @@
1
1
  # DismissibleMessage
2
2
 
3
- A dismissible alert/message component with color themes and slide transition.
3
+ A dismissible alert/message component with semantic intents and slide transition.
4
4
 
5
5
  ## Props
6
6
 
7
7
  | Prop | Type | Default | Description |
8
8
  |------|------|---------|-------------|
9
9
  | `message` | `THC \| Error` | - | Message content (string, HTML, or Error object) |
10
- | `theme` | `TW_COLORS` | - | Tailwind color theme (e.g., `"red"`, `"green"`, `"blue"`) |
10
+ | `intent` | `"destructive" \| "warning" \| "success" \| "info"` | - | Semantic color intent |
11
11
  | `forceAsHtml` | `boolean` | `true` | Render message as HTML |
12
12
  | `duration` | `number` | `150` | Slide transition duration (ms) |
13
13
  | `onDismiss` | `(() => void) \| null \| false` | - | Dismiss callback (set to `false` to hide X button) |
14
14
  | `class` | `string` | - | CSS for container |
15
15
  | `classContent` | `string` | - | CSS for content area |
16
- | `classDismiss` | `string` | - | CSS for dismiss button |
17
- | `classX` | `string` | - | CSS for X icon |
18
16
 
19
17
  ## Usage
20
18
 
@@ -22,7 +20,7 @@ A dismissible alert/message component with color themes and slide transition.
22
20
 
23
21
  ```svelte
24
22
  <script lang="ts">
25
- import { DismissibleMessage } from 'stuic';
23
+ import { DismissibleMessage } from '@marianmeres/stuic';
26
24
 
27
25
  let message = $state('This is an important notice.');
28
26
  </script>
@@ -33,27 +31,41 @@ A dismissible alert/message component with color themes and slide transition.
33
31
  />
34
32
  ```
35
33
 
36
- ### With Theme Colors
34
+ ### With Semantic Intents
37
35
 
38
36
  ```svelte
39
37
  <script lang="ts">
40
- import { DismissibleMessage } from 'stuic';
38
+ import { DismissibleMessage } from '@marianmeres/stuic';
41
39
 
42
40
  let error = $state('Something went wrong!');
43
41
  let success = $state('Operation completed successfully.');
44
42
  </script>
45
43
 
44
+ <!-- Error/destructive message -->
46
45
  <DismissibleMessage
47
46
  message={error}
48
- theme="red"
47
+ intent="destructive"
49
48
  onDismiss={() => error = ''}
50
49
  />
51
50
 
51
+ <!-- Success message -->
52
52
  <DismissibleMessage
53
53
  message={success}
54
- theme="green"
54
+ intent="success"
55
55
  onDismiss={() => success = ''}
56
56
  />
57
+
58
+ <!-- Warning message -->
59
+ <DismissibleMessage
60
+ message="Please review your changes"
61
+ intent="warning"
62
+ />
63
+
64
+ <!-- Info message -->
65
+ <DismissibleMessage
66
+ message="New features are available"
67
+ intent="info"
68
+ />
57
69
  ```
58
70
 
59
71
  ### Non-Dismissible
@@ -61,7 +73,7 @@ A dismissible alert/message component with color themes and slide transition.
61
73
  ```svelte
62
74
  <DismissibleMessage
63
75
  message="This message cannot be dismissed."
64
- theme="blue"
76
+ intent="info"
65
77
  onDismiss={false}
66
78
  />
67
79
  ```
@@ -84,8 +96,78 @@ A dismissible alert/message component with color themes and slide transition.
84
96
  {#if error}
85
97
  <DismissibleMessage
86
98
  message={error}
87
- theme="red"
99
+ intent="destructive"
88
100
  onDismiss={() => error = null}
89
101
  />
90
102
  {/if}
91
103
  ```
104
+
105
+ ## CSS Variables
106
+
107
+ ### Component Tokens
108
+
109
+ | Variable | Default | Description |
110
+ |----------|---------|-------------|
111
+ | `--stuic-dismissible-message-radius` | `var(--radius-md)` | Border radius |
112
+ | `--stuic-dismissible-message-padding-x` | `calc(var(--spacing) * 4)` | Horizontal padding |
113
+ | `--stuic-dismissible-message-padding-y` | `calc(var(--spacing) * 3)` | Vertical padding |
114
+ | `--stuic-dismissible-message-border-width` | `1px` | Border width |
115
+ | `--stuic-dismissible-message-transition` | `150ms` | Color transition duration |
116
+
117
+ ### Customization Examples
118
+
119
+ ```css
120
+ /* Global override */
121
+ :root {
122
+ --stuic-dismissible-message-radius: var(--radius-lg);
123
+ --stuic-dismissible-message-padding-x: calc(var(--spacing) * 6);
124
+ }
125
+ ```
126
+
127
+ ```svelte
128
+ <!-- Inline override -->
129
+ <DismissibleMessage
130
+ message="Custom styled message"
131
+ style="--stuic-dismissible-message-radius: 9999px;"
132
+ />
133
+ ```
134
+
135
+ ### Intent Colors
136
+
137
+ Intent colors are derived from the global STUIC design tokens:
138
+
139
+ | Intent | Token Used |
140
+ |--------|------------|
141
+ | `destructive` | `--stuic-color-destructive` |
142
+ | `warning` | `--stuic-color-warning` |
143
+ | `success` | `--stuic-color-success` |
144
+ | `info` | `--stuic-color-info` |
145
+
146
+ Customize these in your theme file to change all components at once.
147
+
148
+ ## Data Attributes
149
+
150
+ The component uses data attributes for CSS targeting:
151
+
152
+ - `data-intent` - The intent value (when set)
153
+
154
+ ```css
155
+ /* Custom styling for specific intent */
156
+ .stuic-dismissible-message[data-intent="destructive"] {
157
+ font-weight: bold;
158
+ }
159
+ ```
160
+
161
+ ## Migration from v2
162
+
163
+ The `theme` prop has been replaced with `intent`:
164
+
165
+ | Old (v2) | New (v3) |
166
+ |----------|----------|
167
+ | `theme="red"` | `intent="destructive"` |
168
+ | `theme="orange"` | `intent="warning"` |
169
+ | `theme="green"` | `intent="success"` |
170
+ | `theme="blue"` | `intent="info"` |
171
+ | No theme | No intent (default) |
172
+
173
+ The `classDismiss` and `classX` props have been removed.
@@ -1,11 +1,131 @@
1
- /* prettier-ignore */
2
- @theme inline {
3
- --color-dismiss-bg: var(--color-dismiss-bg, var(--color-neutral-200));
4
- --color-dismiss-bg-dark: var(--color-dismiss-bg-dark, var(--color-neutral-700));
1
+ /* =============================================================================
2
+ DISMISSIBLE MESSAGE COMPONENT TOKENS
3
+ Override globally: :root { --stuic-dismissible-message-radius: 0; }
4
+ Override locally: style="--stuic-dismissible-message-radius: 9999px;"
5
+ ============================================================================= */
5
6
 
6
- --color-dismiss-text: var(--color-dismiss-text, var(--color-neutral-700));
7
- --color-dismiss-text-dark: var(--color-dismiss-text-dark, var(--color-neutral-200));
7
+ :root {
8
+ --stuic-dismissible-message-radius: var(--radius-md);
9
+ --stuic-dismissible-message-padding-x: calc(var(--spacing) * 4);
10
+ --stuic-dismissible-message-padding-y: calc(var(--spacing) * 3);
11
+ --stuic-dismissible-message-border-width: 1px;
12
+ --stuic-dismissible-message-transition: 150ms;
13
+ }
14
+
15
+ @layer components {
16
+ /* =============================================================================
17
+ BASE STYLES
18
+ ============================================================================= */
19
+
20
+ .stuic-dismissible-message {
21
+ display: flex;
22
+ align-items: center;
23
+ border-width: var(--stuic-dismissible-message-border-width);
24
+ border-style: solid;
25
+ border-radius: var(--stuic-dismissible-message-radius);
26
+ transition:
27
+ background var(--stuic-dismissible-message-transition),
28
+ border-color var(--stuic-dismissible-message-transition);
29
+
30
+ /* Colors via internal vars set by intent */
31
+ background: var(--_bg);
32
+ color: var(--_text);
33
+ border-color: var(--_border);
34
+ }
35
+
36
+ /* Content area */
37
+ .stuic-dismissible-message > .content {
38
+ flex: 1;
39
+ padding: var(--stuic-dismissible-message-padding-y)
40
+ var(--stuic-dismissible-message-padding-x);
41
+ }
42
+
43
+ /* Icon container (left side) */
44
+ .stuic-dismissible-message > .icon {
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ flex-shrink: 0;
49
+ padding-left: var(--stuic-dismissible-message-padding-x);
50
+ color: var(--_text);
51
+ opacity: 0.85;
52
+ }
53
+
54
+ .stuic-dismissible-message > .icon svg {
55
+ width: 1.5rem;
56
+ height: 1.5rem;
57
+ }
58
+
59
+ /* Dismiss button container */
60
+ .stuic-dismissible-message > .dismiss {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ padding: calc(var(--stuic-dismissible-message-padding-y) * 0.75);
65
+ }
66
+
67
+ /* Dismiss button inherits message text color */
68
+ .stuic-dismissible-message > .dismiss .stuic-button {
69
+ color: var(--_text);
70
+ }
71
+
72
+ /* =============================================================================
73
+ DEFAULT (NO INTENT): NEUTRAL MUTED APPEARANCE
74
+ ============================================================================= */
75
+
76
+ .stuic-dismissible-message:not([data-intent]) {
77
+ --_bg: var(--stuic-color-muted);
78
+ --_text: var(--stuic-color-muted-foreground);
79
+ --_border: var(--stuic-color-border);
80
+ }
81
+
82
+ /* =============================================================================
83
+ INTENT COLOR MAPPING (SOFT STYLE)
84
+ Each intent uses a soft/tinted appearance appropriate for messages.
85
+ ============================================================================= */
86
+
87
+ /* Destructive: error messages */
88
+ .stuic-dismissible-message[data-intent="destructive"] {
89
+ --_bg: color-mix(in srgb, var(--stuic-color-destructive) 15%, transparent);
90
+ /* --_text: var(--stuic-color-destructive); */
91
+ --_text: color-mix(in srgb, var(--stuic-color-destructive), black 15%);
92
+ --_border: color-mix(in srgb, var(--stuic-color-destructive) 30%, transparent);
93
+ }
94
+
95
+ /* Warning: caution messages */
96
+ .stuic-dismissible-message[data-intent="warning"] {
97
+ --_bg: color-mix(in srgb, var(--stuic-color-warning) 15%, transparent);
98
+ /* --_text: var(--stuic-color-warning); */
99
+ --_text: color-mix(in srgb, var(--stuic-color-warning), black 15%);
100
+ --_border: color-mix(in srgb, var(--stuic-color-warning) 30%, transparent);
101
+ }
102
+
103
+ /* Success: confirmation messages */
104
+ .stuic-dismissible-message[data-intent="success"] {
105
+ --_bg: color-mix(in srgb, var(--stuic-color-success) 15%, transparent);
106
+ /* --_text: var(--stuic-color-success); */
107
+ --_text: color-mix(in srgb, var(--stuic-color-success), black 15%);
108
+ --_border: color-mix(in srgb, var(--stuic-color-success) 30%, transparent);
109
+ }
110
+
111
+ /* Info: informational messages */
112
+ .stuic-dismissible-message[data-intent="info"] {
113
+ --_bg: color-mix(in srgb, var(--stuic-color-info) 15%, transparent);
114
+ /* --_text: var(--stuic-color-info); */
115
+ --_text: color-mix(in srgb, var(--stuic-color-info), black 15%);
116
+ --_border: color-mix(in srgb, var(--stuic-color-info) 30%, transparent);
117
+ }
118
+
119
+ /* =============================================================================
120
+ DARK MODE ADJUSTMENTS
121
+ Increase color intensity for better visibility in dark mode.
122
+ ============================================================================= */
8
123
 
9
- --color-dismiss-border: var(--color-dismiss-border, var(--color-neutral-500));
10
- --color-dismiss-border-dark: var(--color-dismiss-border-dark, var(--color-neutral-500));
124
+ .dark .stuic-dismissible-message[data-intent="destructive"],
125
+ .dark .stuic-dismissible-message[data-intent="warning"],
126
+ .dark .stuic-dismissible-message[data-intent="success"],
127
+ .dark .stuic-dismissible-message[data-intent="info"] {
128
+ --_bg: color-mix(in srgb, var(--_text) 20%, transparent);
129
+ --_border: color-mix(in srgb, var(--_text) 40%, transparent);
130
+ }
11
131
  }
@@ -1 +1 @@
1
- export { default as DismissibleMessage, type Props as DismissibleMessageProps, } from "./DismissibleMessage.svelte";
1
+ export { default as DismissibleMessage, type Props as DismissibleMessageProps, type MessageIntent as DismissibleMessageIntent, } from "./DismissibleMessage.svelte";
@@ -205,49 +205,17 @@
205
205
  );
206
206
  }
207
207
 
208
- export const DROPDOWN_MENU_BASE_CLASSES = `stuic-dropdown-menu relative inline-block`;
209
-
210
- export const DROPDOWN_MENU_TRIGGER_CLASSES = `
211
- inline-flex items-center justify-center gap-2
212
- px-3 py-2
213
- rounded-md border
214
- bg-white dark:bg-neutral-800
215
- text-neutral-900 dark:text-neutral-100
216
- border-neutral-200 dark:border-neutral-700
217
- hover:brightness-95 dark:hover:brightness-110
218
- cursor-pointer
219
- `;
220
- // focus-visible:outline-2 focus-visible:outline-offset-2
221
-
222
- export const DROPDOWN_MENU_DROPDOWN_CLASSES = `
223
- stuic-dropdown-menu-dropdown
224
- bg-white dark:bg-neutral-800
225
- text-neutral-900 dark:text-neutral-100
226
- border border-neutral-200 dark:border-neutral-700
227
- rounded-md shadow-sm
228
- p-1
229
- overflow-y-auto
230
- z-50
231
- min-w-48
232
- `;
233
-
234
- export const DROPDOWN_MENU_DIVIDER_CLASSES = `
235
- h-px my-1
236
- bg-neutral-200 dark:bg-neutral-700
237
- `;
238
-
239
- export const DROPDOWN_MENU_HEADER_CLASSES = `
240
- px-2 py-1.5
241
- text-xs font-semibold uppercase tracking-wide
242
- text-neutral-500 dark:text-neutral-400
243
- select-none
244
- `;
245
-
246
- export const DROPDOWN_MENU_BACKDROP_CLASSES = `
247
- stuic-dropdown-menu-backdrop
248
- fixed inset-0 bg-black/25
249
- z-40
250
- `;
208
+ export const DROPDOWN_MENU_BASE_CLASSES = `stuic-dropdown-menu`;
209
+
210
+ export const DROPDOWN_MENU_TRIGGER_CLASSES = `stuic-dropdown-menu-trigger`;
211
+
212
+ export const DROPDOWN_MENU_DROPDOWN_CLASSES = `stuic-dropdown-menu-dropdown`;
213
+
214
+ export const DROPDOWN_MENU_DIVIDER_CLASSES = `stuic-dropdown-menu-divider`;
215
+
216
+ export const DROPDOWN_MENU_HEADER_CLASSES = `stuic-dropdown-menu-header`;
217
+
218
+ export const DROPDOWN_MENU_BACKDROP_CLASSES = `stuic-dropdown-menu-backdrop`;
251
219
  </script>
252
220
 
253
221
  <script lang="ts">
@@ -261,7 +229,6 @@
261
229
  import { untrack } from "svelte";
262
230
  import Thc from "../Thc/Thc.svelte";
263
231
  import ListItemButton from "../ListItemButton/ListItemButton.svelte";
264
- import "./index.css";
265
232
  import { BodyScroll } from "../../utils/body-scroll-locker.js";
266
233
  import { waitForTwoRepaints } from "../../utils/paint.js";
267
234
 
@@ -659,15 +626,11 @@
659
626
  >
660
627
  <!-- Close button (fallback mode only) -->
661
628
  {#if !isSupported}
662
- <div class="sticky top-0 right-0 z-10 flex just pointer-events-none">
629
+ <div class="sticky top-0 right-0 z-10 flex pointer-events-none">
663
630
  <button
664
631
  type="button"
665
632
  aria-label="Close"
666
- class={[
667
- "bg-black text-white rounded-md cursor-pointer opacity-60",
668
- "absolute right-0 top-0 p-2",
669
- "leading-none hover:opacity-100 pointer-events-auto",
670
- ]}
633
+ class="stuic-dropdown-menu-close absolute right-0 top-0 pointer-events-auto"
671
634
  onclick={() => {
672
635
  isOpen = false;
673
636
  triggerEl?.focus();
@@ -760,7 +723,7 @@
760
723
  {#if isExpanded}
761
724
  <div
762
725
  class={twMerge(
763
- "stuic-dropdown-menu-expandable-content pl-4",
726
+ "stuic-dropdown-menu-expandable-content",
764
727
  classExpandableContent
765
728
  )}
766
729
  transition:slide={{ duration: transitionDuration }}