@spree/dashboard-ui 6.0.0 → 6.0.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spree/dashboard-ui",
3
3
  "license": "MIT",
4
- "version": "6.0.0",
4
+ "version": "6.0.2",
5
5
  "description": "Spree Dashboard design system — shadcn primitives, headless composed components, and design tokens. Source-only package; consumers compile via their own Vite/Tailwind setup.",
6
6
  "author": "Vendo Connect Inc.",
7
7
  "homepage": "https://spreecommerce.org",
@@ -64,8 +64,6 @@
64
64
  "@tanstack/react-hotkeys": "^0.16.0",
65
65
  "@tanstack/react-table": "9.3.1",
66
66
  "@tiptap/core": "3.32.0",
67
- "@tiptap/extension-bubble-menu": "3.32.0",
68
- "@tiptap/extension-floating-menu": "3.32.0",
69
67
  "@tiptap/extension-image": "3.32.0",
70
68
  "@tiptap/extension-link": "3.32.0",
71
69
  "@tiptap/extension-placeholder": "3.32.0",
@@ -75,7 +73,6 @@
75
73
  "@uiw/react-json-view": "1.12.2",
76
74
  "class-variance-authority": "0.7.1",
77
75
  "clsx": "2.1.1",
78
- "cmdk": "1.1.1",
79
76
  "date-fns": "4.4.0",
80
77
  "date-fns-tz": "3.2.0",
81
78
  "flag-icons": "7.6.0",
@@ -83,14 +80,19 @@
83
80
  "react-colorful": "5.8.1",
84
81
  "react-day-picker": "10.0.2",
85
82
  "recharts": "3.10.1",
86
- "shadcn": "4.22.1",
87
83
  "tailwind-merge": "3.7.0",
88
84
  "tw-animate-css": "1.4.0",
89
- "@spree/core": "^6.0.0"
85
+ "@spree/core": "^6.0.2"
90
86
  },
91
87
  "devDependencies": {
88
+ "@tanstack/react-router": "^1.170.45",
92
89
  "@types/react": "^19.2.14",
93
90
  "@types/react-dom": "^19.2.3",
91
+ "i18next": "^26.5.3",
92
+ "react": "^19.3.1",
93
+ "react-dom": "^19.3.1",
94
+ "react-hook-form": "^7.90.0",
95
+ "react-i18next": "^17.1.0",
94
96
  "tailwindcss": "^4.2.4",
95
97
  "typescript": "~7.0.2",
96
98
  "vite": "^8.3.4"
package/src/index.ts CHANGED
@@ -39,6 +39,7 @@ export * from './spree/bulk-price-table'
39
39
  export * from './spree/bulk-variants-table'
40
40
  export * from './spree/calculator-summary'
41
41
  export * from './spree/claim-resolve-dialog'
42
+ export * from './spree/collapsible-card'
42
43
  export * from './spree/color-picker'
43
44
  export * from './spree/confirm-dialog'
44
45
  export * from './spree/copy-to-clipboard-button'
@@ -85,6 +86,7 @@ export * from './spree/row-actions'
85
86
  export * from './spree/row-click-bridge'
86
87
  export * from './spree/search-input'
87
88
  export * from './spree/secret-input'
89
+ export * from './spree/step-icon'
88
90
  export * from './spree/storefront-visible-switch'
89
91
  export * from './spree/tag-list'
90
92
  export * from './spree/tax-identifiers-card'
package/src/shadcn.css ADDED
@@ -0,0 +1,640 @@
1
+ /* Vendored from shadcn@4.22.1 (dist/tailwind.css, MIT) so host apps do not
2
+ * install the shadcn CLI to get these variants and keyframes. */
3
+
4
+ @theme inline {
5
+ @keyframes accordion-down {
6
+ from {
7
+ height: 0;
8
+ }
9
+ to {
10
+ height: var(
11
+ --radix-accordion-content-height,
12
+ var(--accordion-panel-height, auto)
13
+ );
14
+ }
15
+ }
16
+
17
+ @keyframes accordion-up {
18
+ from {
19
+ height: var(
20
+ --radix-accordion-content-height,
21
+ var(--accordion-panel-height, auto)
22
+ );
23
+ }
24
+ to {
25
+ height: 0;
26
+ }
27
+ }
28
+ }
29
+
30
+ /* Custom variants */
31
+ @custom-variant data-open {
32
+ &:where([data-state="open"]),
33
+ &:where([data-open]:not([data-open="false"])) {
34
+ @slot;
35
+ }
36
+ }
37
+
38
+ @custom-variant data-closed {
39
+ &:where([data-state="closed"]),
40
+ &:where([data-closed]:not([data-closed="false"])) {
41
+ @slot;
42
+ }
43
+ }
44
+
45
+ @custom-variant data-checked {
46
+ &:where([data-state="checked"]),
47
+ &:where([data-checked]:not([data-checked="false"])) {
48
+ @slot;
49
+ }
50
+ }
51
+
52
+ @custom-variant data-unchecked {
53
+ &:where([data-state="unchecked"]),
54
+ &:where([data-unchecked]:not([data-unchecked="false"])) {
55
+ @slot;
56
+ }
57
+ }
58
+
59
+ @custom-variant data-selected {
60
+ &:where([data-selected="true"]) {
61
+ @slot;
62
+ }
63
+ }
64
+
65
+ @custom-variant data-disabled {
66
+ &:where([data-disabled="true"]),
67
+ &:where([data-disabled]:not([data-disabled="false"])) {
68
+ @slot;
69
+ }
70
+ }
71
+
72
+ @custom-variant data-active {
73
+ &:where([data-state="active"]),
74
+ &:where([data-active]:not([data-active="false"])) {
75
+ @slot;
76
+ }
77
+ }
78
+
79
+ @custom-variant data-horizontal {
80
+ &:where([data-orientation="horizontal"]) {
81
+ @slot;
82
+ }
83
+ }
84
+
85
+ @custom-variant data-vertical {
86
+ &:where([data-orientation="vertical"]) {
87
+ @slot;
88
+ }
89
+ }
90
+
91
+ @utility no-scrollbar {
92
+ -ms-overflow-style: none;
93
+ scrollbar-width: none;
94
+
95
+ &::-webkit-scrollbar {
96
+ display: none;
97
+ }
98
+ }
99
+
100
+ /* scroll-fade */
101
+ @property --scroll-fade-t {
102
+ syntax: "<length-percentage>";
103
+ inherits: false;
104
+ initial-value: 0px;
105
+ }
106
+ @property --scroll-fade-b {
107
+ syntax: "<length-percentage>";
108
+ inherits: false;
109
+ initial-value: 0px;
110
+ }
111
+ @property --scroll-fade-s {
112
+ syntax: "<length-percentage>";
113
+ inherits: false;
114
+ initial-value: 0px;
115
+ }
116
+ @property --scroll-fade-e {
117
+ syntax: "<length-percentage>";
118
+ inherits: false;
119
+ initial-value: 0px;
120
+ }
121
+ @property --scroll-fade-mask {
122
+ syntax: "*";
123
+ inherits: false;
124
+ }
125
+
126
+ @theme inline {
127
+ @keyframes scroll-fade-reveal-t {
128
+ from {
129
+ --scroll-fade-t: 0px;
130
+ }
131
+ to {
132
+ --scroll-fade-t: var(--_scroll-fade-size-t, var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10))));
133
+ }
134
+ }
135
+ @keyframes scroll-fade-reveal-b {
136
+ from {
137
+ --scroll-fade-b: var(--_scroll-fade-size-b, var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10))));
138
+ }
139
+ to {
140
+ --scroll-fade-b: 0px;
141
+ }
142
+ }
143
+ @keyframes scroll-fade-reveal-s {
144
+ from {
145
+ --scroll-fade-s: 0px;
146
+ }
147
+ to {
148
+ --scroll-fade-s: var(--_scroll-fade-size-s, var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10))));
149
+ }
150
+ }
151
+ @keyframes scroll-fade-reveal-e {
152
+ from {
153
+ --scroll-fade-e: var(--_scroll-fade-size-e, var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10))));
154
+ }
155
+ to {
156
+ --scroll-fade-e: 0px;
157
+ }
158
+ }
159
+ }
160
+
161
+ @utility scroll-fade {
162
+ --_scroll-fade-size-t: var(
163
+ --scroll-fade-t-size,
164
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
165
+ );
166
+ --_scroll-fade-size-b: var(
167
+ --scroll-fade-b-size,
168
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
169
+ );
170
+ --scroll-fade-block: linear-gradient(
171
+ to bottom,
172
+ transparent 0,
173
+ #000 var(--scroll-fade-t, 0px),
174
+ #000 calc(100% - var(--scroll-fade-b, 0px)),
175
+ transparent 100%
176
+ );
177
+ -webkit-mask-image: var(--scroll-fade-mask, var(--scroll-fade-block));
178
+ mask-image: var(--scroll-fade-mask, var(--scroll-fade-block));
179
+ -webkit-mask-composite: source-in;
180
+ mask-composite: intersect;
181
+ -webkit-mask-repeat: no-repeat;
182
+ mask-repeat: no-repeat;
183
+
184
+ @supports (animation-timeline: scroll()) {
185
+ animation:
186
+ scroll-fade-reveal-t 1ms ease-in-out,
187
+ scroll-fade-reveal-b 1ms ease-in-out;
188
+ animation-timeline: scroll(self y), scroll(self y);
189
+ animation-range:
190
+ 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24)),
191
+ calc(100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))) 100%;
192
+ animation-fill-mode: both;
193
+ }
194
+
195
+ @supports not (animation-timeline: scroll()) {
196
+ --scroll-fade-t: var(--_scroll-fade-size-t);
197
+ --scroll-fade-b: var(--_scroll-fade-size-b);
198
+ }
199
+ }
200
+
201
+ @utility scroll-fade-y {
202
+ --_scroll-fade-size-t: var(
203
+ --scroll-fade-t-size,
204
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
205
+ );
206
+ --_scroll-fade-size-b: var(
207
+ --scroll-fade-b-size,
208
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
209
+ );
210
+ --scroll-fade-block: linear-gradient(
211
+ to bottom,
212
+ transparent 0,
213
+ #000 var(--scroll-fade-t, 0px),
214
+ #000 calc(100% - var(--scroll-fade-b, 0px)),
215
+ transparent 100%
216
+ );
217
+ -webkit-mask-image: var(--scroll-fade-mask, var(--scroll-fade-block));
218
+ mask-image: var(--scroll-fade-mask, var(--scroll-fade-block));
219
+ -webkit-mask-composite: source-in;
220
+ mask-composite: intersect;
221
+ -webkit-mask-repeat: no-repeat;
222
+ mask-repeat: no-repeat;
223
+
224
+ @supports (animation-timeline: scroll()) {
225
+ animation:
226
+ scroll-fade-reveal-t 1ms ease-in-out,
227
+ scroll-fade-reveal-b 1ms ease-in-out;
228
+ animation-timeline: scroll(self y), scroll(self y);
229
+ animation-range:
230
+ 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24)),
231
+ calc(100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))) 100%;
232
+ animation-fill-mode: both;
233
+ }
234
+
235
+ @supports not (animation-timeline: scroll()) {
236
+ --scroll-fade-t: var(--_scroll-fade-size-t);
237
+ --scroll-fade-b: var(--_scroll-fade-size-b);
238
+ }
239
+ }
240
+
241
+ @utility scroll-fade-x {
242
+ --_scroll-fade-size-s: var(
243
+ --scroll-fade-s-size,
244
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
245
+ );
246
+ --_scroll-fade-size-e: var(
247
+ --scroll-fade-e-size,
248
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
249
+ );
250
+ --scroll-fade-inline: linear-gradient(
251
+ to right,
252
+ transparent 0,
253
+ #000 var(--scroll-fade-s, 0px),
254
+ #000 calc(100% - var(--scroll-fade-e, 0px)),
255
+ transparent 100%
256
+ );
257
+ &:where([dir="rtl"], [dir="rtl"] *) {
258
+ --scroll-fade-inline: linear-gradient(
259
+ to left,
260
+ transparent 0,
261
+ #000 var(--scroll-fade-s, 0px),
262
+ #000 calc(100% - var(--scroll-fade-e, 0px)),
263
+ transparent 100%
264
+ );
265
+ }
266
+ -webkit-mask-image: var(--scroll-fade-mask, var(--scroll-fade-inline));
267
+ mask-image: var(--scroll-fade-mask, var(--scroll-fade-inline));
268
+ -webkit-mask-composite: source-in;
269
+ mask-composite: intersect;
270
+ -webkit-mask-repeat: no-repeat;
271
+ mask-repeat: no-repeat;
272
+
273
+ @supports (animation-timeline: scroll()) {
274
+ animation:
275
+ scroll-fade-reveal-s 1ms ease-in-out,
276
+ scroll-fade-reveal-e 1ms ease-in-out;
277
+ animation-timeline: scroll(self inline), scroll(self inline);
278
+ animation-range:
279
+ 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24)),
280
+ calc(100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))) 100%;
281
+ animation-fill-mode: both;
282
+ }
283
+
284
+ @supports not (animation-timeline: scroll()) {
285
+ --scroll-fade-s: var(--_scroll-fade-size-s);
286
+ --scroll-fade-e: var(--_scroll-fade-size-e);
287
+ }
288
+ }
289
+
290
+ @utility scroll-fade-t {
291
+ --_scroll-fade-size-t: var(
292
+ --scroll-fade-t-size,
293
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
294
+ );
295
+ --scroll-fade-mask: linear-gradient(
296
+ to bottom,
297
+ transparent 0,
298
+ #000 var(--scroll-fade-t, 0px),
299
+ #000 100%
300
+ );
301
+ -webkit-mask-image: var(--scroll-fade-mask);
302
+ mask-image: var(--scroll-fade-mask);
303
+ -webkit-mask-composite: source-in;
304
+ mask-composite: intersect;
305
+ -webkit-mask-repeat: no-repeat;
306
+ mask-repeat: no-repeat;
307
+
308
+ @supports (animation-timeline: scroll()) {
309
+ animation: scroll-fade-reveal-t 1ms ease-in-out;
310
+ animation-timeline: scroll(self y);
311
+ animation-range: 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24));
312
+ animation-fill-mode: both;
313
+ }
314
+
315
+ @supports not (animation-timeline: scroll()) {
316
+ --scroll-fade-t: var(--_scroll-fade-size-t);
317
+ }
318
+ }
319
+
320
+ @utility scroll-fade-b {
321
+ --_scroll-fade-size-b: var(
322
+ --scroll-fade-b-size,
323
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
324
+ );
325
+ --scroll-fade-mask: linear-gradient(
326
+ to bottom,
327
+ #000 0,
328
+ #000 calc(100% - var(--scroll-fade-b, 0px)),
329
+ transparent 100%
330
+ );
331
+ -webkit-mask-image: var(--scroll-fade-mask);
332
+ mask-image: var(--scroll-fade-mask);
333
+ -webkit-mask-composite: source-in;
334
+ mask-composite: intersect;
335
+ -webkit-mask-repeat: no-repeat;
336
+ mask-repeat: no-repeat;
337
+
338
+ @supports (animation-timeline: scroll()) {
339
+ animation: scroll-fade-reveal-b 1ms ease-in-out;
340
+ animation-timeline: scroll(self y);
341
+ animation-range: calc(
342
+ 100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))
343
+ )
344
+ 100%;
345
+ animation-fill-mode: both;
346
+ }
347
+
348
+ @supports not (animation-timeline: scroll()) {
349
+ --scroll-fade-b: var(--_scroll-fade-size-b);
350
+ }
351
+ }
352
+
353
+ @utility scroll-fade-l {
354
+ --_scroll-fade-size-s: var(
355
+ --scroll-fade-s-size,
356
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
357
+ );
358
+ --scroll-fade-mask: linear-gradient(
359
+ to right,
360
+ transparent 0,
361
+ #000 var(--scroll-fade-s, 0px),
362
+ #000 100%
363
+ );
364
+ -webkit-mask-image: var(--scroll-fade-mask);
365
+ mask-image: var(--scroll-fade-mask);
366
+ -webkit-mask-composite: source-in;
367
+ mask-composite: intersect;
368
+ -webkit-mask-repeat: no-repeat;
369
+ mask-repeat: no-repeat;
370
+
371
+ @supports (animation-timeline: scroll()) {
372
+ animation: scroll-fade-reveal-s 1ms ease-in-out;
373
+ animation-timeline: scroll(self x);
374
+ animation-range: 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24));
375
+ animation-fill-mode: both;
376
+ }
377
+
378
+ @supports not (animation-timeline: scroll()) {
379
+ --scroll-fade-s: var(--_scroll-fade-size-s);
380
+ }
381
+ }
382
+
383
+ @utility scroll-fade-r {
384
+ --_scroll-fade-size-e: var(
385
+ --scroll-fade-e-size,
386
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
387
+ );
388
+ --scroll-fade-mask: linear-gradient(
389
+ to right,
390
+ #000 0,
391
+ #000 calc(100% - var(--scroll-fade-e, 0px)),
392
+ transparent 100%
393
+ );
394
+ -webkit-mask-image: var(--scroll-fade-mask);
395
+ mask-image: var(--scroll-fade-mask);
396
+ -webkit-mask-composite: source-in;
397
+ mask-composite: intersect;
398
+ -webkit-mask-repeat: no-repeat;
399
+ mask-repeat: no-repeat;
400
+
401
+ @supports (animation-timeline: scroll()) {
402
+ animation: scroll-fade-reveal-e 1ms ease-in-out;
403
+ animation-timeline: scroll(self x);
404
+ animation-range: calc(
405
+ 100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))
406
+ )
407
+ 100%;
408
+ animation-fill-mode: both;
409
+ }
410
+
411
+ @supports not (animation-timeline: scroll()) {
412
+ --scroll-fade-e: var(--_scroll-fade-size-e);
413
+ }
414
+ }
415
+
416
+ @utility scroll-fade-s {
417
+ --_scroll-fade-size-s: var(
418
+ --scroll-fade-s-size,
419
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
420
+ );
421
+ --scroll-fade-mask: linear-gradient(
422
+ to right,
423
+ transparent 0,
424
+ #000 var(--scroll-fade-s, 0px),
425
+ #000 100%
426
+ );
427
+ &:where([dir="rtl"], [dir="rtl"] *) {
428
+ --scroll-fade-mask: linear-gradient(
429
+ to left,
430
+ transparent 0,
431
+ #000 var(--scroll-fade-s, 0px),
432
+ #000 100%
433
+ );
434
+ }
435
+ -webkit-mask-image: var(--scroll-fade-mask);
436
+ mask-image: var(--scroll-fade-mask);
437
+ -webkit-mask-composite: source-in;
438
+ mask-composite: intersect;
439
+ -webkit-mask-repeat: no-repeat;
440
+ mask-repeat: no-repeat;
441
+
442
+ @supports (animation-timeline: scroll()) {
443
+ animation: scroll-fade-reveal-s 1ms ease-in-out;
444
+ animation-timeline: scroll(self inline);
445
+ animation-range: 0 var(--scroll-fade-reveal, calc(var(--spacing) * 24));
446
+ animation-fill-mode: both;
447
+ }
448
+
449
+ @supports not (animation-timeline: scroll()) {
450
+ --scroll-fade-s: var(--_scroll-fade-size-s);
451
+ }
452
+ }
453
+
454
+ @utility scroll-fade-e {
455
+ --_scroll-fade-size-e: var(
456
+ --scroll-fade-e-size,
457
+ var(--scroll-fade-size, min(12%, calc(var(--spacing) * 10)))
458
+ );
459
+ --scroll-fade-mask: linear-gradient(
460
+ to right,
461
+ #000 0,
462
+ #000 calc(100% - var(--scroll-fade-e, 0px)),
463
+ transparent 100%
464
+ );
465
+ &:where([dir="rtl"], [dir="rtl"] *) {
466
+ --scroll-fade-mask: linear-gradient(
467
+ to left,
468
+ #000 0,
469
+ #000 calc(100% - var(--scroll-fade-e, 0px)),
470
+ transparent 100%
471
+ );
472
+ }
473
+ -webkit-mask-image: var(--scroll-fade-mask);
474
+ mask-image: var(--scroll-fade-mask);
475
+ -webkit-mask-composite: source-in;
476
+ mask-composite: intersect;
477
+ -webkit-mask-repeat: no-repeat;
478
+ mask-repeat: no-repeat;
479
+
480
+ @supports (animation-timeline: scroll()) {
481
+ animation: scroll-fade-reveal-e 1ms ease-in-out;
482
+ animation-timeline: scroll(self inline);
483
+ animation-range: calc(
484
+ 100% - var(--scroll-fade-reveal, calc(var(--spacing) * 24))
485
+ )
486
+ 100%;
487
+ animation-fill-mode: both;
488
+ }
489
+
490
+ @supports not (animation-timeline: scroll()) {
491
+ --scroll-fade-e: var(--_scroll-fade-size-e);
492
+ }
493
+ }
494
+
495
+ @utility scroll-fade-* {
496
+ --scroll-fade-size: calc(var(--spacing) * --value(integer));
497
+ --scroll-fade-size: --value([length], [percentage]);
498
+ }
499
+
500
+ @utility scroll-fade-t-* {
501
+ --scroll-fade-t-size: calc(var(--spacing) * --value(integer));
502
+ --scroll-fade-t-size: --value([length], [percentage]);
503
+ }
504
+
505
+ @utility scroll-fade-b-* {
506
+ --scroll-fade-b-size: calc(var(--spacing) * --value(integer));
507
+ --scroll-fade-b-size: --value([length], [percentage]);
508
+ }
509
+
510
+ @utility scroll-fade-s-* {
511
+ --scroll-fade-s-size: calc(var(--spacing) * --value(integer));
512
+ --scroll-fade-s-size: --value([length], [percentage]);
513
+ }
514
+
515
+ @utility scroll-fade-e-* {
516
+ --scroll-fade-e-size: calc(var(--spacing) * --value(integer));
517
+ --scroll-fade-e-size: --value([length], [percentage]);
518
+ }
519
+
520
+ @utility scroll-fade-none {
521
+ --scroll-fade-mask: none;
522
+ }
523
+
524
+ /* shimmer */
525
+ @property --shimmer-angle {
526
+ syntax: "<angle>";
527
+ inherits: true;
528
+ initial-value: 20deg;
529
+ }
530
+ @property --shimmer-image {
531
+ syntax: "*";
532
+ inherits: false;
533
+ }
534
+ @property --shimmer-text-fill {
535
+ syntax: "*";
536
+ inherits: false;
537
+ }
538
+
539
+ @theme inline {
540
+ @keyframes tw-shimmer {
541
+ from {
542
+ background-position: 100% 0;
543
+ }
544
+ to {
545
+ background-position: 0 0;
546
+ }
547
+ }
548
+ }
549
+
550
+ @utility shimmer {
551
+ --_spread: var(--shimmer-spread, calc(3ch + 40px));
552
+ --_base: currentColor;
553
+ --_highlight: var(
554
+ --shimmer-color,
555
+ oklch(from currentColor l c h / calc(alpha* 0.2))
556
+ );
557
+
558
+ background-image: var(
559
+ --shimmer-image,
560
+ linear-gradient(
561
+ calc(90deg + var(--shimmer-angle)),
562
+ var(--_base) calc(50% - var(--_spread)),
563
+ color-mix(in oklch, var(--_highlight), var(--_base) 50%)
564
+ calc(50% - var(--_spread) * 0.5),
565
+ var(--_highlight) 50%,
566
+ color-mix(in oklch, var(--_highlight), var(--_base) 50%)
567
+ calc(50% + var(--_spread) * 0.5),
568
+ var(--_base) calc(50% + var(--_spread))
569
+ )
570
+ );
571
+ background-repeat: no-repeat;
572
+ background-size: calc(200% + var(--_spread) * 2) 100%;
573
+ background-position: 0 0;
574
+ background-clip: text;
575
+ -webkit-background-clip: text;
576
+ -webkit-text-fill-color: var(--shimmer-text-fill, transparent);
577
+ animation: tw-shimmer var(--shimmer-duration, 2s) linear infinite;
578
+
579
+ @variant dark {
580
+ --_highlight: var(
581
+ --shimmer-color,
582
+ oklch(from currentColor max(0.8, calc(l + 0.4)) c h / calc(alpha + 0.4))
583
+ );
584
+ }
585
+
586
+ &:where([dir="rtl"], [dir="rtl"] *) {
587
+ animation-direction: reverse;
588
+ }
589
+
590
+ @media (prefers-reduced-motion: reduce) {
591
+ animation: none;
592
+ background-image: none;
593
+ -webkit-text-fill-color: currentColor;
594
+ }
595
+ }
596
+
597
+ @utility shimmer-once {
598
+ animation-iteration-count: 1;
599
+ }
600
+
601
+ @utility shimmer-reverse {
602
+ animation-direction: reverse;
603
+ }
604
+
605
+ @utility shimmer-none {
606
+ --shimmer-image: none;
607
+ --shimmer-text-fill: currentColor;
608
+ }
609
+
610
+ @utility shimmer-color-* {
611
+ --shimmer-color: --value(--color, [color]);
612
+ --shimmer-color: color-mix(
613
+ in oklch,
614
+ --value(--color, [color]) calc(--modifier(integer) * 1%),
615
+ transparent
616
+ );
617
+ }
618
+
619
+ @utility shimmer-duration-* {
620
+ --shimmer-duration: calc(--value(integer) * 1ms);
621
+ }
622
+
623
+ @utility shimmer-spread-* {
624
+ --shimmer-spread: calc(var(--spacing) * --value(integer));
625
+ --shimmer-spread: --value([length], [percentage]);
626
+ }
627
+
628
+ @utility shimmer-angle-* {
629
+ --shimmer-angle: calc(--value(integer) * 1deg);
630
+ }
631
+
632
+ /* Kept for backwards compatibility. Unlayered, so it still wins over other
633
+ utilities on a plain .shimmer element. Variants are handled in the utility. */
634
+ @media (prefers-reduced-motion: reduce) {
635
+ .shimmer {
636
+ animation: none;
637
+ background-image: none;
638
+ -webkit-text-fill-color: currentColor;
639
+ }
640
+ }