@ai-matrx/design-system 0.8.0 → 0.10.0
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/CHANGELOG.md +217 -0
- package/README.md +16 -0
- package/dist/index.cjs +489 -383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +184 -9
- package/dist/index.d.ts +184 -9
- package/dist/index.js +454 -348
- package/dist/index.js.map +1 -1
- package/dist/styles.css +474 -0
- package/dist/tokens.css +25 -0
- package/package.json +1 -1
package/dist/styles.css
CHANGED
|
@@ -190,6 +190,480 @@
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
/* Collapsible open/close. The SAME rule as the accordion above and a separate
|
|
194
|
+
one on purpose: Radix publishes a DIFFERENT measured variable per primitive
|
|
195
|
+
(`--radix-collapsible-content-height`), and the whole reason this ships here
|
|
196
|
+
is that two matrx-frontend collapsibles reached for the ACCORDION keyframes
|
|
197
|
+
and therefore interpolated to a variable that is never set on a collapsible
|
|
198
|
+
— no animation, no error, for as long as they existed (census row 19f).
|
|
199
|
+
Six more used host-only `slide-down`/`slide-up` keyframes that were keyed
|
|
200
|
+
correctly and existed in exactly one app's globals.css: the same C26 silent
|
|
201
|
+
host contract, wearing a working coat. One duration (200ms) for both
|
|
202
|
+
primitives, so a collapsible and an accordion on the same screen agree.
|
|
203
|
+
Colourless and inert until an element carries the class. */
|
|
204
|
+
@keyframes matrx-collapsible-down {
|
|
205
|
+
from {
|
|
206
|
+
height: 0;
|
|
207
|
+
}
|
|
208
|
+
to {
|
|
209
|
+
height: var(--radix-collapsible-content-height);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
@keyframes matrx-collapsible-up {
|
|
213
|
+
from {
|
|
214
|
+
height: var(--radix-collapsible-content-height);
|
|
215
|
+
}
|
|
216
|
+
to {
|
|
217
|
+
height: 0;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
.matrx-collapsible-content[data-state="open"] {
|
|
221
|
+
animation: matrx-collapsible-down 200ms ease-out;
|
|
222
|
+
}
|
|
223
|
+
.matrx-collapsible-content[data-state="closed"] {
|
|
224
|
+
animation: matrx-collapsible-up 200ms ease-out;
|
|
225
|
+
}
|
|
226
|
+
@media (prefers-reduced-motion: reduce) {
|
|
227
|
+
.matrx-collapsible-content[data-state="open"],
|
|
228
|
+
.matrx-collapsible-content[data-state="closed"] {
|
|
229
|
+
animation: none;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* ═══════════════════════════════════════════════════════════════════════
|
|
234
|
+
THE MOTION LAYER (0.10.0) — every overlay animation this package emits.
|
|
235
|
+
|
|
236
|
+
THE DOCTRINE (FEATURE.md): a primitive that leaves motion to the host has
|
|
237
|
+
not shipped motion, it has shipped a coin flip. 0.8.0 and 0.9.0 closed that
|
|
238
|
+
for Accordion and Collapsible one primitive at a time. The sweep that
|
|
239
|
+
followed found the SAME shape on ten more, and far worse than a missing
|
|
240
|
+
keyframe: every floating surface in this package — Dialog, AlertDialog,
|
|
241
|
+
Sheet, CommandDialog, Popover, DropdownMenu, ContextMenu, HoverCard,
|
|
242
|
+
Select, Tooltip — animated with `animate-in` / `animate-out` /
|
|
243
|
+
`fade-in-0` / `zoom-in-95` / `slide-in-from-*-2`. Those are not Tailwind
|
|
244
|
+
utilities. They come from the `tailwindcss-animate` plugin (or its v4
|
|
245
|
+
successor `tw-animate-css`), which is a HOST dependency this package never
|
|
246
|
+
declared and cannot declare — a Tailwind plugin is loaded by the host's CSS
|
|
247
|
+
entry, not by a node_modules package.
|
|
248
|
+
|
|
249
|
+
Measured on built output, 2026-09-07, before this file owned any of it:
|
|
250
|
+
|
|
251
|
+
matrx-frontend `@import "tw-animate-css"` in globals.css → animated
|
|
252
|
+
aidream/dashboard no plugin → 0 rules
|
|
253
|
+
aidream/workflow-studio no plugin → 0 rules
|
|
254
|
+
matrx-extend `tailwindcss-animate` in package.json but
|
|
255
|
+
NEVER LOADED (it is a Tailwind v3 plugin and
|
|
256
|
+
extend is on v4 with no `@plugin` directive)
|
|
257
|
+
→ 0 rules
|
|
258
|
+
|
|
259
|
+
Three consumers out of four. `grep -c 'animate-in\|slide-in-from'` on each
|
|
260
|
+
app's built stylesheet returned 0. Every dialog, dropdown, popover, tooltip
|
|
261
|
+
and sheet in the two aidream apps and the Chrome extension appeared
|
|
262
|
+
instantly, with no animation and no error, for as long as they existed.
|
|
263
|
+
The one host that worked, worked by accident of its own CSS entry.
|
|
264
|
+
|
|
265
|
+
So the package owns it. Below: package-defined keyframes, applied through
|
|
266
|
+
`matrx-`-prefixed classes the components put on the DOM themselves, timed
|
|
267
|
+
from `--matrx-motion-*` tokens, silenced by `prefers-reduced-motion`, and
|
|
268
|
+
asserted by `styles.test.ts` + the packed-tarball canary.
|
|
269
|
+
|
|
270
|
+
WHERE THE LINE IS. This layer owns KEYFRAME ANIMATION — motion that either
|
|
271
|
+
happens or silently does not. It deliberately does NOT own Tailwind's
|
|
272
|
+
`transition-*` / `duration-*` / `ease-*` utilities that the primitives also
|
|
273
|
+
carry (a hover colour easing, the progress bar's width, the close button's
|
|
274
|
+
opacity). Those are CORE Tailwind, present in every Tailwind host, and
|
|
275
|
+
their absence degrades to an instant-but-correct change rather than to a
|
|
276
|
+
surface that lies about its state. Re-implementing them here would mean
|
|
277
|
+
shipping a copy of Tailwind.
|
|
278
|
+
|
|
279
|
+
UNLAYERED on purpose, exactly like the accordion and collapsible rules
|
|
280
|
+
above: a host that still loads `tw-animate-css` would otherwise emit a
|
|
281
|
+
competing `animation` from `@layer utilities` and win, giving that one host
|
|
282
|
+
different motion from everyone else — the coin flip again, wearing a
|
|
283
|
+
working coat. Unlayered means every consumer gets identical motion. The
|
|
284
|
+
sanctioned escape is the `animated={false}` prop on the component, not a
|
|
285
|
+
className.
|
|
286
|
+
═══════════════════════════════════════════════════════════════════════ */
|
|
287
|
+
|
|
288
|
+
/* --- scrim ------------------------------------------------------------- */
|
|
289
|
+
@keyframes matrx-fade-in {
|
|
290
|
+
from {
|
|
291
|
+
opacity: 0;
|
|
292
|
+
}
|
|
293
|
+
to {
|
|
294
|
+
opacity: 1;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
@keyframes matrx-fade-out {
|
|
298
|
+
from {
|
|
299
|
+
opacity: 1;
|
|
300
|
+
}
|
|
301
|
+
to {
|
|
302
|
+
opacity: 0;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
.matrx-motion-overlay[data-state="open"] {
|
|
306
|
+
animation: matrx-fade-in var(--matrx-motion-duration-base)
|
|
307
|
+
var(--matrx-motion-ease-out);
|
|
308
|
+
}
|
|
309
|
+
.matrx-motion-overlay[data-state="closed"] {
|
|
310
|
+
animation: matrx-fade-out var(--matrx-motion-duration-base)
|
|
311
|
+
var(--matrx-motion-ease-in);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* --- centred dialog card ----------------------------------------------
|
|
315
|
+
The card is positioned by `translate-x-[-50%] translate-y-[-50%]`
|
|
316
|
+
utilities, and an animation REPLACES `transform` for its whole duration —
|
|
317
|
+
which is why the shadcn original had to re-state the centring inside the
|
|
318
|
+
motion (`slide-in-from-left-1/2 slide-in-from-top-[48%]`). Owning the
|
|
319
|
+
keyframes lets us just say it: the card rises 2% and scales up from 95%,
|
|
320
|
+
ending exactly on the resting transform so nothing jumps at the end. */
|
|
321
|
+
@keyframes matrx-dialog-in {
|
|
322
|
+
from {
|
|
323
|
+
opacity: 0;
|
|
324
|
+
transform: translate(-50%, -48%) scale(0.95);
|
|
325
|
+
}
|
|
326
|
+
to {
|
|
327
|
+
opacity: 1;
|
|
328
|
+
transform: translate(-50%, -50%) scale(1);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
@keyframes matrx-dialog-out {
|
|
332
|
+
from {
|
|
333
|
+
opacity: 1;
|
|
334
|
+
transform: translate(-50%, -50%) scale(1);
|
|
335
|
+
}
|
|
336
|
+
to {
|
|
337
|
+
opacity: 0;
|
|
338
|
+
transform: translate(-50%, -48%) scale(0.95);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
.matrx-motion-dialog[data-state="open"] {
|
|
342
|
+
animation: matrx-dialog-in var(--matrx-motion-duration-base)
|
|
343
|
+
var(--matrx-motion-ease-out);
|
|
344
|
+
}
|
|
345
|
+
.matrx-motion-dialog[data-state="closed"] {
|
|
346
|
+
animation: matrx-dialog-out var(--matrx-motion-duration-base)
|
|
347
|
+
var(--matrx-motion-ease-in);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* --- edge sheets -------------------------------------------------------
|
|
351
|
+
Five named classes rather than one `data-side` rule, because a Sheet's side
|
|
352
|
+
is a `sheetVariants` variant on the element's own class list — Radix
|
|
353
|
+
publishes no `data-side` on a Dialog-based sheet. The mobile Dialog /
|
|
354
|
+
CommandDialog bottom sheet reuses `-bottom`. */
|
|
355
|
+
@keyframes matrx-slide-in-top {
|
|
356
|
+
from {
|
|
357
|
+
transform: translateY(-100%);
|
|
358
|
+
}
|
|
359
|
+
to {
|
|
360
|
+
transform: translateY(0);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
@keyframes matrx-slide-out-top {
|
|
364
|
+
from {
|
|
365
|
+
transform: translateY(0);
|
|
366
|
+
}
|
|
367
|
+
to {
|
|
368
|
+
transform: translateY(-100%);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
@keyframes matrx-slide-in-bottom {
|
|
372
|
+
from {
|
|
373
|
+
transform: translateY(100%);
|
|
374
|
+
}
|
|
375
|
+
to {
|
|
376
|
+
transform: translateY(0);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
@keyframes matrx-slide-out-bottom {
|
|
380
|
+
from {
|
|
381
|
+
transform: translateY(0);
|
|
382
|
+
}
|
|
383
|
+
to {
|
|
384
|
+
transform: translateY(100%);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
@keyframes matrx-slide-in-left {
|
|
388
|
+
from {
|
|
389
|
+
transform: translateX(-100%);
|
|
390
|
+
}
|
|
391
|
+
to {
|
|
392
|
+
transform: translateX(0);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
@keyframes matrx-slide-out-left {
|
|
396
|
+
from {
|
|
397
|
+
transform: translateX(0);
|
|
398
|
+
}
|
|
399
|
+
to {
|
|
400
|
+
transform: translateX(-100%);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
@keyframes matrx-slide-in-right {
|
|
404
|
+
from {
|
|
405
|
+
transform: translateX(100%);
|
|
406
|
+
}
|
|
407
|
+
to {
|
|
408
|
+
transform: translateX(0);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
@keyframes matrx-slide-out-right {
|
|
412
|
+
from {
|
|
413
|
+
transform: translateX(0);
|
|
414
|
+
}
|
|
415
|
+
to {
|
|
416
|
+
transform: translateX(100%);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
.matrx-motion-sheet-top[data-state="open"] {
|
|
420
|
+
animation: matrx-slide-in-top var(--matrx-motion-duration-sheet)
|
|
421
|
+
var(--matrx-motion-ease-out);
|
|
422
|
+
}
|
|
423
|
+
.matrx-motion-sheet-top[data-state="closed"] {
|
|
424
|
+
animation: matrx-slide-out-top var(--matrx-motion-duration-slow)
|
|
425
|
+
var(--matrx-motion-ease-in);
|
|
426
|
+
}
|
|
427
|
+
.matrx-motion-sheet-bottom[data-state="open"] {
|
|
428
|
+
animation: matrx-slide-in-bottom var(--matrx-motion-duration-sheet)
|
|
429
|
+
var(--matrx-motion-ease-out);
|
|
430
|
+
}
|
|
431
|
+
.matrx-motion-sheet-bottom[data-state="closed"] {
|
|
432
|
+
animation: matrx-slide-out-bottom var(--matrx-motion-duration-slow)
|
|
433
|
+
var(--matrx-motion-ease-in);
|
|
434
|
+
}
|
|
435
|
+
.matrx-motion-sheet-left[data-state="open"] {
|
|
436
|
+
animation: matrx-slide-in-left var(--matrx-motion-duration-sheet)
|
|
437
|
+
var(--matrx-motion-ease-out);
|
|
438
|
+
}
|
|
439
|
+
.matrx-motion-sheet-left[data-state="closed"] {
|
|
440
|
+
animation: matrx-slide-out-left var(--matrx-motion-duration-slow)
|
|
441
|
+
var(--matrx-motion-ease-in);
|
|
442
|
+
}
|
|
443
|
+
.matrx-motion-sheet-right[data-state="open"] {
|
|
444
|
+
animation: matrx-slide-in-right var(--matrx-motion-duration-sheet)
|
|
445
|
+
var(--matrx-motion-ease-out);
|
|
446
|
+
}
|
|
447
|
+
.matrx-motion-sheet-right[data-state="closed"] {
|
|
448
|
+
animation: matrx-slide-out-right var(--matrx-motion-duration-slow)
|
|
449
|
+
var(--matrx-motion-ease-in);
|
|
450
|
+
}
|
|
451
|
+
/* A `side="center"` Sheet has no edge to come from, so it fades like a
|
|
452
|
+
dialog scrim rather than sliding from nowhere. */
|
|
453
|
+
.matrx-motion-sheet-center[data-state="open"] {
|
|
454
|
+
animation: matrx-fade-in var(--matrx-motion-duration-sheet)
|
|
455
|
+
var(--matrx-motion-ease-out);
|
|
456
|
+
}
|
|
457
|
+
.matrx-motion-sheet-center[data-state="closed"] {
|
|
458
|
+
animation: matrx-fade-out var(--matrx-motion-duration-slow)
|
|
459
|
+
var(--matrx-motion-ease-in);
|
|
460
|
+
}
|
|
461
|
+
/* The mobile Dialog / CommandDialog bottom sheet: slides AND fades, at the
|
|
462
|
+
dialog's 200ms rather than the Sheet's 500ms, because it is a dialog
|
|
463
|
+
wearing sheet geometry and it opens from a tap, not from a nav gesture. */
|
|
464
|
+
@keyframes matrx-bottom-sheet-in {
|
|
465
|
+
from {
|
|
466
|
+
opacity: 0;
|
|
467
|
+
transform: translateY(100%);
|
|
468
|
+
}
|
|
469
|
+
to {
|
|
470
|
+
opacity: 1;
|
|
471
|
+
transform: translateY(0);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
@keyframes matrx-bottom-sheet-out {
|
|
475
|
+
from {
|
|
476
|
+
opacity: 1;
|
|
477
|
+
transform: translateY(0);
|
|
478
|
+
}
|
|
479
|
+
to {
|
|
480
|
+
opacity: 0;
|
|
481
|
+
transform: translateY(100%);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
.matrx-motion-bottom-sheet[data-state="open"] {
|
|
485
|
+
animation: matrx-bottom-sheet-in var(--matrx-motion-duration-base)
|
|
486
|
+
var(--matrx-motion-ease-out);
|
|
487
|
+
}
|
|
488
|
+
.matrx-motion-bottom-sheet[data-state="closed"] {
|
|
489
|
+
animation: matrx-bottom-sheet-out var(--matrx-motion-duration-base)
|
|
490
|
+
var(--matrx-motion-ease-in);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/* --- poppers -----------------------------------------------------------
|
|
494
|
+
Popover, DropdownMenu, ContextMenu, HoverCard, Select and Tooltip all
|
|
495
|
+
position through Radix's popper, which publishes `data-side` on the content
|
|
496
|
+
and `--radix-popper-transform-origin` — the point on the surface that faces
|
|
497
|
+
the trigger. Reading that origin is a correctness fix the `zoom-in-95`
|
|
498
|
+
original never had: the surface now grows OUT OF its anchor instead of out
|
|
499
|
+
of its own centre, so a menu below a button no longer appears to expand
|
|
500
|
+
upward into the button.
|
|
501
|
+
|
|
502
|
+
`data-side` says where the surface sits, so it travels FROM the trigger:
|
|
503
|
+
a surface on the `bottom` starts slightly above where it lands. Exit fades
|
|
504
|
+
and shrinks without sliding — matching the originals, and the right
|
|
505
|
+
behaviour, since a surface leaving should not appear to move somewhere. */
|
|
506
|
+
@keyframes matrx-popper-in-from-top {
|
|
507
|
+
from {
|
|
508
|
+
opacity: 0;
|
|
509
|
+
transform: scale(0.95) translateY(calc(-1 * var(--matrx-motion-popper-travel)));
|
|
510
|
+
}
|
|
511
|
+
to {
|
|
512
|
+
opacity: 1;
|
|
513
|
+
transform: scale(1) translateY(0);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
@keyframes matrx-popper-in-from-bottom {
|
|
517
|
+
from {
|
|
518
|
+
opacity: 0;
|
|
519
|
+
transform: scale(0.95) translateY(var(--matrx-motion-popper-travel));
|
|
520
|
+
}
|
|
521
|
+
to {
|
|
522
|
+
opacity: 1;
|
|
523
|
+
transform: scale(1) translateY(0);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
@keyframes matrx-popper-in-from-left {
|
|
527
|
+
from {
|
|
528
|
+
opacity: 0;
|
|
529
|
+
transform: scale(0.95) translateX(calc(-1 * var(--matrx-motion-popper-travel)));
|
|
530
|
+
}
|
|
531
|
+
to {
|
|
532
|
+
opacity: 1;
|
|
533
|
+
transform: scale(1) translateX(0);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
@keyframes matrx-popper-in-from-right {
|
|
537
|
+
from {
|
|
538
|
+
opacity: 0;
|
|
539
|
+
transform: scale(0.95) translateX(var(--matrx-motion-popper-travel));
|
|
540
|
+
}
|
|
541
|
+
to {
|
|
542
|
+
opacity: 1;
|
|
543
|
+
transform: scale(1) translateX(0);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
@keyframes matrx-popper-out {
|
|
547
|
+
from {
|
|
548
|
+
opacity: 1;
|
|
549
|
+
transform: scale(1);
|
|
550
|
+
}
|
|
551
|
+
to {
|
|
552
|
+
opacity: 0;
|
|
553
|
+
transform: scale(0.95);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/* THE RIGHT VARIABLE, PER PRIMITIVE. Radix publishes the anchor-facing origin
|
|
557
|
+
under the shared popper name AND under a per-primitive alias, and which one
|
|
558
|
+
is present depends on the primitive — `Select` sets
|
|
559
|
+
`--radix-select-content-transform-origin`, `Tooltip` sets
|
|
560
|
+
`--radix-tooltip-content-transform-origin`, and so on. Reusing one
|
|
561
|
+
primitive's variable on another is the exact silent death census row 19f
|
|
562
|
+
recorded (accordion keyframes on a collapsible panel), so this states the
|
|
563
|
+
whole chain rather than betting on one name. If none resolves, the origin
|
|
564
|
+
falls back to the element's centre — degraded, never broken. */
|
|
565
|
+
.matrx-motion-popper {
|
|
566
|
+
transform-origin: var(
|
|
567
|
+
--radix-popper-transform-origin,
|
|
568
|
+
var(
|
|
569
|
+
--radix-select-content-transform-origin,
|
|
570
|
+
var(
|
|
571
|
+
--radix-tooltip-content-transform-origin,
|
|
572
|
+
var(
|
|
573
|
+
--radix-dropdown-menu-content-transform-origin,
|
|
574
|
+
var(
|
|
575
|
+
--radix-context-menu-content-transform-origin,
|
|
576
|
+
var(
|
|
577
|
+
--radix-hover-card-content-transform-origin,
|
|
578
|
+
var(--radix-popover-content-transform-origin, center)
|
|
579
|
+
)
|
|
580
|
+
)
|
|
581
|
+
)
|
|
582
|
+
)
|
|
583
|
+
)
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
/* A surface rendered BELOW the trigger enters from above it, and so on. The
|
|
587
|
+
bare `[data-state=open]` rule is the fallback for the frame before the
|
|
588
|
+
popper has measured a side (and for `Select` in `item-aligned` position,
|
|
589
|
+
which publishes no side at all). */
|
|
590
|
+
.matrx-motion-popper[data-state="open"] {
|
|
591
|
+
animation: matrx-popper-in-from-top var(--matrx-motion-duration-fast)
|
|
592
|
+
var(--matrx-motion-ease-out);
|
|
593
|
+
}
|
|
594
|
+
.matrx-motion-popper[data-state="open"][data-side="bottom"] {
|
|
595
|
+
animation-name: matrx-popper-in-from-top;
|
|
596
|
+
}
|
|
597
|
+
.matrx-motion-popper[data-state="open"][data-side="top"] {
|
|
598
|
+
animation-name: matrx-popper-in-from-bottom;
|
|
599
|
+
}
|
|
600
|
+
.matrx-motion-popper[data-state="open"][data-side="right"] {
|
|
601
|
+
animation-name: matrx-popper-in-from-left;
|
|
602
|
+
}
|
|
603
|
+
.matrx-motion-popper[data-state="open"][data-side="left"] {
|
|
604
|
+
animation-name: matrx-popper-in-from-right;
|
|
605
|
+
}
|
|
606
|
+
.matrx-motion-popper[data-state="closed"] {
|
|
607
|
+
animation: matrx-popper-out var(--matrx-motion-duration-fast)
|
|
608
|
+
var(--matrx-motion-ease-in);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/* --- the two indefinite loops -----------------------------------------
|
|
612
|
+
`animate-pulse` and `animate-spin` ARE core Tailwind, so they survive in a
|
|
613
|
+
Tailwind host — but a Skeleton that does not pulse is indistinguishable
|
|
614
|
+
from an empty grey box, and a spinner that does not spin claims the work
|
|
615
|
+
has stopped. Both are load-bearing lies in a non-Tailwind consumer, and
|
|
616
|
+
both are four lines. The package owns them. */
|
|
617
|
+
@keyframes matrx-pulse {
|
|
618
|
+
0%,
|
|
619
|
+
100% {
|
|
620
|
+
opacity: 1;
|
|
621
|
+
}
|
|
622
|
+
50% {
|
|
623
|
+
opacity: 0.5;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
@keyframes matrx-spin {
|
|
627
|
+
to {
|
|
628
|
+
transform: rotate(360deg);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
.matrx-pulse {
|
|
632
|
+
animation: matrx-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
633
|
+
}
|
|
634
|
+
.matrx-spin {
|
|
635
|
+
animation: matrx-spin 1s linear infinite;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/* --- the accessibility switch -----------------------------------------
|
|
639
|
+
ONE block for the whole motion layer. A surface still appears and
|
|
640
|
+
disappears — it just does so without travelling. The two indefinite loops
|
|
641
|
+
are the exception that proves the rule: a Skeleton and a spinner say
|
|
642
|
+
"still working" with motion and nothing else, so silencing them entirely
|
|
643
|
+
would remove the information. They slow down instead of stopping.
|
|
644
|
+
|
|
645
|
+
Deliberately NOT a `--matrx-motion-*` token: a user's OS-level reduced
|
|
646
|
+
motion preference is not an org setting a host may override. */
|
|
647
|
+
@media (prefers-reduced-motion: reduce) {
|
|
648
|
+
.matrx-motion-overlay[data-state],
|
|
649
|
+
.matrx-motion-dialog[data-state],
|
|
650
|
+
.matrx-motion-sheet-top[data-state],
|
|
651
|
+
.matrx-motion-sheet-bottom[data-state],
|
|
652
|
+
.matrx-motion-sheet-left[data-state],
|
|
653
|
+
.matrx-motion-sheet-right[data-state],
|
|
654
|
+
.matrx-motion-sheet-center[data-state],
|
|
655
|
+
.matrx-motion-bottom-sheet[data-state],
|
|
656
|
+
.matrx-motion-popper[data-state] {
|
|
657
|
+
animation: none;
|
|
658
|
+
}
|
|
659
|
+
.matrx-pulse {
|
|
660
|
+
animation-duration: 4s;
|
|
661
|
+
}
|
|
662
|
+
.matrx-spin {
|
|
663
|
+
animation-duration: 3s;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
193
667
|
/* ────────────────────────────────────────────────────────────────────────
|
|
194
668
|
Scroll fade — the "there is more below" cue. UNLAYERED on purpose.
|
|
195
669
|
Driven by `useScrollFade`, which sets the data attributes ONLY on edges
|
package/dist/tokens.css
CHANGED
|
@@ -117,6 +117,31 @@
|
|
|
117
117
|
0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
118
118
|
--matrx-glass-shadow-lg:
|
|
119
119
|
0 4px 16px rgba(0, 0, 0, 0.08), 0 2px 6px rgba(0, 0, 0, 0.04);
|
|
120
|
+
|
|
121
|
+
/* MOTION (0.10.0). Every package-owned animation in styles.css reads its
|
|
122
|
+
duration and easing from here, so a host retimes the whole system by
|
|
123
|
+
redeclaring four values — and an org that wants calmer motion sets them
|
|
124
|
+
once instead of overriding twenty rules. They are NOT the accessibility
|
|
125
|
+
switch: `prefers-reduced-motion: reduce` silences the animations
|
|
126
|
+
outright in styles.css, regardless of these values.
|
|
127
|
+
|
|
128
|
+
The numbers are the ones the primitives already carried as Tailwind
|
|
129
|
+
`duration-*` utilities before the package owned the keyframes:
|
|
130
|
+
poppers/tooltips 150ms, dialogs and overlays 200ms, a sheet closing
|
|
131
|
+
300ms and opening 500ms. */
|
|
132
|
+
--matrx-motion-duration-fast: 150ms;
|
|
133
|
+
--matrx-motion-duration-base: 200ms;
|
|
134
|
+
--matrx-motion-duration-slow: 300ms;
|
|
135
|
+
--matrx-motion-duration-sheet: 500ms;
|
|
136
|
+
/* Enters decelerate (the surface arrives and settles); exits accelerate
|
|
137
|
+
(it leaves and is gone). Linear on both — which is what
|
|
138
|
+
`tailwindcss-animate` defaulted to — reads mechanical at these
|
|
139
|
+
durations. */
|
|
140
|
+
--matrx-motion-ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
141
|
+
--matrx-motion-ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
142
|
+
/* The distance a popper travels toward its anchor as it opens. 0.5rem is
|
|
143
|
+
the `slide-in-from-*-2` the primitives carried. */
|
|
144
|
+
--matrx-motion-popper-travel: 0.5rem;
|
|
120
145
|
}
|
|
121
146
|
|
|
122
147
|
/* Dark theme. Matches the `.dark`-class convention (Tailwind v4 hosts wire
|
package/package.json
CHANGED