@sabrenski/spire-ui-vue 0.2.0 → 0.2.2

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.
package/README.md CHANGED
@@ -20,12 +20,29 @@ npm install vue@^3.0.0
20
20
 
21
21
  ## Quick Start
22
22
 
23
+ ### 1. CSS Setup (Required)
24
+
25
+ Spire UI uses Tailwind CSS v4's `@theme` directive for theming. Add these imports to your main CSS file:
26
+
27
+ ```css
28
+ /* app.css */
29
+ @import "@sabrenski/spire-ui-vue/theme.css";
30
+ @import "tailwindcss";
31
+
32
+ /* Required: Tell Tailwind to scan component files for utility classes */
33
+ @source "../node_modules/@sabrenski/spire-ui-vue/dist/**/*.js";
34
+ ```
35
+
36
+ - **theme.css** - Must be imported **before** `tailwindcss` so Tailwind processes the theme tokens
37
+ - **@source** - Required for Tailwind to discover which utility classes the components use
38
+
39
+ ### 2. Vue Plugin Setup
40
+
23
41
  ```ts
24
42
  // main.ts
25
43
  import { createApp } from 'vue'
26
44
  import { SpireUI } from '@sabrenski/spire-ui-vue'
27
45
  import App from './App.vue'
28
- import '@sabrenski/spire-ui-vue/style.css'
29
46
 
30
47
  const app = createApp(App)
31
48
 
@@ -335,6 +352,34 @@ function showToast() {
335
352
 
336
353
  ## Theming
337
354
 
355
+ ### CSS Imports
356
+
357
+ Spire UI provides two CSS exports:
358
+
359
+ | Import | Purpose |
360
+ |--------|---------|
361
+ | `@sabrenski/spire-ui-vue/theme.css` | Raw `@theme` tokens for Tailwind v4 to process |
362
+ | `@sabrenski/spire-ui-vue/style.css` | Pre-built component styles (optional) |
363
+
364
+ For Tailwind v4 projects:
365
+
366
+ ```css
367
+ /* app.css */
368
+ @import "@sabrenski/spire-ui-vue/theme.css";
369
+ @import "tailwindcss";
370
+
371
+ /* Required: Scan component files for utility classes */
372
+ @source "../node_modules/@sabrenski/spire-ui-vue/dist/**/*.js";
373
+ ```
374
+
375
+ You can also import individual theme files:
376
+
377
+ ```css
378
+ @import "@sabrenski/spire-ui-vue/theme/base.css"; /* Color palette */
379
+ @import "@sabrenski/spire-ui-vue/theme/semantic.css"; /* Semantic tokens + dark mode */
380
+ @import "@sabrenski/spire-ui-vue/theme/components.css"; /* Component-specific tokens */
381
+ ```
382
+
338
383
  ### Dark Mode
339
384
 
340
385
  Add the `dark` class to `<html>` or any parent element:
@@ -347,17 +392,29 @@ Add the `dark` class to `<html>` or any parent element:
347
392
 
348
393
  - **Light** (default)
349
394
  - **Dark** (`class="dark"`)
350
- - **Ocean** (`class="dark ocean"`)
395
+ - **Ocean** (`class="ocean"`)
351
396
  - **Forest** (`class="forest"`)
397
+ - **Sunset** (`class="sunset"`)
398
+ - **Rose** (`class="rose"`)
399
+ - **Midnight** (`class="midnight"`)
352
400
 
353
- ### CSS Variables
401
+ ### Customizing Colors
402
+
403
+ Override the base color variables to customize the entire palette:
404
+
405
+ ```css
406
+ :root {
407
+ --color-primary-base: oklch(55% 0.2 250); /* Blue primary */
408
+ --color-danger-base: oklch(55% 0.22 27);
409
+ }
410
+ ```
354
411
 
355
- Override CSS custom properties to customize the theme:
412
+ Or override individual semantic tokens:
356
413
 
357
414
  ```css
358
415
  :root {
359
416
  --color-primary: oklch(0.6 0.2 250);
360
- --color-danger: oklch(0.6 0.2 25);
417
+ --color-primary-hover: oklch(0.55 0.2 250);
361
418
  }
362
419
  ```
363
420
 
@@ -0,0 +1,423 @@
1
+ /**
2
+ * Global Intelligent Position Fallbacks for CSS Anchor Positioning
3
+ *
4
+ * Usage: Add data-placement="bottom-start" (or any placement) to any anchor-positioned element
5
+ *
6
+ * Applies to: Dropdown, Popover, Tooltip, Combobox, Select, and any future anchor-positioned components
7
+ *
8
+ * Each placement has a priority-ordered fallback sequence:
9
+ * 1. Flip on primary axis (maintain alignment)
10
+ * 2. Try adjacent placements (maintain axis when possible)
11
+ * 3. Flip to perpendicular axis (last resort)
12
+ */
13
+
14
+ /* Reset default popover positioning */
15
+ [popover] {
16
+ position: absolute;
17
+ inset: unset;
18
+ margin: 0;
19
+ overflow: visible;
20
+ }
21
+
22
+ /* Match trigger width - use on dropdown menus that should match their trigger's width */
23
+ [data-spire-same-width] {
24
+ min-width: anchor-size(width);
25
+ }
26
+
27
+ /* Fixed strategy for anchors in fixed containers */
28
+ [popover][data-spire-strategy="fixed"] {
29
+ position: fixed;
30
+ }
31
+
32
+ /* Bottom placements */
33
+ @position-try --fallback-bottom-start-1 {
34
+ inset: auto;
35
+ margin-bottom: 8px;
36
+ bottom: anchor(top);
37
+ left: anchor(left);
38
+ }
39
+
40
+ @position-try --fallback-bottom-start-2 {
41
+ inset: auto;
42
+ margin-left: 4px;
43
+ left: anchor(right);
44
+ top: anchor(top);
45
+ }
46
+
47
+ @position-try --fallback-bottom-start-3 {
48
+ inset: auto;
49
+ margin-right: 4px;
50
+ right: anchor(left);
51
+ top: anchor(top);
52
+ }
53
+
54
+ @position-try --fallback-bottom-end-1 {
55
+ inset: auto;
56
+ margin-bottom: 8px;
57
+ bottom: anchor(top);
58
+ right: anchor(right);
59
+ }
60
+
61
+ @position-try --fallback-bottom-end-2 {
62
+ inset: auto;
63
+ margin-right: 4px;
64
+ right: anchor(left);
65
+ top: anchor(top);
66
+ }
67
+
68
+ @position-try --fallback-bottom-end-3 {
69
+ inset: auto;
70
+ margin-left: 4px;
71
+ left: anchor(right);
72
+ top: anchor(top);
73
+ }
74
+
75
+ @position-try --fallback-bottom-1 {
76
+ inset: auto;
77
+ margin-bottom: 8px;
78
+ bottom: anchor(top);
79
+ left: anchor(left);
80
+ }
81
+
82
+ @position-try --fallback-bottom-2 {
83
+ inset: auto;
84
+ margin-left: 4px;
85
+ left: anchor(right);
86
+ top: anchor(top);
87
+ }
88
+
89
+ @position-try --fallback-bottom-3 {
90
+ inset: auto;
91
+ margin-right: 4px;
92
+ right: anchor(left);
93
+ top: anchor(top);
94
+ }
95
+
96
+ /* Top placements */
97
+ @position-try --fallback-top-start-1 {
98
+ inset: auto;
99
+ margin-top: 8px;
100
+ top: anchor(bottom);
101
+ left: anchor(left);
102
+ }
103
+
104
+ @position-try --fallback-top-start-2 {
105
+ inset: auto;
106
+ margin-left: 4px;
107
+ left: anchor(right);
108
+ top: anchor(top);
109
+ }
110
+
111
+ @position-try --fallback-top-start-3 {
112
+ inset: auto;
113
+ margin-right: 4px;
114
+ right: anchor(left);
115
+ top: anchor(top);
116
+ }
117
+
118
+ @position-try --fallback-top-end-1 {
119
+ inset: auto;
120
+ margin-top: 8px;
121
+ top: anchor(bottom);
122
+ right: anchor(right);
123
+ }
124
+
125
+ @position-try --fallback-top-end-2 {
126
+ inset: auto;
127
+ margin-right: 4px;
128
+ right: anchor(left);
129
+ top: anchor(top);
130
+ }
131
+
132
+ @position-try --fallback-top-end-3 {
133
+ inset: auto;
134
+ margin-left: 4px;
135
+ left: anchor(right);
136
+ top: anchor(top);
137
+ }
138
+
139
+ @position-try --fallback-top-1 {
140
+ inset: auto;
141
+ margin-top: 8px;
142
+ top: anchor(bottom);
143
+ left: anchor(left);
144
+ }
145
+
146
+ @position-try --fallback-top-2 {
147
+ inset: auto;
148
+ margin-left: 4px;
149
+ left: anchor(right);
150
+ top: anchor(top);
151
+ }
152
+
153
+ @position-try --fallback-top-3 {
154
+ inset: auto;
155
+ margin-right: 4px;
156
+ right: anchor(left);
157
+ top: anchor(top);
158
+ }
159
+
160
+ /* Right placements */
161
+ @position-try --fallback-right-start-1 {
162
+ inset: auto;
163
+ margin-right: 4px;
164
+ right: anchor(left);
165
+ top: anchor(top);
166
+ }
167
+
168
+ @position-try --fallback-right-start-2 {
169
+ inset: auto;
170
+ margin-top: 8px;
171
+ top: anchor(bottom);
172
+ left: anchor(left);
173
+ }
174
+
175
+ @position-try --fallback-right-start-3 {
176
+ inset: auto;
177
+ margin-bottom: 8px;
178
+ bottom: anchor(top);
179
+ left: anchor(left);
180
+ }
181
+
182
+ @position-try --fallback-right-end-1 {
183
+ inset: auto;
184
+ margin-right: 4px;
185
+ right: anchor(left);
186
+ bottom: anchor(bottom);
187
+ }
188
+
189
+ @position-try --fallback-right-end-2 {
190
+ inset: auto;
191
+ margin-bottom: 8px;
192
+ bottom: anchor(top);
193
+ left: anchor(left);
194
+ }
195
+
196
+ @position-try --fallback-right-end-3 {
197
+ inset: auto;
198
+ margin-top: 8px;
199
+ top: anchor(bottom);
200
+ left: anchor(left);
201
+ }
202
+
203
+ @position-try --fallback-right-1 {
204
+ inset: auto;
205
+ margin-right: 4px;
206
+ right: anchor(left);
207
+ top: anchor(top);
208
+ }
209
+
210
+ @position-try --fallback-right-2 {
211
+ inset: auto;
212
+ margin-top: 8px;
213
+ top: anchor(bottom);
214
+ left: anchor(left);
215
+ }
216
+
217
+ @position-try --fallback-right-3 {
218
+ inset: auto;
219
+ margin-bottom: 8px;
220
+ bottom: anchor(top);
221
+ left: anchor(left);
222
+ }
223
+
224
+ /* Left placements */
225
+ @position-try --fallback-left-start-1 {
226
+ inset: auto;
227
+ margin-left: 4px;
228
+ left: anchor(right);
229
+ top: anchor(top);
230
+ }
231
+
232
+ @position-try --fallback-left-start-2 {
233
+ inset: auto;
234
+ margin-top: 8px;
235
+ top: anchor(bottom);
236
+ right: anchor(right);
237
+ }
238
+
239
+ @position-try --fallback-left-start-3 {
240
+ inset: auto;
241
+ margin-bottom: 8px;
242
+ bottom: anchor(top);
243
+ right: anchor(right);
244
+ }
245
+
246
+ @position-try --fallback-left-end-1 {
247
+ inset: auto;
248
+ margin-left: 4px;
249
+ left: anchor(right);
250
+ bottom: anchor(bottom);
251
+ }
252
+
253
+ @position-try --fallback-left-end-2 {
254
+ inset: auto;
255
+ margin-bottom: 8px;
256
+ bottom: anchor(top);
257
+ right: anchor(right);
258
+ }
259
+
260
+ @position-try --fallback-left-end-3 {
261
+ inset: auto;
262
+ margin-top: 8px;
263
+ top: anchor(bottom);
264
+ right: anchor(right);
265
+ }
266
+
267
+ @position-try --fallback-left-1 {
268
+ inset: auto;
269
+ margin-left: 4px;
270
+ left: anchor(right);
271
+ top: anchor(top);
272
+ }
273
+
274
+ @position-try --fallback-left-2 {
275
+ inset: auto;
276
+ margin-top: 8px;
277
+ top: anchor(bottom);
278
+ right: anchor(right);
279
+ }
280
+
281
+ @position-try --fallback-left-3 {
282
+ inset: auto;
283
+ margin-bottom: 8px;
284
+ bottom: anchor(top);
285
+ right: anchor(right);
286
+ }
287
+
288
+ /* Apply fallbacks to elements with data-spire-placement */
289
+ [data-spire-placement="bottom-start"] {
290
+ inset: auto;
291
+ margin-top: 8px;
292
+ top: anchor(bottom);
293
+ left: anchor(left);
294
+ position-try-fallbacks:
295
+ --fallback-bottom-start-1,
296
+ --fallback-bottom-start-2,
297
+ --fallback-bottom-start-3;
298
+ }
299
+
300
+ [data-spire-placement="bottom-end"] {
301
+ inset: auto;
302
+ margin-top: 8px;
303
+ top: anchor(bottom);
304
+ right: anchor(right);
305
+ position-try-fallbacks:
306
+ --fallback-bottom-end-1,
307
+ --fallback-bottom-end-2,
308
+ --fallback-bottom-end-3;
309
+ }
310
+
311
+ [data-spire-placement="bottom"] {
312
+ inset: auto;
313
+ margin-top: 8px;
314
+ top: anchor(bottom);
315
+ left: calc(anchor(left) + (anchor-size(width) / 2));
316
+ translate: -50% 0;
317
+ position-try-fallbacks:
318
+ --fallback-bottom-1,
319
+ --fallback-bottom-2,
320
+ --fallback-bottom-3;
321
+ }
322
+
323
+ [data-spire-placement="top-start"] {
324
+ inset: auto;
325
+ margin-bottom: 8px;
326
+ bottom: anchor(top);
327
+ left: anchor(left);
328
+ position-try-fallbacks:
329
+ --fallback-top-start-1,
330
+ --fallback-top-start-2,
331
+ --fallback-top-start-3;
332
+ }
333
+
334
+ [data-spire-placement="top-end"] {
335
+ inset: auto;
336
+ margin-bottom: 8px;
337
+ bottom: anchor(top);
338
+ right: anchor(right);
339
+ position-try-fallbacks:
340
+ --fallback-top-end-1,
341
+ --fallback-top-end-2,
342
+ --fallback-top-end-3;
343
+ }
344
+
345
+ [data-spire-placement="top"] {
346
+ inset: auto;
347
+ margin-bottom: 8px;
348
+ bottom: anchor(top);
349
+ left: calc(anchor(left) + (anchor-size(width) / 2));
350
+ translate: -50% 0;
351
+ position-try-fallbacks:
352
+ --fallback-top-1,
353
+ --fallback-top-2,
354
+ --fallback-top-3;
355
+ }
356
+
357
+ [data-spire-placement="right-start"] {
358
+ inset: auto;
359
+ margin-left: 4px;
360
+ left: anchor(right);
361
+ top: anchor(top);
362
+ position-try-fallbacks:
363
+ --fallback-right-start-1,
364
+ --fallback-right-start-2,
365
+ --fallback-right-start-3;
366
+ }
367
+
368
+ [data-spire-placement="right-end"] {
369
+ inset: auto;
370
+ margin-left: 4px;
371
+ left: anchor(right);
372
+ bottom: anchor(bottom);
373
+ position-try-fallbacks:
374
+ --fallback-right-end-1,
375
+ --fallback-right-end-2,
376
+ --fallback-right-end-3;
377
+ }
378
+
379
+ [data-spire-placement="right"] {
380
+ inset: auto;
381
+ margin-left: 4px;
382
+ left: anchor(right);
383
+ top: calc(anchor(top) + (anchor-size(height) / 2));
384
+ translate: 0 -50%;
385
+ position-try-fallbacks:
386
+ --fallback-right-1,
387
+ --fallback-right-2,
388
+ --fallback-right-3;
389
+ }
390
+
391
+ [data-spire-placement="left-start"] {
392
+ inset: auto;
393
+ margin-right: 4px;
394
+ right: anchor(left);
395
+ top: anchor(top);
396
+ position-try-fallbacks:
397
+ --fallback-left-start-1,
398
+ --fallback-left-start-2,
399
+ --fallback-left-start-3;
400
+ }
401
+
402
+ [data-spire-placement="left-end"] {
403
+ inset: auto;
404
+ margin-right: 4px;
405
+ right: anchor(left);
406
+ bottom: anchor(bottom);
407
+ position-try-fallbacks:
408
+ --fallback-left-end-1,
409
+ --fallback-left-end-2,
410
+ --fallback-left-end-3;
411
+ }
412
+
413
+ [data-spire-placement="left"] {
414
+ inset: auto;
415
+ margin-right: 4px;
416
+ right: anchor(left);
417
+ top: calc(anchor(top) + (anchor-size(height) / 2));
418
+ translate: 0 -50%;
419
+ position-try-fallbacks:
420
+ --fallback-left-1,
421
+ --fallback-left-2,
422
+ --fallback-left-3;
423
+ }
@@ -0,0 +1,93 @@
1
+ :root {
2
+ --color-primary-base: oklch(55% 0.1632 318.71);
3
+ --color-secondary-base: oklch(55% 0.18 285);
4
+ --color-success-base: oklch(55% 0.19 145);
5
+ --color-danger-base: oklch(55% 0.22 27);
6
+ --color-warning-base: oklch(70% 0.17 70);
7
+ --color-neutral-base: oklch(50% 0.02 60);
8
+ }
9
+
10
+
11
+ @theme {
12
+ --color-primary-50: oklch(from var(--color-primary-base) 97% calc(c * 0.1) h);
13
+ --color-primary-100: oklch(from var(--color-primary-base) 94% calc(c * 0.15) h);
14
+ --color-primary-200: oklch(from var(--color-primary-base) 86% calc(c * 0.25) h);
15
+ --color-primary-300: oklch(from var(--color-primary-base) 76% calc(c * 0.4) h);
16
+ --color-primary-400: oklch(from var(--color-primary-base) 65% calc(c * 0.7) h);
17
+ --color-primary-500: oklch(from var(--color-primary-base) l c h);
18
+ --color-primary-600: oklch(from var(--color-primary-base) 47% calc(c * 0.95) h);
19
+ --color-primary-700: oklch(from var(--color-primary-base) 39% calc(c * 0.85) h);
20
+ --color-primary-800: oklch(from var(--color-primary-base) 31% calc(c * 0.7) h);
21
+ --color-primary-900: oklch(from var(--color-primary-base) 23% calc(c * 0.55) h);
22
+ --color-primary-950: oklch(from var(--color-primary-base) 14% calc(c * 0.4) h);
23
+
24
+ --color-secondary-50: oklch(from var(--color-secondary-base) 97% calc(c * 0.1) h);
25
+ --color-secondary-100: oklch(from var(--color-secondary-base) 94% calc(c * 0.15) h);
26
+ --color-secondary-200: oklch(from var(--color-secondary-base) 86% calc(c * 0.25) h);
27
+ --color-secondary-300: oklch(from var(--color-secondary-base) 76% calc(c * 0.4) h);
28
+ --color-secondary-400: oklch(from var(--color-secondary-base) 65% calc(c * 0.7) h);
29
+ --color-secondary-500: oklch(from var(--color-secondary-base) l c h);
30
+ --color-secondary-600: oklch(from var(--color-secondary-base) 47% calc(c * 0.95) h);
31
+ --color-secondary-700: oklch(from var(--color-secondary-base) 39% calc(c * 0.85) h);
32
+ --color-secondary-800: oklch(from var(--color-secondary-base) 31% calc(c * 0.7) h);
33
+ --color-secondary-900: oklch(from var(--color-secondary-base) 23% calc(c * 0.55) h);
34
+ --color-secondary-950: oklch(from var(--color-secondary-base) 14% calc(c * 0.4) h);
35
+
36
+ --color-success-50: oklch(from var(--color-success-base) 97% calc(c * 0.1) h);
37
+ --color-success-100: oklch(from var(--color-success-base) 94% calc(c * 0.15) h);
38
+ --color-success-200: oklch(from var(--color-success-base) 86% calc(c * 0.25) h);
39
+ --color-success-300: oklch(from var(--color-success-base) 76% calc(c * 0.4) h);
40
+ --color-success-400: oklch(from var(--color-success-base) 65% calc(c * 0.7) h);
41
+ --color-success-500: oklch(from var(--color-success-base) l c h);
42
+ --color-success-600: oklch(from var(--color-success-base) 47% calc(c * 0.95) h);
43
+ --color-success-700: oklch(from var(--color-success-base) 39% calc(c * 0.85) h);
44
+ --color-success-800: oklch(from var(--color-success-base) 31% calc(c * 0.7) h);
45
+ --color-success-900: oklch(from var(--color-success-base) 23% calc(c * 0.55) h);
46
+ --color-success-950: oklch(from var(--color-success-base) 14% calc(c * 0.4) h);
47
+
48
+ --color-danger-50: oklch(from var(--color-danger-base) 97% calc(c * 0.1) h);
49
+ --color-danger-100: oklch(from var(--color-danger-base) 94% calc(c * 0.15) h);
50
+ --color-danger-200: oklch(from var(--color-danger-base) 86% calc(c * 0.25) h);
51
+ --color-danger-300: oklch(from var(--color-danger-base) 76% calc(c * 0.4) h);
52
+ --color-danger-400: oklch(from var(--color-danger-base) 65% calc(c * 0.7) h);
53
+ --color-danger-500: oklch(from var(--color-danger-base) l c h);
54
+ --color-danger-600: oklch(from var(--color-danger-base) 47% calc(c * 0.95) h);
55
+ --color-danger-700: oklch(from var(--color-danger-base) 39% calc(c * 0.85) h);
56
+ --color-danger-800: oklch(from var(--color-danger-base) 31% calc(c * 0.7) h);
57
+ --color-danger-900: oklch(from var(--color-danger-base) 23% calc(c * 0.55) h);
58
+ --color-danger-950: oklch(from var(--color-danger-base) 14% calc(c * 0.4) h);
59
+
60
+ --color-warning-50: oklch(from var(--color-warning-base) 97% calc(c * 0.1) h);
61
+ --color-warning-100: oklch(from var(--color-warning-base) 94% calc(c * 0.15) h);
62
+ --color-warning-200: oklch(from var(--color-warning-base) 86% calc(c * 0.25) h);
63
+ --color-warning-300: oklch(from var(--color-warning-base) 76% calc(c * 0.4) h);
64
+ --color-warning-400: oklch(from var(--color-warning-base) 65% calc(c * 0.7) h);
65
+ --color-warning-500: oklch(from var(--color-warning-base) l c h);
66
+ --color-warning-600: oklch(from var(--color-warning-base) 47% calc(c * 0.95) h);
67
+ --color-warning-700: oklch(from var(--color-warning-base) 39% calc(c * 0.85) h);
68
+ --color-warning-800: oklch(from var(--color-warning-base) 31% calc(c * 0.7) h);
69
+ --color-warning-900: oklch(from var(--color-warning-base) 23% calc(c * 0.55) h);
70
+ --color-warning-950: oklch(from var(--color-warning-base) 14% calc(c * 0.4) h);
71
+
72
+ --color-neutral-50: oklch(from var(--color-neutral-base) 97% calc(c * 0.1) h);
73
+ --color-neutral-100: oklch(from var(--color-neutral-base) 94% calc(c * 0.15) h);
74
+ --color-neutral-200: oklch(from var(--color-neutral-base) 86% calc(c * 0.25) h);
75
+ --color-neutral-300: oklch(from var(--color-neutral-base) 76% calc(c * 0.4) h);
76
+ --color-neutral-400: oklch(from var(--color-neutral-base) 65% calc(c * 0.7) h);
77
+ --color-neutral-500: oklch(from var(--color-neutral-base) l c h);
78
+ --color-neutral-600: oklch(from var(--color-neutral-base) 47% calc(c * 0.95) h);
79
+ --color-neutral-700: oklch(from var(--color-neutral-base) 39% calc(c * 0.85) h);
80
+ --color-neutral-800: oklch(from var(--color-neutral-base) 31% calc(c * 0.7) h);
81
+ --color-neutral-900: oklch(from var(--color-neutral-base) 23% calc(c * 0.55) h);
82
+ --color-neutral-950: oklch(from var(--color-neutral-base) 14% calc(c * 0.4) h);
83
+
84
+ --radius-base: 0.5rem;
85
+
86
+ --radius-sm: calc(var(--radius-base) - 4px);
87
+ --radius-md: calc(var(--radius-base) - 2px);
88
+ --radius-lg: var(--radius-base);
89
+ --radius-xl: calc(var(--radius-base) + 4px);
90
+
91
+ --inset-shadow-btn: inset 0.5px 2px 0 0 rgb(255 255 255 / 0.15);
92
+ --inset-shadow-btn-active: inset 2px 3px 0 0 rgb(0 0 0 / 0.15);
93
+ }
@@ -0,0 +1,138 @@
1
+ @theme {
2
+ --color-card: var(--color-elevated);
3
+ --radius-card: var(--radius-lg);
4
+
5
+ --color-dialog: var(--color-elevated);
6
+ --color-dialog-overlay: var(--color-overlay);
7
+ --radius-dialog: var(--radius-lg);
8
+
9
+ --color-tooltip: var(--color-neutral-900);
10
+ --color-tooltip-foreground: var(--color-on-emphasis);
11
+ --radius-tooltip: var(--radius-sm);
12
+
13
+ --radius-badge: var(--radius-sm);
14
+
15
+ --radius-button: var(--radius-lg);
16
+
17
+ --color-avatar: var(--color-muted);
18
+
19
+ --color-picker-handle: white;
20
+ --color-picker-handle-border: white;
21
+ }
22
+
23
+ .dark {
24
+ --color-tooltip: var(--color-neutral-100);
25
+ --color-tooltip-foreground: var(--color-neutral-900);
26
+ }
27
+
28
+ [popover] {
29
+ opacity: 0;
30
+ transform: scale(0.95);
31
+ transition:
32
+ opacity 150ms ease-out,
33
+ transform 150ms ease-out,
34
+ overlay 150ms allow-discrete,
35
+ display 150ms allow-discrete;
36
+ }
37
+
38
+ [popover]:popover-open {
39
+ opacity: 1;
40
+ transform: scale(1);
41
+ }
42
+
43
+ @starting-style {
44
+ [popover]:popover-open {
45
+ opacity: 0;
46
+ transform: scale(0.95);
47
+ }
48
+ }
49
+
50
+ @utility scrollbar-thin {
51
+ scrollbar-width: thin;
52
+ scrollbar-color: var(--color-border) transparent;
53
+
54
+ &::-webkit-scrollbar {
55
+ width: 6px;
56
+ height: 6px;
57
+ }
58
+
59
+ &::-webkit-scrollbar-track {
60
+ background: transparent;
61
+ }
62
+
63
+ &::-webkit-scrollbar-thumb {
64
+ background: var(--color-border);
65
+ border-radius: 3px;
66
+ }
67
+
68
+ &::-webkit-scrollbar-thumb:hover {
69
+ background: var(--color-border-hover);
70
+ }
71
+ }
72
+
73
+ @utility appearance-textfield {
74
+ -moz-appearance: textfield;
75
+
76
+ &::-webkit-outer-spin-button,
77
+ &::-webkit-inner-spin-button {
78
+ -webkit-appearance: none;
79
+ margin: 0;
80
+ }
81
+ }
82
+
83
+ @utility empty-state-responsive {
84
+ & [data-spire-empty-state-title] {
85
+ font-size: 0.875rem;
86
+ line-height: 1.25rem;
87
+ }
88
+
89
+ & [data-spire-empty-state-description] {
90
+ font-size: 0.75rem;
91
+ line-height: 1rem;
92
+ }
93
+
94
+ @container (min-width: 300px) {
95
+ & [data-spire-empty-state-title] {
96
+ font-size: 1rem;
97
+ line-height: 1.5rem;
98
+ }
99
+
100
+ & [data-spire-empty-state-description] {
101
+ font-size: 0.875rem;
102
+ line-height: 1.25rem;
103
+ }
104
+ }
105
+
106
+ @container (min-width: 500px) {
107
+ & [data-spire-empty-state-title] {
108
+ font-size: 1.125rem;
109
+ line-height: 1.75rem;
110
+ }
111
+
112
+ & [data-spire-empty-state-description] {
113
+ font-size: 0.875rem;
114
+ line-height: 1.25rem;
115
+ }
116
+ }
117
+ }
118
+
119
+ @utility line-through-animated {
120
+ position: relative;
121
+
122
+ &::after {
123
+ content: '';
124
+ position: absolute;
125
+ left: 0;
126
+ top: 50%;
127
+ width: 100%;
128
+ height: 1px;
129
+ background-color: currentColor;
130
+ transform: scaleX(0);
131
+ transform-origin: left;
132
+ transition: transform 300ms var(--ease-smooth);
133
+ }
134
+
135
+ &[data-checked="true"]::after {
136
+ transform: scaleX(1);
137
+ }
138
+ }
@@ -0,0 +1,399 @@
1
+ @theme {
2
+ --color-canvas: var(--color-neutral-100);
3
+ --color-surface: var(--color-neutral-50);
4
+ --color-surface-hover: var(--color-neutral-100);
5
+ --color-subtle: var(--color-neutral-200);
6
+ --color-muted: var(--color-neutral-300);
7
+ --color-elevated: white;
8
+ --color-overlay: oklch(0% 0 0 / 50%);
9
+ --color-popover: white;
10
+ --color-inset: var(--color-neutral-200);
11
+
12
+ --color-foreground: var(--color-neutral-900);
13
+ --color-foreground-muted: var(--color-neutral-600);
14
+ --color-foreground-subtle: var(--color-neutral-500);
15
+ --color-foreground-disabled: var(--color-neutral-400);
16
+ --color-foreground-inverse: white;
17
+ --color-on-emphasis: white;
18
+
19
+ --color-border: var(--color-neutral-200);
20
+ --color-border-hover: var(--color-neutral-300);
21
+ --color-border-muted: var(--color-neutral-100);
22
+ --color-border-emphasis: var(--color-neutral-400);
23
+
24
+ --color-primary: var(--color-primary-600);
25
+ --color-primary-hover: var(--color-primary-700);
26
+ --color-primary-active: var(--color-primary-800);
27
+ --color-primary-subtle: var(--color-primary-100);
28
+ --color-primary-subtle-hover: var(--color-primary-200);
29
+ --color-primary-outline: var(--color-primary-200);
30
+ --color-primary-outline-hover: var(--color-primary-300);
31
+ --color-primary-foreground: var(--color-primary-600);
32
+ --color-primary-ring: var(--color-primary-400);
33
+
34
+ --color-secondary: var(--color-neutral-100);
35
+ --color-secondary-hover: var(--color-neutral-200);
36
+ --color-secondary-active: var(--color-neutral-300);
37
+ --color-secondary-subtle: var(--color-neutral-100);
38
+ --color-secondary-foreground: var(--color-neutral-700);
39
+
40
+ --color-success: var(--color-success-600);
41
+ --color-success-hover: var(--color-success-700);
42
+ --color-success-active: var(--color-success-800);
43
+ --color-success-subtle: var(--color-success-100);
44
+ --color-success-subtle-hover: var(--color-success-200);
45
+ --color-success-foreground: var(--color-success-600);
46
+ --color-success-ring: var(--color-success-400);
47
+
48
+ --color-danger: var(--color-danger-600);
49
+ --color-danger-hover: var(--color-danger-700);
50
+ --color-danger-active: var(--color-danger-800);
51
+ --color-danger-subtle: var(--color-danger-100);
52
+ --color-danger-subtle-hover: var(--color-danger-200);
53
+ --color-danger-foreground: var(--color-danger-600);
54
+ --color-danger-ring: var(--color-danger-400);
55
+
56
+ --color-warning: var(--color-warning-500);
57
+ --color-warning-hover: var(--color-warning-600);
58
+ --color-warning-active: var(--color-warning-700);
59
+ --color-warning-subtle: var(--color-warning-100);
60
+ --color-warning-subtle-hover: var(--color-warning-200);
61
+ --color-warning-foreground: var(--color-warning-600);
62
+ --color-warning-ring: var(--color-warning-400);
63
+
64
+ --color-info: var(--color-primary-600);
65
+ --color-info-hover: var(--color-primary-700);
66
+ --color-info-active: var(--color-primary-800);
67
+ --color-info-subtle: var(--color-primary-100);
68
+ --color-info-subtle-hover: var(--color-primary-200);
69
+ --color-info-foreground: var(--color-primary-600);
70
+ --color-info-ring: var(--color-primary-400);
71
+
72
+ --color-chart-1: oklch(55% 0.2 250);
73
+ --color-chart-2: oklch(60% 0.2 150);
74
+ --color-chart-3: oklch(65% 0.2 45);
75
+ --color-chart-4: oklch(55% 0.2 320);
76
+ --color-chart-5: oklch(60% 0.18 80);
77
+ --color-chart-6: oklch(55% 0.22 15);
78
+ --color-chart-7: oklch(58% 0.15 200);
79
+ --color-chart-8: oklch(55% 0.18 290);
80
+
81
+ --color-ghost: transparent;
82
+ --color-ghost-hover: var(--color-neutral-100);
83
+ --color-ghost-active: var(--color-neutral-200);
84
+
85
+ --color-contrast: var(--color-neutral-800);
86
+ --color-contrast-hover: var(--color-neutral-900);
87
+ --color-contrast-active: var(--color-neutral-950);
88
+ --color-contrast-foreground: white;
89
+
90
+ --color-outline: transparent;
91
+ --color-outline-hover: var(--color-neutral-50);
92
+ --color-outline-active: var(--color-neutral-100);
93
+
94
+ --color-ring: var(--color-primary-400);
95
+ --color-ring-offset: white;
96
+
97
+ --color-input: white;
98
+ --color-input-disabled: var(--color-neutral-100);
99
+ --color-input-border: var(--color-neutral-300);
100
+ --color-input-border-hover: var(--color-neutral-400);
101
+ --color-input-border-focus: var(--color-primary-500);
102
+ --color-input-border-invalid: var(--color-danger-500);
103
+ --color-input-placeholder: var(--color-neutral-400);
104
+
105
+ --size-control-xs: 1.5rem;
106
+ --size-control-sm: 2rem;
107
+ --size-control-md: 2.5rem;
108
+ --size-control-lg: 3rem;
109
+ --size-control-xl: 3.5rem;
110
+
111
+ --ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
112
+ --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
113
+ --ease-snappy: cubic-bezier(0.2, 0, 0, 1);
114
+
115
+ --animate-fade-in: fade-in 0.2s var(--ease-smooth);
116
+ --animate-fade-out: fade-out 0.2s var(--ease-smooth);
117
+ --animate-scale-in: scale-in 0.2s var(--ease-spring);
118
+ --animate-scale-out: scale-out 0.15s var(--ease-smooth);
119
+ --animate-slide-up: slide-up 0.3s var(--ease-smooth);
120
+ --animate-slide-down: slide-down 0.3s var(--ease-smooth);
121
+ --animate-pulse-soft: pulse-soft 2s var(--ease-smooth) infinite;
122
+
123
+ --animate-toast-slide-in-right: toast-slide-in-right 0.3s var(--ease-spring);
124
+ --animate-toast-slide-in-left: toast-slide-in-left 0.3s var(--ease-spring);
125
+ --animate-toast-slide-in-top: toast-slide-in-top 0.3s var(--ease-spring);
126
+ --animate-toast-slide-in-bottom: toast-slide-in-bottom 0.3s var(--ease-spring);
127
+ --animate-toast-slide-out-right: toast-slide-out-right 0.2s var(--ease-smooth);
128
+ --animate-toast-slide-out-left: toast-slide-out-left 0.2s var(--ease-smooth);
129
+ --animate-toast-slide-out-top: toast-slide-out-top 0.2s var(--ease-smooth);
130
+ --animate-toast-slide-out-bottom: toast-slide-out-bottom 0.2s var(--ease-smooth);
131
+ }
132
+
133
+ @keyframes fade-in {
134
+ from { opacity: 0; }
135
+ to { opacity: 1; }
136
+ }
137
+ @keyframes fade-out {
138
+ from { opacity: 1; }
139
+ to { opacity: 0; }
140
+ }
141
+ @keyframes scale-in {
142
+ from { opacity: 0; transform: scale(0.95); }
143
+ to { opacity: 1; transform: scale(1); }
144
+ }
145
+ @keyframes scale-out {
146
+ from { opacity: 1; transform: scale(1); }
147
+ to { opacity: 0; transform: scale(0.95); }
148
+ }
149
+ @keyframes slide-up {
150
+ from { opacity: 0; transform: translateY(8px); }
151
+ to { opacity: 1; transform: translateY(0); }
152
+ }
153
+ @keyframes slide-down {
154
+ from { opacity: 0; transform: translateY(-8px); }
155
+ to { opacity: 1; transform: translateY(0); }
156
+ }
157
+ @keyframes pulse-soft {
158
+ 0%, 100% { opacity: 1; }
159
+ 50% { opacity: 0.6; }
160
+ }
161
+
162
+ @keyframes toast-slide-in-right {
163
+ from { opacity: 0; transform: translateX(100%); }
164
+ to { opacity: 1; transform: translateX(0); }
165
+ }
166
+ @keyframes toast-slide-in-left {
167
+ from { opacity: 0; transform: translateX(-100%); }
168
+ to { opacity: 1; transform: translateX(0); }
169
+ }
170
+ @keyframes toast-slide-in-top {
171
+ from { opacity: 0; transform: translateY(-100%); }
172
+ to { opacity: 1; transform: translateY(0); }
173
+ }
174
+ @keyframes toast-slide-in-bottom {
175
+ from { opacity: 0; transform: translateY(100%); }
176
+ to { opacity: 1; transform: translateY(0); }
177
+ }
178
+ @keyframes toast-slide-out-right {
179
+ from { opacity: 1; transform: translateX(0); }
180
+ to { opacity: 0; transform: translateX(100%); }
181
+ }
182
+ @keyframes toast-slide-out-left {
183
+ from { opacity: 1; transform: translateX(0); }
184
+ to { opacity: 0; transform: translateX(-100%); }
185
+ }
186
+ @keyframes toast-slide-out-top {
187
+ from { opacity: 1; transform: translateY(0); }
188
+ to { opacity: 0; transform: translateY(-100%); }
189
+ }
190
+ @keyframes toast-slide-out-bottom {
191
+ from { opacity: 1; transform: translateY(0); }
192
+ to { opacity: 0; transform: translateY(100%); }
193
+ }
194
+
195
+ .dark {
196
+ --color-canvas: var(--color-neutral-950);
197
+ --color-surface: var(--color-neutral-900);
198
+ --color-surface-hover: var(--color-neutral-800);
199
+ --color-subtle: var(--color-neutral-800);
200
+ --color-muted: var(--color-neutral-700);
201
+ --color-elevated: var(--color-neutral-800);
202
+ --color-overlay: var(--color-neutral-900);
203
+ --color-popover: var(--color-neutral-900);
204
+ --color-inset: var(--color-neutral-950);
205
+
206
+ --color-foreground: var(--color-neutral-50);
207
+ --color-foreground-muted: var(--color-neutral-400);
208
+ --color-foreground-subtle: var(--color-neutral-500);
209
+ --color-foreground-disabled: var(--color-neutral-600);
210
+ --color-foreground-inverse: var(--color-neutral-950);
211
+
212
+ --color-border: var(--color-neutral-700);
213
+ --color-border-hover: var(--color-neutral-600);
214
+ --color-border-muted: var(--color-neutral-800);
215
+ --color-border-emphasis: var(--color-neutral-500);
216
+
217
+ --color-primary: var(--color-primary-500);
218
+ --color-primary-hover: var(--color-primary-400);
219
+ --color-primary-active: var(--color-primary-300);
220
+ --color-primary-subtle: var(--color-primary-900);
221
+ --color-primary-subtle-hover: var(--color-primary-800);
222
+ --color-primary-outline: var(--color-primary-800);
223
+ --color-primary-outline-hover: var(--color-primary-700);
224
+ --color-primary-foreground: var(--color-primary-400);
225
+ --color-primary-ring: var(--color-primary-500);
226
+
227
+ --color-secondary: var(--color-neutral-800);
228
+ --color-secondary-hover: var(--color-neutral-700);
229
+ --color-secondary-active: var(--color-neutral-600);
230
+ --color-secondary-subtle: var(--color-neutral-800);
231
+ --color-secondary-foreground: var(--color-neutral-300);
232
+
233
+ --color-success: var(--color-success-500);
234
+ --color-success-hover: var(--color-success-400);
235
+ --color-success-active: var(--color-success-300);
236
+ --color-success-subtle: var(--color-success-900);
237
+ --color-success-subtle-hover: var(--color-success-800);
238
+ --color-success-foreground: var(--color-success-400);
239
+ --color-success-ring: var(--color-success-500);
240
+
241
+ --color-danger: var(--color-danger-500);
242
+ --color-danger-hover: var(--color-danger-400);
243
+ --color-danger-active: var(--color-danger-300);
244
+ --color-danger-subtle: var(--color-danger-900);
245
+ --color-danger-subtle-hover: var(--color-danger-800);
246
+ --color-danger-foreground: var(--color-danger-400);
247
+ --color-danger-ring: var(--color-danger-500);
248
+
249
+ --color-warning: var(--color-warning-500);
250
+ --color-warning-hover: var(--color-warning-400);
251
+ --color-warning-active: var(--color-warning-300);
252
+ --color-warning-subtle: var(--color-warning-900);
253
+ --color-warning-subtle-hover: var(--color-warning-800);
254
+ --color-warning-foreground: var(--color-warning-400);
255
+ --color-warning-ring: var(--color-warning-500);
256
+
257
+ --color-info: var(--color-primary-500);
258
+ --color-info-hover: var(--color-primary-400);
259
+ --color-info-active: var(--color-primary-300);
260
+ --color-info-subtle: var(--color-primary-900);
261
+ --color-info-subtle-hover: var(--color-primary-800);
262
+ --color-info-foreground: var(--color-primary-400);
263
+ --color-info-ring: var(--color-primary-500);
264
+
265
+ --color-chart-1: oklch(65% 0.18 250);
266
+ --color-chart-2: oklch(70% 0.18 150);
267
+ --color-chart-3: oklch(72% 0.18 45);
268
+ --color-chart-4: oklch(65% 0.18 320);
269
+ --color-chart-5: oklch(70% 0.16 80);
270
+ --color-chart-6: oklch(65% 0.20 15);
271
+ --color-chart-7: oklch(68% 0.14 200);
272
+ --color-chart-8: oklch(65% 0.16 290);
273
+
274
+ --color-ghost-hover: var(--color-neutral-700);
275
+ --color-ghost-active: var(--color-neutral-600);
276
+
277
+ --color-contrast: var(--color-neutral-100);
278
+ --color-contrast-hover: var(--color-neutral-200);
279
+ --color-contrast-active: var(--color-neutral-300);
280
+ --color-contrast-foreground: var(--color-neutral-900);
281
+
282
+ --color-outline-hover: var(--color-neutral-800);
283
+ --color-outline-active: var(--color-neutral-700);
284
+
285
+ --color-ring: var(--color-primary-500);
286
+ --color-ring-offset: var(--color-neutral-900);
287
+
288
+ --color-input: var(--color-neutral-900);
289
+ --color-input-disabled: var(--color-neutral-800);
290
+ --color-input-border: var(--color-neutral-600);
291
+ --color-input-border-hover: var(--color-neutral-500);
292
+ --color-input-border-focus: var(--color-primary-400);
293
+ --color-input-border-invalid: var(--color-danger-400);
294
+ --color-input-placeholder: var(--color-neutral-500);
295
+ }
296
+
297
+ .ocean {
298
+ --color-primary-base: oklch(55% 0.15 195);
299
+ --color-secondary-base: oklch(55% 0.12 230);
300
+ --color-success-base: oklch(55% 0.15 170);
301
+ --color-danger-base: oklch(55% 0.18 15);
302
+ --color-warning-base: oklch(70% 0.14 85);
303
+ --color-neutral-base: oklch(50% 0.02 210);
304
+ }
305
+
306
+ .forest {
307
+ --color-primary-base: oklch(45% 0.12 145);
308
+ --color-secondary-base: oklch(50% 0.08 80);
309
+ --color-success-base: oklch(50% 0.14 145);
310
+ --color-danger-base: oklch(50% 0.16 25);
311
+ --color-warning-base: oklch(65% 0.14 70);
312
+ --color-neutral-base: oklch(45% 0.03 90);
313
+ }
314
+
315
+ .sunset {
316
+ --color-primary-base: oklch(60% 0.18 35);
317
+ --color-secondary-base: oklch(55% 0.15 55);
318
+ --color-success-base: oklch(55% 0.14 160);
319
+ --color-danger-base: oklch(55% 0.20 15);
320
+ --color-warning-base: oklch(70% 0.16 80);
321
+ --color-neutral-base: oklch(50% 0.03 50);
322
+ }
323
+
324
+ .rose {
325
+ --color-primary-base: oklch(60% 0.17 350);
326
+ --color-secondary-base: oklch(55% 0.14 320);
327
+ --color-success-base: oklch(55% 0.15 160);
328
+ --color-danger-base: oklch(55% 0.18 20);
329
+ --color-warning-base: oklch(68% 0.15 65);
330
+ --color-neutral-base: oklch(50% 0.02 350);
331
+ }
332
+
333
+ .midnight {
334
+ --color-primary-base: oklch(50% 0.16 270);
335
+ --color-secondary-base: oklch(55% 0.14 290);
336
+ --color-success-base: oklch(55% 0.15 180);
337
+ --color-danger-base: oklch(55% 0.18 10);
338
+ --color-warning-base: oklch(68% 0.14 80);
339
+ --color-neutral-base: oklch(45% 0.03 270);
340
+ }
341
+
342
+ @utility h-control-xs {
343
+ height: var(--size-control-xs);
344
+ }
345
+ @utility h-control-sm {
346
+ height: var(--size-control-sm);
347
+ }
348
+ @utility h-control-md {
349
+ height: var(--size-control-md);
350
+ }
351
+ @utility h-control-lg {
352
+ height: var(--size-control-lg);
353
+ }
354
+ @utility h-control-xl {
355
+ height: var(--size-control-xl);
356
+ }
357
+
358
+ @utility size-control-xs {
359
+ width: var(--size-control-xs);
360
+ height: var(--size-control-xs);
361
+ }
362
+ @utility size-control-sm {
363
+ width: var(--size-control-sm);
364
+ height: var(--size-control-sm);
365
+ }
366
+ @utility size-control-md {
367
+ width: var(--size-control-md);
368
+ height: var(--size-control-md);
369
+ }
370
+ @utility size-control-lg {
371
+ width: var(--size-control-lg);
372
+ height: var(--size-control-lg);
373
+ }
374
+ @utility size-control-xl {
375
+ width: var(--size-control-xl);
376
+ height: var(--size-control-xl);
377
+ }
378
+
379
+ :root {
380
+ interpolate-size: allow-keywords;
381
+ }
382
+
383
+ [data-spire-accordion-item] {
384
+ overflow: hidden;
385
+ }
386
+
387
+ [data-spire-accordion-item]::details-content {
388
+ block-size: 0;
389
+ transition: block-size 0.3s var(--ease-smooth), content-visibility 0.3s;
390
+ transition-behavior: allow-discrete;
391
+ }
392
+
393
+ [data-spire-accordion-item][open]::details-content {
394
+ block-size: auto;
395
+ }
396
+
397
+ [data-spire-accordion-item][data-spire-no-animation]::details-content {
398
+ transition: none;
399
+ }
package/dist/theme.css ADDED
@@ -0,0 +1,4 @@
1
+ @import './theme/base.css';
2
+ @import './theme/semantic.css';
3
+ @import './theme/components.css';
4
+ @import './theme/anchor-positioning.css';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabrenski/spire-ui-vue",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "A modern, themeable Vue 3 component library with 57+ components, TypeScript support, and Tailwind CSS v4",
5
5
  "type": "module",
6
6
  "author": "Spire UI Contributors",
@@ -36,7 +36,10 @@
36
36
  "import": "./dist/spire-ui.js",
37
37
  "require": "./dist/spire-ui.cjs"
38
38
  },
39
- "./style.css": "./dist/spire-ui.css"
39
+ "./style.css": "./dist/spire-ui.css",
40
+ "./theme.css": "./dist/theme.css",
41
+ "./theme": "./dist/theme.css",
42
+ "./theme/*": "./dist/theme/*"
40
43
  },
41
44
  "files": [
42
45
  "dist"