@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
@@ -1,80 +1,192 @@
1
1
  # Spinner
2
2
 
3
- A customizable loading spinner with rotating segments. Pure CSS animation with configurable appearance.
3
+ A family of loading spinner components with different visual styles. All spinners inherit color from `currentColor`, making them easy to style with Tailwind text color classes.
4
4
 
5
- ## Props
5
+ ## Components
6
+
7
+ | Component | Description |
8
+ |-----------|-------------|
9
+ | `Spinner` | Radial bar spinner with fading segments |
10
+ | `SpinnerCircle` | Simple circular border spinner |
11
+ | `SpinnerCircleOscillate` | Circle with oscillating progress animation |
12
+ | `SpinnerUnicode` | Unicode character-based spinner (17+ variants) |
13
+
14
+ ---
15
+
16
+ ## Spinner
17
+
18
+ Rotating segments that fade in sequence. Pure CSS animation.
19
+
20
+ ### Props
6
21
 
7
22
  | Prop | Type | Default | Description |
8
23
  |------|------|---------|-------------|
9
- | `duration` | `number` | `750` | One full rotation duration (ms) |
10
- | `count` | `number` | `8` | Number of segments/hands (3-12) |
11
- | `thickness` | `"thin" \| "normal" \| "thick"` | `"thick"` | Segment width |
24
+ | `count` | `number` | `8` | Number of segments (3-12 recommended) |
25
+ | `thickness` | `"thin" \| "normal" \| "thick"` | `"normal"` | Segment width |
12
26
  | `height` | `"short" \| "normal" \| "tall"` | `"normal"` | Segment length |
13
- | `direction` | `"cw" \| "ccw"` | `"cw"` | Rotation direction (clockwise/counter-clockwise) |
14
- | `class` | `string` | - | CSS classes for sizing |
15
-
16
- ## Usage
27
+ | `direction` | `"cw" \| "ccw"` | `"cw"` | Rotation direction |
28
+ | `duration` | `number` | `750` | Animation duration (ms) |
29
+ | `rounded` | `number` | `2` | Border radius of segments (px) |
30
+ | `class` | `string` | - | Additional CSS classes |
17
31
 
18
- ### Basic Spinner
32
+ ### Usage
19
33
 
20
34
  ```svelte
21
- <script lang="ts">
22
- import { Spinner } from 'stuic';
23
- </script>
24
-
25
35
  <Spinner />
36
+ <Spinner thickness="thin" count={12} />
37
+ <Spinner class="text-blue-500" direction="ccw" />
26
38
  ```
27
39
 
28
- ### Different Sizes
40
+ ---
41
+
42
+ ## SpinnerCircle
43
+
44
+ Simple circular spinner using CSS border animation.
45
+
46
+ ### Props
47
+
48
+ | Prop | Type | Default | Description |
49
+ |------|------|---------|-------------|
50
+ | `thickness` | `"thin" \| "normal" \| "thick"` | `"normal"` | Border thickness |
51
+ | `direction` | `"cw" \| "ccw"` | `"cw"` | Rotation direction |
52
+ | `duration` | `number` | `750` | Animation duration (ms) |
53
+ | `class` | `string` | - | Additional CSS classes |
54
+
55
+ ### Usage
29
56
 
30
57
  ```svelte
31
- <Spinner class="w-4" />
32
- <Spinner class="w-6" />
33
- <Spinner class="w-8" />
34
- <Spinner class="w-12" />
58
+ <SpinnerCircle />
59
+ <SpinnerCircle thickness="thick" class="size-8" />
60
+ <SpinnerCircle class="text-red-500 size-6" direction="ccw" />
35
61
  ```
36
62
 
37
- ### Customized Appearance
63
+ ---
38
64
 
39
- ```svelte
40
- <!-- More segments, thinner -->
41
- <Spinner count={12} thickness="thin" />
65
+ ## SpinnerCircleOscillate
66
+
67
+ Circle progress indicator with oscillating completeness animation.
68
+
69
+ ### Props
42
70
 
43
- <!-- Fewer segments, thicker, taller -->
44
- <Spinner count={4} thickness="thick" height="tall" />
71
+ | Prop | Type | Default | Description |
72
+ |------|------|---------|-------------|
73
+ | `bgStrokeColor` | `string` | CSS variable | Background stroke color |
74
+ | `strokeWidth` | `number` | - | Stroke width |
75
+ | `noOscillate` | `boolean` | `false` | Disable oscillation (static 66%) |
76
+ | `rotateDuration` | `string` | CSS variable | Rotation duration (e.g., ".75s") |
77
+ | `class` | `string` | - | Additional CSS classes |
78
+
79
+ ### Usage
80
+
81
+ ```svelte
82
+ <SpinnerCircleOscillate />
83
+ <SpinnerCircleOscillate class="text-blue-500 size-8" />
84
+ <SpinnerCircleOscillate noOscillate bgStrokeColor="" />
45
85
  ```
46
86
 
47
- ### Slower/Faster Animation
87
+ ---
88
+
89
+ ## SpinnerUnicode
90
+
91
+ Text-based spinner cycling through Unicode characters.
92
+
93
+ ### Props
94
+
95
+ | Prop | Type | Default | Description |
96
+ |------|------|---------|-------------|
97
+ | `variant` | `SpinnerUnicodeVariant` | `"braille_bar_dot"` | Built-in animation variant |
98
+ | `speed` | `number` | `100` | Frame duration (ms) |
99
+ | `reversed` | `boolean` | `false` | Reverse animation direction |
100
+ | `frames` | `string[]` | - | Custom frame array |
101
+ | `class` | `string` | - | Additional CSS classes |
102
+
103
+ ### Built-in Variants
104
+
105
+ `braille_bar`, `braille_bar_dot`, `braille_dot_circle`, `braille_dot_bounce`, `half_circle`, `quarter_circle`, `ascii`, `bar_v`, `bar_h`, `shade`, `arrows`, `arrows2`, `asterix`, `asterix2`, `asterix3`, `asterix4`, `asterix5`
106
+
107
+ ### Usage
48
108
 
49
109
  ```svelte
50
- <Spinner duration={500} /> <!-- Faster -->
51
- <Spinner duration={1500} /> <!-- Slower -->
110
+ <SpinnerUnicode />
111
+ <SpinnerUnicode variant="ascii" />
112
+ <SpinnerUnicode variant="arrows" class="text-green-500" />
113
+
114
+ <!-- Custom frames -->
115
+ <SpinnerUnicode frames={spinnerCreateBackAndForthCharFrames(5, "■", "□")} />
116
+ ```
117
+
118
+ ---
119
+
120
+ ## CSS Customization
121
+
122
+ All spinners support customization via CSS variables.
123
+
124
+ ### Available Variables
125
+
126
+ ```css
127
+ :root {
128
+ /* Spinner (radial bars) */
129
+ --stuic-spinner-opacity: 0.8;
130
+ --stuic-spinner-fade-end-opacity: 0.12;
131
+ --stuic-spinner-duration: 750ms;
132
+
133
+ /* SpinnerCircle */
134
+ --stuic-spinner-circle-thickness-thin: 1px;
135
+ --stuic-spinner-circle-thickness-normal: 2px;
136
+ --stuic-spinner-circle-thickness-thick: 4px;
137
+ --stuic-spinner-circle-duration: 750ms;
138
+
139
+ /* SpinnerCircleOscillate */
140
+ --stuic-spinner-circle-oscillate-bg-stroke: var(--stuic-color-border, rgba(0 0 0 / 0.1));
141
+ --stuic-spinner-circle-oscillate-duration: 0.75s;
142
+
143
+ /* SpinnerUnicode */
144
+ --stuic-spinner-unicode-font-size: var(--text-xl);
145
+ }
52
146
  ```
53
147
 
54
- ### Counter-Clockwise
148
+ ### Global Override
149
+
150
+ ```css
151
+ :root {
152
+ --stuic-spinner-opacity: 1;
153
+ --stuic-spinner-circle-thickness-normal: 3px;
154
+ }
155
+ ```
156
+
157
+ ### Local Override
55
158
 
56
159
  ```svelte
57
- <Spinner direction="ccw" />
160
+ <Spinner style="--stuic-spinner-opacity: 0.5;" />
161
+ <SpinnerCircle style="--stuic-spinner-circle-duration: 500ms;" />
58
162
  ```
59
163
 
60
- ### With Custom Color
164
+ ---
165
+
166
+ ## Color Customization
167
+
168
+ All spinners use `currentColor`, so apply Tailwind text color classes:
61
169
 
62
170
  ```svelte
63
- <Spinner class="w-8 text-blue-500" />
64
- <Spinner class="w-8 text-green-500" />
171
+ <Spinner class="text-blue-500" />
172
+ <SpinnerCircle class="text-red-600" />
173
+ <SpinnerUnicode class="text-green-500" />
65
174
  ```
66
175
 
67
- ### Loading Button
176
+ ---
177
+
178
+ ## Loading Button Example
68
179
 
69
180
  ```svelte
70
181
  <script lang="ts">
182
+ import { Button, SpinnerCircle } from 'stuic';
71
183
  let loading = $state(false);
72
184
  </script>
73
185
 
74
- <button disabled={loading}>
186
+ <Button disabled={loading}>
75
187
  {#if loading}
76
- <Spinner class="w-4 mr-2" />
188
+ <SpinnerCircle class="size-4" />
77
189
  {/if}
78
190
  Submit
79
- </button>
191
+ </Button>
80
192
  ```
@@ -1,9 +1,10 @@
1
1
  <script lang="ts" module>
2
2
  export interface Props {
3
3
  class?: string;
4
+ style?: string;
4
5
  count?: number;
5
6
  thickness?: "thin" | "normal" | "thick";
6
- height?: "short" | "normal" | "tall";
7
+ size?: "sm" | "md" | "lg";
7
8
  direction?: "cw" | "ccw";
8
9
  rounded?: number;
9
10
  duration?: number;
@@ -15,9 +16,10 @@
15
16
 
16
17
  let {
17
18
  class: classProp,
19
+ style: styleProp,
18
20
  count = 8,
19
21
  thickness = "normal",
20
- height = "normal",
22
+ size = "md",
21
23
  direction = "cw",
22
24
  rounded = 2,
23
25
  duration = 750,
@@ -28,29 +30,28 @@
28
30
  normal: 2,
29
31
  thick: 4,
30
32
  };
31
- const heightMap: Record<NonNullable<Props["height"]>, number> = {
32
- short: 5,
33
- normal: 7,
34
- tall: 10,
33
+ const sizeMap: Record<NonNullable<Props["size"]>, number> = {
34
+ sm: 5,
35
+ md: 6,
36
+ lg: 10,
35
37
  };
36
38
 
37
- const barLength = $derived(heightMap[height]);
39
+ const barLength = $derived(sizeMap[size]);
38
40
  const barWidth = $derived(thicknessMap[thickness]);
39
- const size = $derived(barLength * 3);
40
- const center = $derived(size / 2);
41
+ const containerSize = $derived(barLength * 3);
42
+ const center = $derived(containerSize / 2);
41
43
  const barHeight = $derived(barLength - 1);
42
44
  </script>
43
45
 
44
46
  <div
45
- class={twMerge("spinner opacity-50", classProp)}
46
- style:--size="{size}px"
47
- style:--duration="{duration}ms"
47
+ class={twMerge("stuic-spinner", classProp)}
48
+ style="{styleProp ?? ''}; width: {containerSize}px; height: {containerSize}px; --stuic-spinner-duration: {duration}ms;"
48
49
  >
49
50
  {#each Array(count) as _, i}
50
51
  {@const angle = (360 / count) * i}
51
52
  {@const delay = direction === "ccw" ? i / count : (count - i) / count}
52
53
  <span
53
- class="bar"
54
+ class="stuic-spinner-bar"
54
55
  style:width="{barWidth}px"
55
56
  style:height="{barHeight}px"
56
57
  style:border-radius="{rounded}px"
@@ -60,28 +61,3 @@
60
61
  ></span>
61
62
  {/each}
62
63
  </div>
63
-
64
- <style>
65
- .spinner {
66
- position: relative;
67
- width: var(--size);
68
- height: var(--size);
69
- }
70
-
71
- .bar {
72
- position: absolute;
73
- left: 50%;
74
- top: 0px;
75
- background: currentColor;
76
- animation: fade var(--duration) linear infinite;
77
- }
78
-
79
- @keyframes fade {
80
- from {
81
- opacity: 1;
82
- }
83
- to {
84
- opacity: 0.12;
85
- }
86
- }
87
- </style>
@@ -1,8 +1,9 @@
1
1
  export interface Props {
2
2
  class?: string;
3
+ style?: string;
3
4
  count?: number;
4
5
  thickness?: "thin" | "normal" | "thick";
5
- height?: "short" | "normal" | "tall";
6
+ size?: "sm" | "md" | "lg";
6
7
  direction?: "cw" | "ccw";
7
8
  rounded?: number;
8
9
  duration?: number;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" module>
2
2
  export interface Props {
3
3
  class?: string;
4
+ style?: string;
4
5
  /** One "loop" duration in ms */
5
6
  duration?: number;
6
7
  /** Border thickness preset */
@@ -15,48 +16,19 @@
15
16
 
16
17
  let {
17
18
  class: classProp,
19
+ style: styleProp,
18
20
  duration = 750,
19
21
  thickness = "normal",
20
22
  direction = "cw",
21
23
  }: Props = $props();
22
24
 
23
25
  let _thickness = $derived(
24
- "thickness-" +
25
- (["normal", "thin", "thick"].includes(thickness) ? thickness : "normal")
26
+ ["normal", "thin", "thick"].includes(thickness) ? thickness : "normal"
26
27
  );
27
28
  </script>
28
29
 
29
30
  <span
30
- class={twMerge("stuic-spinner-basic inline-block size-5", _thickness, classProp)}
31
- style="animation-duration: {duration}ms; animation-direction: {direction === 'ccw'
32
- ? 'reverse'
33
- : 'normal'};"
31
+ class={twMerge("stuic-spinner-circle size-4", classProp)}
32
+ data-thickness={_thickness}
33
+ style="{styleProp ?? ''}; --stuic-spinner-circle-duration: {duration}ms; animation-direction: {direction === 'ccw' ? 'reverse' : 'normal'};"
34
34
  ></span>
35
-
36
- <style>
37
- .stuic-spinner-basic {
38
- box-sizing: border-box;
39
- border-radius: 50%;
40
- border-style: solid;
41
- border-color: currentColor;
42
- border-top-color: transparent;
43
- animation: spin linear infinite;
44
- }
45
-
46
- /* Thickness presets */
47
- .stuic-spinner-basic.thickness-thin {
48
- border-width: 1px;
49
- }
50
- .stuic-spinner-basic.thickness-normal {
51
- border-width: 2px;
52
- }
53
- .stuic-spinner-basic.thickness-thick {
54
- border-width: 4px;
55
- }
56
-
57
- @keyframes spin {
58
- to {
59
- transform: rotate(360deg);
60
- }
61
- }
62
- </style>
@@ -1,5 +1,6 @@
1
1
  export interface Props {
2
2
  class?: string;
3
+ style?: string;
3
4
  /** One "loop" duration in ms */
4
5
  duration?: number;
5
6
  /** Border thickness preset */
@@ -17,12 +17,17 @@
17
17
 
18
18
  let {
19
19
  class: classProp = "",
20
- bgStrokeColor = "rgba(0 0 0 / .1)",
20
+ bgStrokeColor,
21
21
  strokeWidth,
22
22
  noOscillate,
23
- rotateDuration = ".75s",
23
+ rotateDuration,
24
24
  }: Props = $props();
25
25
 
26
+ // Use CSS variable as default when bgStrokeColor is not provided
27
+ const _bgStrokeColor = $derived(
28
+ bgStrokeColor ?? "var(--stuic-spinner-circle-oscillate-bg-stroke)"
29
+ );
30
+
26
31
  /**
27
32
  * NOTE: we happen to have 4 distinct values here which effect the overall look and feel...
28
33
  * 1. the tick frequency
@@ -40,8 +45,8 @@
40
45
  <Circle
41
46
  animateCompletenessMs={0}
42
47
  {completeness}
43
- class={twMerge("stuic-spinner-circle animate-spin", classProp)}
44
- {bgStrokeColor}
48
+ class={twMerge("stuic-spinner-circle-oscillate", classProp)}
49
+ bgStrokeColor={_bgStrokeColor}
45
50
  {strokeWidth}
46
- style="animation-duration: {rotateDuration}"
51
+ style={rotateDuration ? `--stuic-spinner-circle-oscillate-duration: ${rotateDuration}` : undefined}
47
52
  />
@@ -20,6 +20,7 @@
20
20
 
21
21
  export interface Props {
22
22
  class?: string;
23
+ style?: string;
23
24
  speed?: number;
24
25
  variant?: SpinnerUnicodeVariant;
25
26
  reversed?: boolean;
@@ -68,6 +69,7 @@
68
69
 
69
70
  let {
70
71
  class: _class = "",
72
+ style: _style,
71
73
  speed = 100,
72
74
  variant = "braille_bar_dot",
73
75
  reversed = false,
@@ -152,6 +154,6 @@
152
154
  });
153
155
  </script>
154
156
 
155
- <span class={twMerge(`inline-block font-mono leading-none text-current text-xl`, _class)}>
157
+ <span class={twMerge("stuic-spinner-unicode", _class)} style={_style}>
156
158
  {_frames[currentFrame]}
157
159
  </span>
@@ -1,6 +1,7 @@
1
1
  export type SpinnerUnicodeVariant = "braille_bar" | "braille_bar_dot" | "braille_dot_circle" | "braille_dot_bounce" | "half_circle" | "quarter_circle" | "ascii" | "bar_v" | "bar_h" | "shade" | "arrows" | "arrows2" | "asterix" | "asterix2" | "asterix3" | "asterix4" | "asterix5";
2
2
  export interface Props {
3
3
  class?: string;
4
+ style?: string;
4
5
  speed?: number;
5
6
  variant?: SpinnerUnicodeVariant;
6
7
  reversed?: boolean;
@@ -0,0 +1,104 @@
1
+ :root {
2
+ /* Spinner (radial bars) */
3
+ --stuic-spinner-opacity: 0.8;
4
+ --stuic-spinner-fade-end-opacity: 0.12;
5
+ --stuic-spinner-duration: 750ms;
6
+
7
+ /* SpinnerCircle */
8
+ --stuic-spinner-circle-thickness-thin: 1px;
9
+ --stuic-spinner-circle-thickness-normal: 2px;
10
+ --stuic-spinner-circle-thickness-thick: 4px;
11
+ --stuic-spinner-circle-duration: 750ms;
12
+
13
+ /* SpinnerCircleOscillate */
14
+ --stuic-spinner-circle-oscillate-bg-stroke: var(
15
+ --stuic-color-border,
16
+ rgba(0 0 0 / 0.1)
17
+ );
18
+ --stuic-spinner-circle-oscillate-duration: 0.75s;
19
+
20
+ /* SpinnerUnicode */
21
+ --stuic-spinner-unicode-font-size: var(--text-xl);
22
+ }
23
+
24
+ @layer components {
25
+ /* ========================================================================
26
+ Spinner (radial bars)
27
+ ======================================================================== */
28
+
29
+ .stuic-spinner {
30
+ position: relative;
31
+ opacity: var(--stuic-spinner-opacity);
32
+ }
33
+
34
+ .stuic-spinner-bar {
35
+ position: absolute;
36
+ left: 50%;
37
+ top: 0;
38
+ background: currentColor;
39
+ animation: stuic-spinner-fade var(--stuic-spinner-duration) linear infinite;
40
+ }
41
+
42
+ @keyframes stuic-spinner-fade {
43
+ from {
44
+ opacity: 1;
45
+ }
46
+ to {
47
+ opacity: var(--stuic-spinner-fade-end-opacity);
48
+ }
49
+ }
50
+
51
+ /* ========================================================================
52
+ SpinnerCircle
53
+ ======================================================================== */
54
+
55
+ .stuic-spinner-circle {
56
+ display: inline-block;
57
+ box-sizing: border-box;
58
+ border-radius: 50%;
59
+ border-style: solid;
60
+ border-color: currentColor;
61
+ border-top-color: transparent;
62
+ animation: stuic-spinner-circle-spin linear infinite;
63
+ animation-duration: var(--stuic-spinner-circle-duration);
64
+ }
65
+
66
+ .stuic-spinner-circle[data-thickness="thin"] {
67
+ border-width: var(--stuic-spinner-circle-thickness-thin);
68
+ }
69
+
70
+ .stuic-spinner-circle[data-thickness="normal"] {
71
+ border-width: var(--stuic-spinner-circle-thickness-normal);
72
+ }
73
+
74
+ .stuic-spinner-circle[data-thickness="thick"] {
75
+ border-width: var(--stuic-spinner-circle-thickness-thick);
76
+ }
77
+
78
+ @keyframes stuic-spinner-circle-spin {
79
+ to {
80
+ transform: rotate(360deg);
81
+ }
82
+ }
83
+
84
+ /* ========================================================================
85
+ SpinnerCircleOscillate
86
+ ======================================================================== */
87
+
88
+ .stuic-spinner-circle-oscillate {
89
+ animation: stuic-spinner-circle-spin linear infinite;
90
+ animation-duration: var(--stuic-spinner-circle-oscillate-duration);
91
+ }
92
+
93
+ /* ========================================================================
94
+ SpinnerUnicode
95
+ ======================================================================== */
96
+
97
+ .stuic-spinner-unicode {
98
+ display: inline-block;
99
+ font-family: var(--font-mono);
100
+ line-height: 1;
101
+ color: currentColor;
102
+ font-size: var(--stuic-spinner-unicode-font-size);
103
+ }
104
+ }