@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
@@ -16,22 +16,20 @@
16
16
  noSpinner?: boolean;
17
17
  noListAllOnEmptyQ?: boolean;
18
18
  appendHint?: string;
19
+ /** Function to reset the ghost text (provided by the component) */
20
+ resetGhost?: () => void;
19
21
  }
20
22
  </script>
21
23
 
22
24
  <script lang="ts" generics="T extends Item">
23
- import { createClog } from "@marianmeres/clog";
24
- import { ItemCollection } from "@marianmeres/item-collection";
25
- import { Debounced, watch } from "runed";
25
+ import { typeahead } from "../../actions/typeahead.svelte.js";
26
26
  import { twMerge } from "../../utils/tw-merge.js";
27
- import { unaccent } from "../../utils/unaccent.js";
28
27
  import Spinner from "../Spinner/Spinner.svelte";
29
28
 
30
- const clog = createClog("TypeaheadInput");
31
-
32
29
  let {
33
30
  input = $bindable(),
34
31
  value = $bindable(),
32
+ resetGhost = $bindable(),
35
33
  placeholder,
36
34
  getOptions,
37
35
  renderOptionLabel,
@@ -48,115 +46,11 @@
48
46
  appendHint = " [tab]",
49
47
  }: Props<T> = $props();
50
48
 
51
- let inputEl: HTMLInputElement = $state()!;
52
- const randName = "name-" + Math.random().toString(36).slice(2);
53
- let isFetching = $state(false); // not used currently
54
- let previousKey = $state();
55
-
56
- // special case flag to allow listing all available options when navigating with arrows
57
- // even on empty query
58
- let allowListAll = $state(false);
59
-
60
- // ItemCollection of all possible candidates based on the current query (value)
61
- // svelte-ignore state_referenced_locally
62
- const options = new ItemCollection<T>([], {
63
- idPropName: itemIdPropName,
64
- searchable: { getContent: (item) => _renderOptionLabel(item) },
65
- allowNextPrevCycle: true,
66
- sortFn: (a, b) => {
67
- const _a = _renderOptionLabel(a).toLowerCase();
68
- const _b = _renderOptionLabel(b).toLowerCase();
69
- return _a.localeCompare(_b);
70
- },
71
- });
72
-
73
- // deriving the actual suggestion from available candidates...
74
- let available = $derived($options);
75
- let suggestion: string = $derived.by(() => {
76
- if (!available.active) return "";
77
- // a little dance, since we need to be case insensitive
78
- // otherwise we would just: `value = _renderOptionLabel(available.active)`
79
- const suggestion = _renderOptionLabel(available.active);
80
- return (value || "") + suggestion.slice(value?.length || 0);
81
- });
82
-
83
- let visibleSuggestion: string = $derived.by(() => {
84
- if (
85
- !suggestion ||
86
- unaccent(suggestion.toLowerCase()) === unaccent(value?.toLowerCase())
87
- ) {
88
- return "";
89
- }
90
-
91
- return suggestion ? suggestion + appendHint : suggestion;
92
- });
93
-
94
- // helper
95
- function _renderOptionLabel(item: T): string {
96
- return renderOptionLabel?.(item) || `${item[itemIdPropName]}`;
97
- }
98
-
99
- // reset suggestion asap, even before the debounced search finishes (it feels better)
100
- // the debounce will take over short after
101
- watch([() => value], ([currQ], [oldQ]) => {
102
- if (value === undefined) return;
103
-
104
- // if we don't have a query or nothing is active, reset asap
105
- if ((!allowListAll && !currQ) || !available.active) {
106
- options.clear();
107
- return;
108
- }
109
-
110
- // we need to be case insensitive
111
- const suggestion = _renderOptionLabel(available.active);
112
- if (!suggestion.toLowerCase().startsWith(currQ.toLowerCase())) {
113
- options.clear();
114
- return;
115
- }
116
- });
117
-
118
- // do the query search
119
- const debounced = new Debounced(() => value, 150);
120
- watch([() => debounced.current, () => allowListAll], ([currQ, ala], [oldQ, _]) => {
121
- // always start fresh
122
- options.clear();
123
-
124
- // no suggestion on empty input
125
- if (!ala && !currQ) return;
126
-
127
- isFetching = true;
128
-
129
- getOptions(currQ, [])
130
- .then((res) => {
131
- // no options?
132
- if (!res.length) return;
49
+ let isFetching = $state(false);
133
50
 
134
- let found = res;
135
- if (currQ) {
136
- // so, here we have some candidate items... but, this is not a typical
137
- // "word search", this is an exact, case-insensitive "string begins with",
138
- // so we need to filter further...
139
- found = res.filter((item) => {
140
- const label = unaccent(_renderOptionLabel(item).toLowerCase());
141
- return label.startsWith(unaccent(currQ.toLowerCase()));
142
- });
143
- }
144
-
145
- // no exact "starts with" found?
146
- if (!found.length) return;
147
-
148
- // finally, this is where we pick the actual suggestion (by setting it as active)
149
- options.addMany(found);
150
- options.setActiveFirst();
151
- })
152
- .catch(clog.error)
153
- .finally(() => (isFetching = false));
154
- });
155
-
156
- //
157
51
  let _fixedInputClasses = $derived(
158
52
  twMerge(
159
- "form-input z-10 relative",
53
+ "z-10 relative",
160
54
  classInput,
161
55
  "text-black",
162
56
  "border-0 p-0 bg-transparent block w-full",
@@ -164,16 +58,6 @@
164
58
  "focus-visible:outline-0 focus-visible:border-0 focus-visible:ring-0"
165
59
  )
166
60
  );
167
-
168
- function _on_submit(v: string) {
169
- v = `${v || ""}`.trim();
170
- if (v) onSubmit?.(v);
171
- // reset this flag, next up/down arrow will switch it on again
172
- allowListAll = false;
173
- }
174
-
175
- // $inspect({ isFetching, value, suggestion }).with(clog);
176
- // $inspect({ previousKey }).with(clog);
177
61
  </script>
178
62
 
179
63
  <div class={twMerge("", classProp)}>
@@ -182,78 +66,26 @@
182
66
  <input
183
67
  type="text"
184
68
  bind:value
185
- bind:this={inputEl}
69
+ bind:this={input}
186
70
  {name}
187
71
  class={twMerge(_fixedInputClasses)}
188
- placeholder={suggestion ? "" : placeholder}
72
+ {placeholder}
189
73
  autocomplete="off"
190
- onkeydown={(e) => {
191
- // ignore on any modifier key
192
- if (e.shiftKey || e.ctrlKey || e.altKey || e.metaKey) {
193
- return;
194
- }
195
-
196
- const cursorPos = inputEl.selectionStart ?? 0;
197
-
198
- // also ignore ArrowRight if cursor is not at the end
199
- if (value?.length) {
200
- const maxPos = value.length;
201
- // clog({ cursorPosition: pos, maxPos, value });
202
- if (e.key === "ArrowRight" && cursorPos < maxPos) return;
203
- }
204
-
205
- // special case Tab handling - if we hit Enter just before, we want Tab
206
- // to behave normally (so we are able to set value which HAS a suggestion
207
- // but is NOT a suggestion - eg "New" vs "New York")
208
- if (previousKey === "Enter" && e.key === "Tab") {
209
- return;
210
- }
211
-
212
- // this acts as trigger for getOptions if empty value (`allowListAll` is watched)
213
- allowListAll =
214
- !value?.length &&
215
- !noListAllOnEmptyQ &&
216
- ["ArrowDown", "ArrowUp"].includes(e.key);
217
-
218
- //
219
- const suggestion = options.active ? _renderOptionLabel(options.active) : null;
220
- if (e.key === "ArrowDown") {
221
- options.setActiveNext();
222
- e.preventDefault();
223
- } else if (e.key === "ArrowUp") {
224
- options.setActivePrevious();
225
- e.preventDefault();
226
- } else if (["ArrowRight", "Tab"].includes(e.key) && suggestion) {
227
- if (e.key === "Tab" && value !== suggestion) {
228
- e.preventDefault();
229
- }
230
- value = suggestion;
231
- if (e.key === "Tab") _on_submit(value);
232
- } else if (e.key === "Enter") {
233
- options.clear();
234
- _on_submit(value);
235
- } else if (e.key === "Backspace" && cursorPos === 0) {
236
- onDeleteRequest?.();
237
- }
238
-
239
- previousKey = e.key;
240
- }}
241
- onblur={() => _on_submit(value)}
242
- />
243
- <input
244
- type="text"
245
- bind:value={visibleSuggestion}
246
- class={twMerge(
247
- _fixedInputClasses,
248
- "absolute inset-0 pointer-events-none opacity-40 z-0"
249
- )}
250
- name={randName}
251
- tabindex="-1"
252
- readonly
74
+ use:typeahead={() => ({
75
+ getOptions,
76
+ renderOptionLabel,
77
+ itemIdPropName,
78
+ onSubmit,
79
+ onDeleteRequest,
80
+ noListAllOnEmptyQ,
81
+ appendHint,
82
+ onFetchingChange: (fetching) => (isFetching = fetching),
83
+ onResetGhost: (fn) => (resetGhost = fn),
84
+ })}
253
85
  />
254
86
  </div>
255
87
  {#if !noSpinner && isFetching}
256
- <Spinner class="size-5 opacity-50" />
88
+ <Spinner class="size-5" />
257
89
  {/if}
258
90
  </div>
259
91
  </div>
@@ -14,11 +14,13 @@ export interface Props<T extends Item = Item> {
14
14
  noSpinner?: boolean;
15
15
  noListAllOnEmptyQ?: boolean;
16
16
  appendHint?: string;
17
+ /** Function to reset the ghost text (provided by the component) */
18
+ resetGhost?: () => void;
17
19
  }
18
20
  declare function $$render<T extends Item>(): {
19
21
  props: Props<T>;
20
22
  exports: {};
21
- bindings: "value" | "input";
23
+ bindings: "value" | "input" | "resetGhost";
22
24
  slots: {};
23
25
  events: {};
24
26
  };
@@ -26,7 +28,7 @@ declare class __sveltets_Render<T extends Item> {
26
28
  props(): ReturnType<typeof $$render<T>>['props'];
27
29
  events(): ReturnType<typeof $$render<T>>['events'];
28
30
  slots(): ReturnType<typeof $$render<T>>['slots'];
29
- bindings(): "value" | "input";
31
+ bindings(): "value" | "input" | "resetGhost";
30
32
  exports(): {};
31
33
  }
32
34
  interface $$IsomorphicComponent {
@@ -3,17 +3,22 @@
3
3
  export interface Props {
4
4
  class?: string;
5
5
  strokeWidth?: 0.5 | 1 | 1.5 | 2 | 2.5 | 3 | 3.5 | 4;
6
+ linecapRound?: boolean;
6
7
  }
7
8
  </script>
8
9
 
9
10
  <script lang="ts">
10
- let { class: classProps, strokeWidth }: Props = $props();
11
+ let { class: classProps, strokeWidth, linecapRound = true }: Props = $props();
11
12
 
12
- const dp = new DevicePointer();
13
- const auto = $derived(dp.isCoarse ? 3 : 2);
13
+ // motivation - make it thicker on mobile, especially for weary eyes
14
+ // (note: dp.isCoarse does not say nothing technically about mobile, but in 90% it will)
15
+ // const dp = new DevicePointer();
16
+ // const auto = $derived(dp.isCoarse ? 3 : 2);
14
17
 
15
18
  // if sw not provided use thicker on mobile
16
- const _strokeWidth = $derived(strokeWidth ?? auto);
19
+ const _strokeWidth = $derived(strokeWidth ?? 2);
20
+
21
+ const _strokeLinecap = $derived(linecapRound ? "round" : "square");
17
22
 
18
23
  // size-6 = 1.5rem = 24px
19
24
  </script>
@@ -25,5 +30,7 @@
25
30
  stroke="currentColor"
26
31
  class={twMerge("inline size-6", classProps)}
27
32
  >
28
- <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
33
+ <!-- iconLucideX -->
34
+ <path stroke-linecap={_strokeLinecap} d="M18 6 6 18" />
35
+ <path stroke-linecap={_strokeLinecap} d="m6 6 12 12" />
29
36
  </svg>
@@ -1,6 +1,7 @@
1
1
  export interface Props {
2
2
  class?: string;
3
3
  strokeWidth?: 0.5 | 1 | 1.5 | 2 | 2.5 | 3 | 3.5 | 4;
4
+ linecapRound?: boolean;
4
5
  }
5
6
  declare const X: import("svelte").Component<Props, {}, "">;
6
7
  type X = ReturnType<typeof X>;
@@ -36,3 +36,4 @@ export { iconLucideSquare as iconSquare } from "@marianmeres/icons-fns/lucide/ic
36
36
  export { iconLucideMenu as iconMenu } from "@marianmeres/icons-fns/lucide/iconLucideMenu.js";
37
37
  export { iconLucideUser as iconUser } from "@marianmeres/icons-fns/lucide/iconLucideUser.js";
38
38
  export { iconLucideEllipsisVertical as iconEllipsisVertical } from "@marianmeres/icons-fns/lucide/iconLucideEllipsisVertical.js";
39
+ export { iconLucideSettings as iconSettings } from "@marianmeres/icons-fns/lucide/iconLucideSettings.js";
@@ -40,3 +40,4 @@ export { iconLucideSquare as iconSquare } from "@marianmeres/icons-fns/lucide/ic
40
40
  export { iconLucideMenu as iconMenu } from "@marianmeres/icons-fns/lucide/iconLucideMenu.js";
41
41
  export { iconLucideUser as iconUser } from "@marianmeres/icons-fns/lucide/iconLucideUser.js";
42
42
  export { iconLucideEllipsisVertical as iconEllipsisVertical } from "@marianmeres/icons-fns/lucide/iconLucideEllipsisVertical.js";
43
+ export { iconLucideSettings as iconSettings } from "@marianmeres/icons-fns/lucide/iconLucideSettings.js";
package/dist/index.css CHANGED
@@ -1,33 +1,54 @@
1
- /*
2
- Tailwind import removed here because it causes CSS cascade/layer issues in WebKit browsers
3
- (Safari, iOS Chrome) when consumers also import Tailwind. The double import can result in
4
- Tailwind's preflight styles (like border-style: solid) not being applied correctly.
5
- Consumers of STUIC should import Tailwind at their own app level.
6
- */
7
- /* @import "tailwindcss"; */
1
+ @source "./";
8
2
 
9
- @plugin '@tailwindcss/forms';
3
+ /* */
4
+ @import "./themes/neutral.css";
10
5
 
11
- @custom-variant dark (&:where(.dark, .dark *));
6
+ /*****************************************************************************************
12
7
 
13
- @source "./";
8
+ # Component CSS - centralized to avoid race conditions with barrel exports
14
9
 
15
- /* "components" looks like a better fit here, but forms plugin uses "utilities"
16
- so, since we need to override, sticking with that */
17
- @layer utilities {
18
- @import "./actions/tooltip/index.css";
19
- @import "./components/Button/index.css";
20
- @import "./components/ButtonGroupRadio/index.css";
21
- @import "./components/DismissibleMessage/index.css";
22
- @import "./components/Input/index.css";
23
- @import "./components/ListItemButton/index.css";
24
- @import "./components/Notifications/index.css";
25
- @import "./components/Progress/index.css";
26
- @import "./components/Switch/index.css";
27
- @import "./components/TabbedMenu/index.css";
28
- @import "./components/TwCheck/index.css";
29
- }
10
+ Barrel exports + CSS side effects = race conditions
11
+
12
+ When you use barrel exports (export * from) in a library entry point, importing
13
+ anything from that barrel causes all modules to be evaluated. If those modules have
14
+ CSS side effects (like import "./index.css" in Svelte components), all CSS files load
15
+ simultaneously in unpredictable order.
16
+
17
+ The fix: Centralize CSS imports in a single entry point (like lib/index.css) that
18
+ loads at app startup, rather than letting each component import its own CSS. This
19
+ ensures CSS loads in a deterministic order before any components render.
20
+
21
+ In practice:
22
+ - ✅ Component CSS in centralized lib/index.css
23
+ - ❌ import "./index.css" inside each component
24
+
25
+ *****************************************************************************************/
26
+ @import "./components/AlertConfirmPrompt/index.css";
27
+ @import "./components/AssetsPreview/index.css";
28
+ @import "./components/Avatar/index.css";
29
+ @import "./components/Backdrop/index.css";
30
+ @import "./components/Button/index.css";
31
+ @import "./components/ButtonGroupRadio/index.css";
32
+ @import "./components/Collapsible/index.css";
33
+ @import "./components/CommandMenu/index.css";
34
+ @import "./components/DismissibleMessage/index.css";
35
+ @import "./components/DropdownMenu/index.css";
36
+ @import "./components/Input/index.css";
37
+ @import "./components/KbdShortcut/index.css";
38
+ @import "./components/ListItemButton/index.css";
39
+ @import "./components/Modal/index.css";
40
+ @import "./components/ModalDialog/index.css";
41
+ @import "./components/Nav/index.css";
42
+ @import "./components/Notifications/index.css";
43
+ @import "./components/Progress/index.css";
44
+ @import "./components/Skeleton/index.css";
45
+ @import "./components/Spinner/index.css";
46
+ @import "./components/Switch/index.css";
47
+ @import "./components/TabbedMenu/index.css";
48
+ @import "./components/ThemePreview/index.css";
49
+ @import "./components/TwCheck/index.css";
30
50
 
51
+ /* Base styles for STUIC components */
31
52
  @layer base {
32
53
  button:not(:disabled),
33
54
  [role="button"]:not(:disabled) {
@@ -38,7 +59,6 @@ so, since we need to override, sticking with that */
38
59
  [role="button"]:disabled,
39
60
  input:disabled {
40
61
  cursor: not-allowed !important;
41
- /* opacity: 0.5 !important; moved to Button itself, so it can be overridden */
42
62
  }
43
63
  }
44
64
 
package/dist/index.d.ts CHANGED
@@ -41,6 +41,7 @@ export * from "./components/KbdShortcut/index.js";
41
41
  export * from "./components/ListItemButton/index.js";
42
42
  export * from "./components/Modal/index.js";
43
43
  export * from "./components/ModalDialog/index.js";
44
+ export * from "./components/Nav/index.js";
44
45
  export * from "./components/Notifications/index.js";
45
46
  export * from "./components/Progress/index.js";
46
47
  export * from "./components/Skeleton/index.js";
@@ -49,6 +50,7 @@ export * from "./components/Spinner/index.js";
49
50
  export * from "./components/Switch/index.js";
50
51
  export * from "./components/TabbedMenu/index.js";
51
52
  export * from "./components/Thc/index.js";
53
+ export * from "./components/ThemePreview/index.js";
52
54
  export * from "./components/TwCheck/index.js";
53
55
  export * from "./components/TypeaheadInput/index.js";
54
56
  export * from "./components/X/index.js";
package/dist/index.js CHANGED
@@ -42,6 +42,7 @@ export * from "./components/KbdShortcut/index.js";
42
42
  export * from "./components/ListItemButton/index.js";
43
43
  export * from "./components/Modal/index.js";
44
44
  export * from "./components/ModalDialog/index.js";
45
+ export * from "./components/Nav/index.js";
45
46
  export * from "./components/Notifications/index.js";
46
47
  export * from "./components/Progress/index.js";
47
48
  export * from "./components/Skeleton/index.js";
@@ -50,6 +51,7 @@ export * from "./components/Spinner/index.js";
50
51
  export * from "./components/Switch/index.js";
51
52
  export * from "./components/TabbedMenu/index.js";
52
53
  export * from "./components/Thc/index.js";
54
+ export * from "./components/ThemePreview/index.js";
53
55
  export * from "./components/TwCheck/index.js";
54
56
  export * from "./components/TypeaheadInput/index.js";
55
57
  export * from "./components/X/index.js";