@waveso/ui 0.17.0 → 0.18.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/README.md +25 -14
- package/dist/accordion.js +2 -2
- package/dist/action-bar.js +1 -1
- package/dist/alert-dialog.js +1 -1
- package/dist/alert.js +1 -1
- package/dist/autocomplete.js +4 -4
- package/dist/avatar.js +6 -6
- package/dist/badge.js +2 -2
- package/dist/button-group.js +3 -3
- package/dist/button.js +3 -3
- package/dist/card.js +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/combobox.js +6 -6
- package/dist/context-menu.d.ts +1 -1
- package/dist/context-menu.js +27 -10
- package/dist/dialog.js +1 -1
- package/dist/drawer.js +2 -2
- package/dist/gradient-reveal-text.js +1 -1
- package/dist/input-group.js +1 -1
- package/dist/input-otp.js +1 -1
- package/dist/input.js +1 -1
- package/dist/item.js +2 -2
- package/dist/menu.d.ts +1 -1
- package/dist/menu.js +27 -10
- package/dist/menubar.js +2 -2
- package/dist/popover.js +1 -1
- package/dist/preview-card.js +1 -1
- package/dist/radio.js +1 -1
- package/dist/resizable.js +2 -2
- package/dist/scroll-area.js +2 -12
- package/dist/select.js +5 -5
- package/dist/separator.js +1 -1
- package/dist/sidebar.js +11 -11
- package/dist/slider.js +2 -2
- package/dist/styles.css +190 -76
- package/dist/swipe-deck.d.ts +92 -36
- package/dist/swipe-deck.js +601 -158
- package/dist/switch.js +1 -1
- package/dist/table.js +3 -3
- package/dist/tabs.js +3 -3
- package/dist/textarea.js +1 -1
- package/dist/toast.d.ts +1 -1
- package/dist/toast.js +4 -4
- package/dist/toggle.js +3 -3
- package/package.json +1 -1
package/dist/styles.css
CHANGED
|
@@ -247,21 +247,21 @@
|
|
|
247
247
|
* `--contrast`…).
|
|
248
248
|
* ──────────────────────────────────────────────────────────────────────── */
|
|
249
249
|
|
|
250
|
-
/* Graphite — the mid-tone grey (default). Built around its card
|
|
251
|
-
* 900 (#
|
|
252
|
-
* either side, the steps above evenly spaced up to the text
|
|
253
|
-
* 50. One hue, 278.
|
|
254
|
-
--graphite-50: oklch(0.964 0.001 278.
|
|
255
|
-
--graphite-100: oklch(0.
|
|
256
|
-
--graphite-200: oklch(0.
|
|
257
|
-
--graphite-300: oklch(0.
|
|
258
|
-
--graphite-400: oklch(0.
|
|
259
|
-
--graphite-500: oklch(0.
|
|
260
|
-
--graphite-600: oklch(0.
|
|
261
|
-
--graphite-700: oklch(0.
|
|
262
|
-
--graphite-800: oklch(0.
|
|
263
|
-
--graphite-900: oklch(0.
|
|
264
|
-
--graphite-950: oklch(0.
|
|
250
|
+
/* Graphite — the mid-tone grey (default). Built around its original card
|
|
251
|
+
* colour, the 900 (#323339): the page (950) and menus (800) one 1.15
|
|
252
|
+
* contrast step either side, the steps above evenly spaced up to the text
|
|
253
|
+
* colour at the 50. One hue, 278.3; chroma arcs to 0.014 through the middle. */
|
|
254
|
+
--graphite-50: oklch(0.964 0.001 278.3); /* #F3F3F4 */
|
|
255
|
+
--graphite-100: oklch(0.912 0.003 278.3); /* #E1E2E4 */
|
|
256
|
+
--graphite-200: oklch(0.842 0.007 278.3); /* #CACBD0 */
|
|
257
|
+
--graphite-300: oklch(0.761 0.009 278.3); /* #B0B1B7 */
|
|
258
|
+
--graphite-400: oklch(0.683 0.011 278.3); /* #9799A0 */
|
|
259
|
+
--graphite-500: oklch(0.595 0.013 278.3); /* #7D7E87 */
|
|
260
|
+
--graphite-600: oklch(0.506 0.014 278.3); /* #63646D */
|
|
261
|
+
--graphite-700: oklch(0.424 0.014 278.3); /* #4C4E56 */
|
|
262
|
+
--graphite-800: oklch(0.359 0.012 278.3); /* #3B3C43 */
|
|
263
|
+
--graphite-900: oklch(0.322 0.011 278.3); /* #323339 */
|
|
264
|
+
--graphite-950: oklch(0.283 0.009 278.3); /* #28292E */
|
|
265
265
|
|
|
266
266
|
/* Ink — deep navy surfaces, neutral-cool structure (page #020812, surface #0B1627).
|
|
267
267
|
* Graphite's even lightness steps between Ink's 50 and its page. Chroma fades
|
|
@@ -318,6 +318,11 @@
|
|
|
318
318
|
/* Rings = brand themed */
|
|
319
319
|
--focus: var(--primary);
|
|
320
320
|
|
|
321
|
+
/* Selected — chosen, current or on: the current tab, the sidebar's current
|
|
322
|
+
* page, a pressed toggle, a checked box, a selected row. Primary by default,
|
|
323
|
+
* so it looks as it always has; set it to restyle every chosen state at once. */
|
|
324
|
+
--selected: var(--primary);
|
|
325
|
+
|
|
321
326
|
/* Scrim — the dim behind modal overlays (dialog / drawer / alert backdrop). */
|
|
322
327
|
--scrim: oklch(0 0 0 / 0.1);
|
|
323
328
|
|
|
@@ -498,17 +503,17 @@
|
|
|
498
503
|
--wave-teal-900: oklch(0.251 0.049 219.9);
|
|
499
504
|
--wave-teal-950: oklch(0.197 0.037 222.5);
|
|
500
505
|
/* Graphite */
|
|
501
|
-
--graphite-50: oklch(0.964 0.001 278.
|
|
502
|
-
--graphite-100: oklch(0.
|
|
503
|
-
--graphite-200: oklch(0.
|
|
504
|
-
--graphite-300: oklch(0.
|
|
505
|
-
--graphite-400: oklch(0.
|
|
506
|
-
--graphite-500: oklch(0.
|
|
507
|
-
--graphite-600: oklch(0.
|
|
508
|
-
--graphite-700: oklch(0.
|
|
509
|
-
--graphite-800: oklch(0.
|
|
510
|
-
--graphite-900: oklch(0.
|
|
511
|
-
--graphite-950: oklch(0.
|
|
506
|
+
--graphite-50: oklch(0.964 0.001 278.3);
|
|
507
|
+
--graphite-100: oklch(0.912 0.003 278.3);
|
|
508
|
+
--graphite-200: oklch(0.842 0.007 278.3);
|
|
509
|
+
--graphite-300: oklch(0.761 0.009 278.3);
|
|
510
|
+
--graphite-400: oklch(0.683 0.011 278.3);
|
|
511
|
+
--graphite-500: oklch(0.595 0.013 278.3);
|
|
512
|
+
--graphite-600: oklch(0.506 0.014 278.3);
|
|
513
|
+
--graphite-700: oklch(0.424 0.014 278.3);
|
|
514
|
+
--graphite-800: oklch(0.359 0.012 278.3);
|
|
515
|
+
--graphite-900: oklch(0.322 0.011 278.3);
|
|
516
|
+
--graphite-950: oklch(0.283 0.009 278.3);
|
|
512
517
|
/* Ink */
|
|
513
518
|
--ink-50: oklch(0.966 0.003 248);
|
|
514
519
|
--ink-100: oklch(0.906 0.007 265);
|
|
@@ -546,8 +551,8 @@
|
|
|
546
551
|
* dark system as on a light one. A pinned theme class still beats both.
|
|
547
552
|
*
|
|
548
553
|
* The page and popups are white; cards and the sidebar sit on the 50, a faint
|
|
549
|
-
* warm tint, so
|
|
550
|
-
* text colour, the 950, made translucent, as in every theme.
|
|
554
|
+
* warm tint, so their edge does most of the separating. Lines and fills are
|
|
555
|
+
* its text colour, the 950, made translucent, as in every theme.
|
|
551
556
|
* ------------------------------------------------------------------------- */
|
|
552
557
|
:where(:root),
|
|
553
558
|
.paper {
|
|
@@ -556,11 +561,13 @@
|
|
|
556
561
|
--elevated: white;
|
|
557
562
|
--contrast: var(--paper-950);
|
|
558
563
|
--muted: var(--paper-600);
|
|
559
|
-
--
|
|
564
|
+
--subtle: var(--paper-500);
|
|
560
565
|
--secondary: var(--paper-100);
|
|
561
|
-
--
|
|
562
|
-
--
|
|
563
|
-
--
|
|
566
|
+
--line: color-mix(in srgb, var(--paper-950) 5%, transparent);
|
|
567
|
+
--edge: color-mix(in srgb, var(--paper-950) 10%, transparent);
|
|
568
|
+
--contour: color-mix(in srgb, var(--paper-950) 15%, transparent);
|
|
569
|
+
--highlighted: color-mix(in srgb, var(--paper-950) 10%, transparent);
|
|
570
|
+
--neutral: color-mix(in srgb, var(--paper-950) 15%, transparent);
|
|
564
571
|
--shadow-strength: 0.055;
|
|
565
572
|
--danger: var(--wave-red-500);
|
|
566
573
|
--danger-text: var(--wave-red-600);
|
|
@@ -589,20 +596,22 @@
|
|
|
589
596
|
--elevated: var(--graphite-800);
|
|
590
597
|
--contrast: var(--graphite-50);
|
|
591
598
|
--muted: var(--graphite-300);
|
|
592
|
-
--
|
|
599
|
+
--subtle: var(--graphite-500);
|
|
593
600
|
--secondary: var(--graphite-700);
|
|
594
|
-
--
|
|
595
|
-
--
|
|
596
|
-
--
|
|
601
|
+
--line: color-mix(in srgb, var(--graphite-50) 5%, transparent);
|
|
602
|
+
--edge: color-mix(in srgb, var(--graphite-50) 10%, transparent);
|
|
603
|
+
--contour: color-mix(in srgb, var(--graphite-50) 15%, transparent);
|
|
604
|
+
--highlighted: color-mix(in srgb, var(--graphite-50) 10%, transparent);
|
|
605
|
+
--neutral: color-mix(in srgb, var(--graphite-50) 15%, transparent);
|
|
597
606
|
--shadow-strength: 0.045;
|
|
598
607
|
--danger: var(--wave-red-500);
|
|
599
|
-
--danger-text: oklch(0.
|
|
608
|
+
--danger-text: oklch(0.749 0.152 16.8); /* #FF828B, see below */
|
|
600
609
|
--success: var(--wave-green-500);
|
|
601
|
-
--success-text: oklch(0.
|
|
610
|
+
--success-text: oklch(0.712 0.161 160); /* #00C07E, see below */
|
|
602
611
|
--warning: var(--wave-orange-500);
|
|
603
|
-
--warning-text: oklch(0.
|
|
612
|
+
--warning-text: oklch(0.745 0.179 57.3); /* #FE8A04, see below */
|
|
604
613
|
--info: var(--wave-blue-500);
|
|
605
|
-
--info-text: oklch(0.
|
|
614
|
+
--info-text: oklch(0.730 0.145 250.4); /* #5AADFF, see below */
|
|
606
615
|
}
|
|
607
616
|
}
|
|
608
617
|
|
|
@@ -612,20 +621,22 @@
|
|
|
612
621
|
--elevated: var(--graphite-800);
|
|
613
622
|
--contrast: var(--graphite-50);
|
|
614
623
|
--muted: var(--graphite-300);
|
|
615
|
-
--
|
|
624
|
+
--subtle: var(--graphite-500);
|
|
616
625
|
--secondary: var(--graphite-700);
|
|
617
|
-
--
|
|
618
|
-
--
|
|
619
|
-
--
|
|
626
|
+
--line: color-mix(in srgb, var(--graphite-50) 5%, transparent);
|
|
627
|
+
--edge: color-mix(in srgb, var(--graphite-50) 10%, transparent);
|
|
628
|
+
--contour: color-mix(in srgb, var(--graphite-50) 15%, transparent);
|
|
629
|
+
--highlighted: color-mix(in srgb, var(--graphite-50) 10%, transparent);
|
|
630
|
+
--neutral: color-mix(in srgb, var(--graphite-50) 15%, transparent);
|
|
620
631
|
--shadow-strength: 0.045;
|
|
621
632
|
--danger: var(--wave-red-500);
|
|
622
|
-
--danger-text: oklch(0.
|
|
633
|
+
--danger-text: oklch(0.749 0.152 16.8); /* #FF828B, see below */
|
|
623
634
|
--success: var(--wave-green-500);
|
|
624
|
-
--success-text: oklch(0.
|
|
635
|
+
--success-text: oklch(0.712 0.161 160); /* #00C07E, see below */
|
|
625
636
|
--warning: var(--wave-orange-500);
|
|
626
|
-
--warning-text: oklch(0.
|
|
637
|
+
--warning-text: oklch(0.745 0.179 57.3); /* #FE8A04, see below */
|
|
627
638
|
--info: var(--wave-blue-500);
|
|
628
|
-
--info-text: oklch(0.
|
|
639
|
+
--info-text: oklch(0.730 0.145 250.4); /* #5AADFF, see below */
|
|
629
640
|
}
|
|
630
641
|
|
|
631
642
|
/* Graphite's status text. Its mid-tone menus need each status a touch lighter
|
|
@@ -636,19 +647,19 @@
|
|
|
636
647
|
* palette steps. */
|
|
637
648
|
@media (color-gamut: p3) {
|
|
638
649
|
.graphite {
|
|
639
|
-
--danger-text: oklch(0.
|
|
640
|
-
--success-text: oklch(0.
|
|
641
|
-
--warning-text: oklch(0.
|
|
642
|
-
--info-text: oklch(0.
|
|
650
|
+
--danger-text: oklch(0.755 0.190 16.8);
|
|
651
|
+
--success-text: oklch(0.705 0.219 160);
|
|
652
|
+
--warning-text: oklch(0.748 0.205 57.3);
|
|
653
|
+
--info-text: oklch(0.730 0.157 250.4);
|
|
643
654
|
}
|
|
644
655
|
}
|
|
645
656
|
|
|
646
657
|
@media (prefers-color-scheme: dark) and (color-gamut: p3) {
|
|
647
658
|
:where(:root:not(.paper):not(.graphite):not(.ink)) {
|
|
648
|
-
--danger-text: oklch(0.
|
|
649
|
-
--success-text: oklch(0.
|
|
650
|
-
--warning-text: oklch(0.
|
|
651
|
-
--info-text: oklch(0.
|
|
659
|
+
--danger-text: oklch(0.755 0.190 16.8);
|
|
660
|
+
--success-text: oklch(0.705 0.219 160);
|
|
661
|
+
--warning-text: oklch(0.748 0.205 57.3);
|
|
662
|
+
--info-text: oklch(0.730 0.157 250.4);
|
|
652
663
|
}
|
|
653
664
|
}
|
|
654
665
|
|
|
@@ -664,11 +675,13 @@
|
|
|
664
675
|
--elevated: var(--ink-800);
|
|
665
676
|
--contrast: var(--ink-50);
|
|
666
677
|
--muted: var(--ink-400);
|
|
667
|
-
--
|
|
678
|
+
--subtle: var(--ink-600);
|
|
668
679
|
--secondary: var(--ink-700);
|
|
669
|
-
--
|
|
670
|
-
--
|
|
671
|
-
--
|
|
680
|
+
--line: color-mix(in srgb, var(--ink-50) 5%, transparent);
|
|
681
|
+
--edge: color-mix(in srgb, var(--ink-50) 10%, transparent);
|
|
682
|
+
--contour: color-mix(in srgb, var(--ink-50) 15%, transparent);
|
|
683
|
+
--highlighted: color-mix(in srgb, var(--ink-50) 10%, transparent);
|
|
684
|
+
--neutral: color-mix(in srgb, var(--ink-50) 15%, transparent);
|
|
672
685
|
--shadow-strength: 0.045;
|
|
673
686
|
--danger: var(--wave-red-500);
|
|
674
687
|
--danger-text: var(--wave-red-400);
|
|
@@ -683,7 +696,7 @@
|
|
|
683
696
|
/* ---------------------------------------------------------------------------
|
|
684
697
|
* Tailwind v4 theme mapping — maps CSS variables to Tailwind color tokens.
|
|
685
698
|
* Consumers MUST include this for Tailwind classes like `bg-primary`,
|
|
686
|
-
* `text-muted`, `border-
|
|
699
|
+
* `text-muted`, `border-line` etc. to work.
|
|
687
700
|
* ------------------------------------------------------------------------- */
|
|
688
701
|
|
|
689
702
|
@theme inline {
|
|
@@ -692,10 +705,10 @@
|
|
|
692
705
|
--color-surface: var(--surface);
|
|
693
706
|
--color-elevated: var(--elevated);
|
|
694
707
|
|
|
695
|
-
/* Contrast / text — `contrast`
|
|
708
|
+
/* Contrast / text, strongest to faintest — `contrast` → `muted` → `subtle`. */
|
|
696
709
|
--color-contrast: var(--contrast);
|
|
697
710
|
--color-muted: var(--muted);
|
|
698
|
-
--color-
|
|
711
|
+
--color-subtle: var(--subtle);
|
|
699
712
|
|
|
700
713
|
/* Inverse — maps the `:root` inverse aliases to utilities. */
|
|
701
714
|
--color-surface-inverse: var(--surface-inverse);
|
|
@@ -706,20 +719,27 @@
|
|
|
706
719
|
--color-primary: var(--primary);
|
|
707
720
|
--color-secondary: var(--secondary);
|
|
708
721
|
--color-accent: var(--accent);
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
*
|
|
722
|
+
--color-selected: var(--selected);
|
|
723
|
+
|
|
724
|
+
/* Lines and fills — the theme's text colour made translucent (Graphite's
|
|
725
|
+
* and Ink's 50, Paper's 950), so each reads the same on any surface beneath
|
|
726
|
+
* it. Every theme uses the same strengths.
|
|
727
|
+
* Lines, one job each: `line` (5%) divides: separators, table rows,
|
|
728
|
+
* hairlines. `edge` (10%) bounds a surface: cards, dialogs, popups, toasts,
|
|
729
|
+
* always as a border (rings are kept for focus and invalid halos).
|
|
730
|
+
* `contour` (15%) outlines a control or a region: outline buttons, badges,
|
|
731
|
+
* toggles, the slider thumb, menubars.
|
|
732
|
+
* Fills, one job each: `highlighted` (10%) marks where attention lands:
|
|
733
|
+
* hovered, keyboard-highlighted and open items. `neutral` (15%) gives a
|
|
734
|
+
* control its body, its look before anything is chosen: field and track
|
|
735
|
+
* fills, unchecked boxes. (Tailwind's own `neutral-50` … `neutral-950`
|
|
736
|
+
* greys are a separate palette Wave doesn't use.) `focus` is the
|
|
737
|
+
* brand-themed ring (= primary). */
|
|
738
|
+
--color-line: var(--line);
|
|
739
|
+
--color-edge: var(--edge);
|
|
720
740
|
--color-contour: var(--contour);
|
|
721
|
-
--color-
|
|
722
|
-
--color-
|
|
741
|
+
--color-highlighted: var(--highlighted);
|
|
742
|
+
--color-neutral: var(--neutral);
|
|
723
743
|
--color-focus: var(--focus);
|
|
724
744
|
--color-scrim: var(--scrim);
|
|
725
745
|
|
|
@@ -813,6 +833,81 @@
|
|
|
813
833
|
}
|
|
814
834
|
}
|
|
815
835
|
|
|
836
|
+
/* `scroll-fade` — fades the edges of anything that scrolls, where there is
|
|
837
|
+
* more to scroll. It's a mask, so the content itself turns transparent and
|
|
838
|
+
* whatever is behind shows through: no colour to match, in any theme. Each
|
|
839
|
+
* fade grows with the first 2.5rem of scroll and shrinks over the last, so it
|
|
840
|
+
* never pops in. Two things drive it, so it works on any scroller:
|
|
841
|
+
* - the element's own scroll position, through scroll-driven animations
|
|
842
|
+
* (Chrome, Edge, Safari 26+): a Combobox list, a plain `overflow-auto` box;
|
|
843
|
+
* - ScrollArea, which reports how far each edge is (`--scroll-area-overflow-*`),
|
|
844
|
+
* so its viewport fades in every browser, Firefox included.
|
|
845
|
+
* A plain scroller in a browser without scroll-driven animations (Firefox,
|
|
846
|
+
* for now) simply doesn't fade. `--scroll-fade-size` sets the length, up to a
|
|
847
|
+
* quarter of the box; the horizontal fade follows the text direction. */
|
|
848
|
+
@property --scroll-fade-top { syntax: "<length>"; inherits: false; initial-value: 0px; }
|
|
849
|
+
@property --scroll-fade-bottom { syntax: "<length>"; inherits: false; initial-value: 0px; }
|
|
850
|
+
@property --scroll-fade-start { syntax: "<length>"; inherits: false; initial-value: 0px; }
|
|
851
|
+
@property --scroll-fade-end { syntax: "<length>"; inherits: false; initial-value: 0px; }
|
|
852
|
+
@utility scroll-fade {
|
|
853
|
+
--scroll-fade-x: to right;
|
|
854
|
+
--scroll-fade-top: min(var(--scroll-fade-size, 2.5rem), var(--scroll-area-overflow-y-start, 0px));
|
|
855
|
+
--scroll-fade-bottom: min(var(--scroll-fade-size, 2.5rem), var(--scroll-area-overflow-y-end, 0px));
|
|
856
|
+
--scroll-fade-start: min(var(--scroll-fade-size, 2.5rem), var(--scroll-area-overflow-x-start, 0px));
|
|
857
|
+
--scroll-fade-end: min(var(--scroll-fade-size, 2.5rem), var(--scroll-area-overflow-x-end, 0px));
|
|
858
|
+
/* Controls laid over an edge (Select's scroll arrows) set
|
|
859
|
+
* `--scroll-fade-inset` to their height: the fade then starts where they
|
|
860
|
+
* end, only while that edge is fading. */
|
|
861
|
+
--scroll-fade-inset-top: min(var(--scroll-fade-inset, 0px), var(--scroll-fade-top) * 1000);
|
|
862
|
+
--scroll-fade-inset-bottom: min(var(--scroll-fade-inset, 0px), var(--scroll-fade-bottom) * 1000);
|
|
863
|
+
/* Each fade at most a quarter of the box, so a short list still keeps a
|
|
864
|
+
* row clear between its two fades. */
|
|
865
|
+
--scroll-fade-top-size: min(var(--scroll-fade-top), 25%);
|
|
866
|
+
--scroll-fade-bottom-size: min(var(--scroll-fade-bottom), 25%);
|
|
867
|
+
--scroll-fade-start-size: min(var(--scroll-fade-start), 25%);
|
|
868
|
+
--scroll-fade-end-size: min(var(--scroll-fade-end), 25%);
|
|
869
|
+
mask-image:
|
|
870
|
+
linear-gradient(to bottom, transparent var(--scroll-fade-inset-top), #000 calc(var(--scroll-fade-inset-top) + var(--scroll-fade-top-size)), #000 calc(100% - var(--scroll-fade-inset-bottom) - var(--scroll-fade-bottom-size)), transparent calc(100% - var(--scroll-fade-inset-bottom))),
|
|
871
|
+
linear-gradient(var(--scroll-fade-x), transparent, #000 var(--scroll-fade-start-size), #000 calc(100% - var(--scroll-fade-end-size)), transparent);
|
|
872
|
+
mask-composite: intersect;
|
|
873
|
+
/* What's scrolled into view (an option picked with the arrow keys) stops
|
|
874
|
+
* clear of whatever is faded at that moment, and nowhere is padded where
|
|
875
|
+
* nothing fades (Firefox's plain lists, an edge scrolled to its end). */
|
|
876
|
+
scroll-padding-block:
|
|
877
|
+
calc(var(--scroll-fade-inset-top) + var(--scroll-fade-top-size))
|
|
878
|
+
calc(var(--scroll-fade-inset-bottom) + var(--scroll-fade-bottom-size));
|
|
879
|
+
@variant rtl {
|
|
880
|
+
--scroll-fade-x: to left;
|
|
881
|
+
}
|
|
882
|
+
@supports (animation-timeline: scroll()) {
|
|
883
|
+
animation-name: scroll-fade-top, scroll-fade-bottom, scroll-fade-start, scroll-fade-end;
|
|
884
|
+
animation-timing-function: linear;
|
|
885
|
+
animation-fill-mode: both;
|
|
886
|
+
animation-timeline: scroll(self block), scroll(self block), scroll(self inline), scroll(self inline);
|
|
887
|
+
animation-range:
|
|
888
|
+
0 var(--scroll-fade-size, 2.5rem),
|
|
889
|
+
calc(100% - var(--scroll-fade-size, 2.5rem)) 100%,
|
|
890
|
+
0 var(--scroll-fade-size, 2.5rem),
|
|
891
|
+
calc(100% - var(--scroll-fade-size, 2.5rem)) 100%;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
@keyframes scroll-fade-top {
|
|
895
|
+
from { --scroll-fade-top: 0px; }
|
|
896
|
+
to { --scroll-fade-top: var(--scroll-fade-size, 2.5rem); }
|
|
897
|
+
}
|
|
898
|
+
@keyframes scroll-fade-bottom {
|
|
899
|
+
from { --scroll-fade-bottom: var(--scroll-fade-size, 2.5rem); }
|
|
900
|
+
to { --scroll-fade-bottom: 0px; }
|
|
901
|
+
}
|
|
902
|
+
@keyframes scroll-fade-start {
|
|
903
|
+
from { --scroll-fade-start: 0px; }
|
|
904
|
+
to { --scroll-fade-start: var(--scroll-fade-size, 2.5rem); }
|
|
905
|
+
}
|
|
906
|
+
@keyframes scroll-fade-end {
|
|
907
|
+
from { --scroll-fade-end: var(--scroll-fade-size, 2.5rem); }
|
|
908
|
+
to { --scroll-fade-end: 0px; }
|
|
909
|
+
}
|
|
910
|
+
|
|
816
911
|
/* `motion-color` — interaction-state transition for controls: smoothly
|
|
817
912
|
* animates color / background / border / ring (box-shadow) / backdrop blur on hover, focus,
|
|
818
913
|
* pressed, checked, etc. Runs at the `sm` tier (controls are small + fast). A
|
|
@@ -1160,3 +1255,22 @@
|
|
|
1160
1255
|
0%, 70%, 100% { opacity: 1; }
|
|
1161
1256
|
20%, 50% { opacity: 0; }
|
|
1162
1257
|
}
|
|
1258
|
+
|
|
1259
|
+
/* ---------------------------------------------------------------------------
|
|
1260
|
+
* SwipeDeck — the numbers each card works out its place from change every
|
|
1261
|
+
* frame of a drag (the cards behind lift toward the front). Unregistered,
|
|
1262
|
+
* custom properties inherit, so each change would restyle everything inside
|
|
1263
|
+
* the cards in sight; registered as not inheriting, it stops at the card.
|
|
1264
|
+
* Measured with heavy cards: about 2.5x less style work in Chromium, and
|
|
1265
|
+
* WebKit back to 60 fps from about 30. The card's public hooks
|
|
1266
|
+
* (`--swipe-deck-progress`, `-movement-x`/`-y`, `-place`, `-index`) still
|
|
1267
|
+
* inherit, so what's inside a card can read them. */
|
|
1268
|
+
@property --swipe-deck-lift { syntax: "*"; inherits: false; }
|
|
1269
|
+
@property --swipe-deck-slot { syntax: "*"; inherits: false; }
|
|
1270
|
+
@property --swipe-deck-layout-slot { syntax: "*"; inherits: false; }
|
|
1271
|
+
@property --swipe-deck-layout-x { syntax: "*"; inherits: false; }
|
|
1272
|
+
@property --swipe-deck-layout-y { syntax: "*"; inherits: false; }
|
|
1273
|
+
@property --swipe-deck-layout-rotate { syntax: "*"; inherits: false; }
|
|
1274
|
+
@property --swipe-deck-layout-scale { syntax: "*"; inherits: false; }
|
|
1275
|
+
@property --swipe-deck-enter-scale { syntax: "*"; inherits: false; }
|
|
1276
|
+
@property --swipe-deck-pose { syntax: "*"; inherits: false; }
|
package/dist/swipe-deck.d.ts
CHANGED
|
@@ -1,28 +1,66 @@
|
|
|
1
1
|
import { ButtonProps } from "./button.js";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
//#region src/swipe-deck.d.ts
|
|
4
|
-
type
|
|
4
|
+
type SwipeDeckDirection = "left" | "right" | "up" | "down";
|
|
5
5
|
type SwipeDeckLayout = "stack" | "fan" | "cascade" | "pile";
|
|
6
6
|
interface SwipeDeckSwipeDetails {
|
|
7
|
-
/** The `value` of the card
|
|
7
|
+
/** The `value` of the card. */
|
|
8
8
|
value: string;
|
|
9
|
-
/** The direction it
|
|
10
|
-
direction:
|
|
9
|
+
/** The direction it leaves in. */
|
|
10
|
+
direction: SwipeDeckDirection;
|
|
11
11
|
}
|
|
12
|
+
/** What sent a card off: a drag or throw, an arrow key, or a `SwipeDeckAction`. */
|
|
13
|
+
type SwipeDeckSwipeEventReason = SwipeDeckSwipeCause["reason"];
|
|
14
|
+
type SwipeDeckSwipeCause = {
|
|
15
|
+
reason: "swipe";
|
|
16
|
+
event: PointerEvent;
|
|
17
|
+
} | {
|
|
18
|
+
reason: "keyboard";
|
|
19
|
+
event: KeyboardEvent;
|
|
20
|
+
} | {
|
|
21
|
+
reason: "action-press";
|
|
22
|
+
event: MouseEvent;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* `onSwipe`'s second argument: the reason and native event behind a swipe, and
|
|
26
|
+
* a way to cancel it. The parts of Base UI's own event details that apply.
|
|
27
|
+
*/
|
|
28
|
+
type SwipeDeckSwipeEventDetails = SwipeDeckSwipeCause & {
|
|
29
|
+
/**
|
|
30
|
+
* Keeps the card in front: a dragged card springs back, and a key or
|
|
31
|
+
* action does nothing.
|
|
32
|
+
*/
|
|
33
|
+
cancel: () => void;
|
|
34
|
+
/** Whether `cancel` has been called. */
|
|
35
|
+
readonly isCanceled: boolean;
|
|
36
|
+
};
|
|
12
37
|
type SwipeDeckProps = React.ComponentProps<"div"> & {
|
|
13
38
|
/**
|
|
14
|
-
* Called
|
|
15
|
-
*
|
|
39
|
+
* Called the moment a card is sent off, before it leaves: count it here, or
|
|
40
|
+
* call `eventDetails.cancel()` to keep it in front. To cycle the deck, move
|
|
41
|
+
* the card to the end of your list here, and it slides back under the pile.
|
|
42
|
+
* Don't remove it here: it would vanish mid-exit, and `onSwipeComplete`
|
|
43
|
+
* would never come.
|
|
16
44
|
*/
|
|
17
|
-
onSwipe?: (details: SwipeDeckSwipeDetails) => void;
|
|
45
|
+
onSwipe?: (details: SwipeDeckSwipeDetails, eventDetails: SwipeDeckSwipeEventDetails) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Called once a card is done leaving: faded out, or (moved to the back in
|
|
48
|
+
* `onSwipe`) on its way under the pile. Remove it from your list here; a
|
|
49
|
+
* card your list keeps comes back, in front or wherever you moved it.
|
|
50
|
+
* Return a promise, such as a save, to keep a faded card out until it
|
|
51
|
+
* settles; a card sliding under the pile is back already.
|
|
52
|
+
*/
|
|
53
|
+
onSwipeComplete?: (details: SwipeDeckSwipeDetails) => void | Promise<unknown>;
|
|
18
54
|
/** The directions a card can leave in. Defaults to left and right. */
|
|
19
|
-
directions?: readonly
|
|
55
|
+
directions?: readonly SwipeDeckDirection[];
|
|
20
56
|
/** Stops cards leaving by pointer, keyboard or action. */
|
|
21
57
|
disabled?: boolean;
|
|
22
58
|
/**
|
|
23
59
|
* How the cards behind the front one sit: `stack` peeks them above it, `fan`
|
|
24
60
|
* turns them out like a hand of cards, `cascade` steps them up and to the
|
|
25
|
-
* side, and `pile` scatters them. Defaults to `
|
|
61
|
+
* side, and `pile` scatters them. Defaults to `fan`. `fan` and `cascade`
|
|
62
|
+
* open toward the end of the line: right in left-to-right text, left in
|
|
63
|
+
* right-to-left.
|
|
26
64
|
*/
|
|
27
65
|
layout?: SwipeDeckLayout;
|
|
28
66
|
/** How far the cards behind spread out, from 0 (not at all) to 2. Defaults to 0.5. */
|
|
@@ -33,49 +71,67 @@ type SwipeDeckProps = React.ComponentProps<"div"> & {
|
|
|
33
71
|
visible?: number;
|
|
34
72
|
};
|
|
35
73
|
type SwipeDeckItemProps = React.ComponentProps<"div"> & {
|
|
36
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Names the card in `onSwipe`. Use the same id as its `key`, unique among
|
|
76
|
+
* the deck's cards, those still leaving included: a card dealt again is a
|
|
77
|
+
* new card and needs a new value.
|
|
78
|
+
*/
|
|
37
79
|
value: string;
|
|
38
80
|
};
|
|
39
81
|
type SwipeDeckEmptyProps = React.ComponentProps<"div">;
|
|
40
82
|
type SwipeDeckActionProps = ButtonProps & {
|
|
41
83
|
/** The direction the front card leaves in when pressed. */
|
|
42
|
-
direction:
|
|
84
|
+
direction: SwipeDeckDirection;
|
|
43
85
|
};
|
|
44
86
|
/**
|
|
45
87
|
* A pile of cards people swipe away: drag or throw the front card, press an
|
|
46
88
|
* arrow key while the deck is focused, or use a `SwipeDeckAction`. A let-go
|
|
47
|
-
* card whose position and throw carry it past a quarter of its width
|
|
48
|
-
*
|
|
89
|
+
* card whose position and throw carry it past a quarter of its width (or of
|
|
90
|
+
* its height, up and down) leaves:
|
|
91
|
+
* it slides out the way it is heading until clear of the pile, held by a
|
|
49
92
|
* spring that a hard throw runs out against, then fades. Short of that, it
|
|
50
|
-
* springs back.
|
|
51
|
-
*
|
|
93
|
+
* springs back. Pressed, a card lifts under the pointer; dragged, it tilts
|
|
94
|
+
* with the throw.
|
|
95
|
+
*
|
|
96
|
+
* Your list stays the source of truth. `onSwipe` comes the moment a card is
|
|
97
|
+
* sent off: count it there, or cancel to keep it. `onSwipeComplete` comes once
|
|
98
|
+
* it has gone: remove it from your list then, not in `onSwipe`, where removing
|
|
99
|
+
* it would cut its exit short. To cycle the deck instead, move the card to
|
|
100
|
+
* the end of your list in `onSwipe`, and it slides back under the pile. To
|
|
101
|
+
* undo a swipe, put the card back at the start of your list.
|
|
102
|
+
*
|
|
103
|
+
* The cards are the deck's own children, in your list's order. A long list
|
|
104
|
+
* needn't be rendered whole: the deck shows `visible` cards, so the next few
|
|
105
|
+
* dozen are plenty.
|
|
52
106
|
*
|
|
53
107
|
* End the deck with a `SwipeDeckEmpty`: it lies under the last card, so
|
|
54
|
-
* dragging that card shows what comes next.
|
|
55
|
-
*
|
|
56
|
-
*
|
|
108
|
+
* dragging that card shows what comes next.
|
|
109
|
+
*
|
|
110
|
+
* Styling hooks: `data-layout`, `data-disabled`, and `data-empty` once no
|
|
111
|
+
* card is in front (the last one leaving, or none left). CSS variables:
|
|
112
|
+
* `--swipe-deck-card-width` / `-height`, the size of the largest card.
|
|
57
113
|
*
|
|
58
114
|
* Give the deck an `aria-label`. Screen readers hear the next card after each
|
|
59
115
|
* swipe: its `aria-label` when it has one, otherwise all of its text.
|
|
60
116
|
*/
|
|
61
|
-
declare function SwipeDeck({ onSwipe, directions, disabled, layout, spread, depth, visible, className, style, onKeyDown, children, ref, ...props }: SwipeDeckProps): React.JSX.Element;
|
|
117
|
+
declare function SwipeDeck({ onSwipe, onSwipeComplete, directions, disabled, layout, spread, depth, visible, className, style, onKeyDown, children, ref, ...props }: SwipeDeckProps): React.JSX.Element;
|
|
62
118
|
/**
|
|
63
|
-
* One card in the deck. It sits in the deck's first grid
|
|
64
|
-
* card, so the deck takes the size of its largest card.
|
|
119
|
+
* One card in the deck, a direct child of it. It sits in the deck's first grid
|
|
120
|
+
* cell with every other card, so the deck takes the size of its largest card.
|
|
65
121
|
*
|
|
66
122
|
* Styling hooks: `data-front` on the top card, `data-swiping` while it is
|
|
67
|
-
* dragged, `data-leaving` from the moment it leaves, `data-
|
|
68
|
-
* it
|
|
69
|
-
* `data-swipe-direction` for the
|
|
70
|
-
*
|
|
71
|
-
* `--swipe-deck-
|
|
72
|
-
*
|
|
123
|
+
* dragged, `data-leaving` from the moment it leaves, `data-starting-style`
|
|
124
|
+
* while it comes in and `data-ending-style` once it is clear of the pile and
|
|
125
|
+
* fading (the `motion-fade-lg` recipe), and `data-swipe-direction` for the
|
|
126
|
+
* way it leans or leaves. CSS variables, which what's inside the card can
|
|
127
|
+
* read too: `--swipe-deck-index` (its place in the pile, 0 at the front),
|
|
128
|
+
* `--swipe-deck-place` (that place as it springs from one to the next),
|
|
73
129
|
* `--swipe-deck-movement-x` / `-y` in px, and `--swipe-deck-progress` from 0
|
|
74
130
|
* at rest to 1 where letting go makes the card leave.
|
|
75
131
|
*
|
|
76
|
-
* The card owns its translate, rotate and
|
|
77
|
-
* be a `motion-fade-*` one: a recipe that transitions those
|
|
78
|
-
* drag.
|
|
132
|
+
* The card owns its translate, rotate, scale and transform, so its motion
|
|
133
|
+
* recipe can only be a `motion-fade-*` one: a recipe that transitions those
|
|
134
|
+
* would lag every drag.
|
|
79
135
|
*/
|
|
80
136
|
declare function SwipeDeckItem({ value, className, style, ref, onPointerDown, onClickCapture, onDragStart, ...props }: SwipeDeckItemProps): React.JSX.Element;
|
|
81
137
|
/**
|
|
@@ -84,15 +140,15 @@ declare function SwipeDeckItem({ value, className, style, ref, onPointerDown, on
|
|
|
84
140
|
* their size, inside a dashed outline of their shape (`data-slot`
|
|
85
141
|
* `swipe-deck-empty-outline`, to restyle or hide). It is drawn as soon as one
|
|
86
142
|
* card is left and has come to rest, under that card, so dragging it shows
|
|
87
|
-
* what comes next; it
|
|
88
|
-
*
|
|
89
|
-
* or its text) once that last card has gone too.
|
|
143
|
+
* what comes next; it can be reached (Tab, clicks) and screen readers hear it
|
|
144
|
+
* (its `aria-label`, or its text) once that last card has gone too.
|
|
90
145
|
*/
|
|
91
146
|
declare function SwipeDeckEmpty({ className, children, ref, ...props }: SwipeDeckEmptyProps): React.JSX.Element;
|
|
92
147
|
/**
|
|
93
148
|
* A button that sends the front card off in `direction`: the way to swipe
|
|
94
|
-
* without dragging. Disabled when the deck is
|
|
149
|
+
* without dragging. Disabled (and still focusable) when the deck is disabled,
|
|
150
|
+
* has no card in front, or can't go that way.
|
|
95
151
|
*/
|
|
96
|
-
declare function SwipeDeckAction({ direction, disabled, onClick, ...props }: SwipeDeckActionProps): React.JSX.Element;
|
|
152
|
+
declare function SwipeDeckAction({ direction, disabled, onClick, onKeyDown, ...props }: SwipeDeckActionProps): React.JSX.Element;
|
|
97
153
|
//#endregion
|
|
98
|
-
export { SwipeDeck, SwipeDeckAction, type SwipeDeckActionProps, SwipeDeckEmpty, type SwipeDeckEmptyProps, SwipeDeckItem, type SwipeDeckItemProps, type SwipeDeckLayout, type SwipeDeckProps, type SwipeDeckSwipeDetails, type
|
|
154
|
+
export { SwipeDeck, SwipeDeckAction, type SwipeDeckActionProps, type SwipeDeckDirection, SwipeDeckEmpty, type SwipeDeckEmptyProps, SwipeDeckItem, type SwipeDeckItemProps, type SwipeDeckLayout, type SwipeDeckProps, type SwipeDeckSwipeDetails, type SwipeDeckSwipeEventDetails, type SwipeDeckSwipeEventReason };
|