@evinvest/uikit 0.18.0 → 0.20.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 +210 -13
- package/dist/chunk-3IPB4QQJ.js +306 -0
- package/dist/chunk-3IPB4QQJ.js.map +1 -0
- package/dist/components/accordion.js +136 -0
- package/dist/components/accordion.js.map +1 -0
- package/dist/components/alert-dialog.js +175 -0
- package/dist/components/alert-dialog.js.map +1 -0
- package/dist/components/alert.js +49 -0
- package/dist/components/alert.js.map +1 -0
- package/dist/components/avatar.js +54 -0
- package/dist/components/avatar.js.map +1 -0
- package/dist/components/badge.js +25 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/band.js +75 -0
- package/dist/components/band.js.map +1 -0
- package/dist/components/breadcrumb.js +132 -0
- package/dist/components/breadcrumb.js.map +1 -0
- package/dist/components/button-group.js +61 -0
- package/dist/components/button-group.js.map +1 -0
- package/dist/components/button.js +55 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/calendar.js +226 -0
- package/dist/components/calendar.js.map +1 -0
- package/dist/components/card.js +98 -0
- package/dist/components/card.js.map +1 -0
- package/dist/components/carousel.js +262 -0
- package/dist/components/carousel.js.map +1 -0
- package/dist/components/chart.js +151 -0
- package/dist/components/chart.js.map +1 -0
- package/dist/components/checkbox.js +68 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/collapsible.js +60 -0
- package/dist/components/collapsible.js.map +1 -0
- package/dist/components/command.js +274 -0
- package/dist/components/command.js.map +1 -0
- package/dist/components/container.js +18 -0
- package/dist/components/container.js.map +1 -0
- package/dist/components/context-menu.js +337 -0
- package/dist/components/context-menu.js.map +1 -0
- package/dist/components/date-time-picker.js +301 -0
- package/dist/components/date-time-picker.js.map +1 -0
- package/dist/components/dialog.js +207 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/drawer.js +351 -0
- package/dist/components/drawer.js.map +1 -0
- package/dist/components/dropdown-menu.js +356 -0
- package/dist/components/dropdown-menu.js.map +1 -0
- package/dist/components/empty.js +91 -0
- package/dist/components/empty.js.map +1 -0
- package/dist/components/field-context.js +30 -0
- package/dist/components/field-context.js.map +1 -0
- package/dist/components/field.js +216 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/footer.js +89 -0
- package/dist/components/footer.js.map +1 -0
- package/dist/components/form.js +101 -0
- package/dist/components/form.js.map +1 -0
- package/dist/components/hover-card.js +90 -0
- package/dist/components/hover-card.js.map +1 -0
- package/dist/components/info-tip.js +161 -0
- package/dist/components/info-tip.js.map +1 -0
- package/dist/components/input-group.js +124 -0
- package/dist/components/input-group.js.map +1 -0
- package/dist/components/input-otp.js +120 -0
- package/dist/components/input-otp.js.map +1 -0
- package/dist/components/input.js +26 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/item.js +167 -0
- package/dist/components/item.js.map +1 -0
- package/dist/components/kbd.js +29 -0
- package/dist/components/kbd.js.map +1 -0
- package/dist/components/label.js +11 -0
- package/dist/components/label.js.map +1 -0
- package/dist/components/logo.js +41 -0
- package/dist/components/logo.js.map +1 -0
- package/dist/components/menubar.js +330 -0
- package/dist/components/menubar.js.map +1 -0
- package/dist/components/native-select.js +62 -0
- package/dist/components/native-select.js.map +1 -0
- package/dist/components/navigation-menu.js +204 -0
- package/dist/components/navigation-menu.js.map +1 -0
- package/dist/components/pagination.js +138 -0
- package/dist/components/pagination.js.map +1 -0
- package/dist/components/popover.js +104 -0
- package/dist/components/popover.js.map +1 -0
- package/dist/components/progress.js +30 -0
- package/dist/components/progress.js.map +1 -0
- package/dist/components/radio-group.js +113 -0
- package/dist/components/radio-group.js.map +1 -0
- package/dist/components/resizable.js +193 -0
- package/dist/components/resizable.js.map +1 -0
- package/dist/components/scroll-area.js +40 -0
- package/dist/components/scroll-area.js.map +1 -0
- package/dist/components/section-descriptor.js +88 -0
- package/dist/components/section-descriptor.js.map +1 -0
- package/dist/components/select-chevron.js +25 -0
- package/dist/components/select-chevron.js.map +1 -0
- package/dist/components/select.js +288 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/separator.js +31 -0
- package/dist/components/separator.js.map +1 -0
- package/dist/components/sheet.js +200 -0
- package/dist/components/sheet.js.map +1 -0
- package/dist/components/sidebar.js +326 -0
- package/dist/components/sidebar.js.map +1 -0
- package/dist/components/skeleton.js +18 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/slider.js +138 -0
- package/dist/components/slider.js.map +1 -0
- package/dist/components/sonner.js +319 -0
- package/dist/components/sonner.js.map +1 -0
- package/dist/components/spinner.js +23 -0
- package/dist/components/spinner.js.map +1 -0
- package/dist/components/status-screen.js +145 -0
- package/dist/components/status-screen.js.map +1 -0
- package/dist/components/switch.js +54 -0
- package/dist/components/switch.js.map +1 -0
- package/dist/components/table.js +124 -0
- package/dist/components/table.js.map +1 -0
- package/dist/components/tabs.js +133 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/terminal.js +206 -0
- package/dist/components/terminal.js.map +1 -0
- package/dist/components/textarea.js +22 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/components/toggle-group.js +105 -0
- package/dist/components/toggle-group.js.map +1 -0
- package/dist/components/toggle.js +53 -0
- package/dist/components/toggle.js.map +1 -0
- package/dist/components/tooltip.js +102 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/generated/accent.js +27 -0
- package/dist/generated/accent.js.map +1 -0
- package/dist/generated/accordion.js +13 -0
- package/dist/generated/accordion.js.map +1 -0
- package/dist/generated/alert-dialog.js +15 -0
- package/dist/generated/alert-dialog.js.map +1 -0
- package/dist/generated/alert.js +16 -0
- package/dist/generated/alert.js.map +1 -0
- package/dist/generated/avatar.js +9 -0
- package/dist/generated/avatar.js.map +1 -0
- package/dist/generated/badge.js +13 -0
- package/dist/generated/badge.js.map +1 -0
- package/dist/generated/band.js +39 -0
- package/dist/generated/band.js.map +1 -0
- package/dist/generated/breadcrumb.js +15 -0
- package/dist/generated/breadcrumb.js.map +1 -0
- package/dist/generated/button-group.js +14 -0
- package/dist/generated/button-group.js.map +1 -0
- package/dist/generated/button.js +30 -0
- package/dist/generated/button.js.map +1 -0
- package/dist/generated/calendar.js +29 -0
- package/dist/generated/calendar.js.map +1 -0
- package/dist/generated/card.js +17 -0
- package/dist/generated/card.js.map +1 -0
- package/dist/generated/carousel.js +31 -0
- package/dist/generated/carousel.js.map +1 -0
- package/dist/generated/chart.js +9 -0
- package/dist/generated/chart.js.map +1 -0
- package/dist/generated/checkbox.js +7 -0
- package/dist/generated/checkbox.js.map +1 -0
- package/dist/generated/command.js +27 -0
- package/dist/generated/command.js.map +1 -0
- package/dist/generated/container.js +5 -0
- package/dist/generated/container.js.map +1 -0
- package/dist/generated/context-menu.js +19 -0
- package/dist/generated/context-menu.js.map +1 -0
- package/dist/generated/date-time-picker.js +15 -0
- package/dist/generated/date-time-picker.js.map +1 -0
- package/dist/generated/dialog.js +17 -0
- package/dist/generated/dialog.js.map +1 -0
- package/dist/generated/drawer.js +26 -0
- package/dist/generated/drawer.js.map +1 -0
- package/dist/generated/dropdown-menu.js +21 -0
- package/dist/generated/dropdown-menu.js.map +1 -0
- package/dist/generated/empty.js +20 -0
- package/dist/generated/empty.js.map +1 -0
- package/dist/generated/field.js +33 -0
- package/dist/generated/field.js.map +1 -0
- package/dist/generated/focus.js +5 -0
- package/dist/generated/focus.js.map +1 -0
- package/dist/generated/form.js +11 -0
- package/dist/generated/form.js.map +1 -0
- package/dist/generated/hover-card.js +5 -0
- package/dist/generated/hover-card.js.map +1 -0
- package/dist/generated/input-group.js +29 -0
- package/dist/generated/input-group.js.map +1 -0
- package/dist/generated/input-otp.js +15 -0
- package/dist/generated/input-otp.js.map +1 -0
- package/dist/generated/input.js +11 -0
- package/dist/generated/input.js.map +1 -0
- package/dist/generated/item.js +40 -0
- package/dist/generated/item.js.map +1 -0
- package/dist/generated/kbd.js +7 -0
- package/dist/generated/kbd.js.map +1 -0
- package/dist/generated/label.js +5 -0
- package/dist/generated/label.js.map +1 -0
- package/dist/generated/menubar.js +27 -0
- package/dist/generated/menubar.js.map +1 -0
- package/dist/generated/navigation-menu.js +19 -0
- package/dist/generated/navigation-menu.js.map +1 -0
- package/dist/generated/popover.js +5 -0
- package/dist/generated/popover.js.map +1 -0
- package/dist/generated/progress.js +7 -0
- package/dist/generated/progress.js.map +1 -0
- package/dist/generated/radio-group.js +7 -0
- package/dist/generated/radio-group.js.map +1 -0
- package/dist/generated/resizable.js +11 -0
- package/dist/generated/resizable.js.map +1 -0
- package/dist/generated/scroll-area.js +14 -0
- package/dist/generated/scroll-area.js.map +1 -0
- package/dist/generated/select.js +15 -0
- package/dist/generated/select.js.map +1 -0
- package/dist/generated/separator.js +10 -0
- package/dist/generated/separator.js.map +1 -0
- package/dist/generated/sheet.js +25 -0
- package/dist/generated/sheet.js.map +1 -0
- package/dist/generated/sidebar.js +41 -0
- package/dist/generated/sidebar.js.map +1 -0
- package/dist/generated/skeleton.js +5 -0
- package/dist/generated/skeleton.js.map +1 -0
- package/dist/generated/slider.js +11 -0
- package/dist/generated/slider.js.map +1 -0
- package/dist/generated/sonner.js +30 -0
- package/dist/generated/sonner.js.map +1 -0
- package/dist/generated/switch.js +7 -0
- package/dist/generated/switch.js.map +1 -0
- package/dist/generated/table.js +21 -0
- package/dist/generated/table.js.map +1 -0
- package/dist/generated/tabs.js +11 -0
- package/dist/generated/tabs.js.map +1 -0
- package/dist/generated/terminal.js +70 -0
- package/dist/generated/terminal.js.map +1 -0
- package/dist/generated/textarea.js +11 -0
- package/dist/generated/textarea.js.map +1 -0
- package/dist/generated/toggle.js +18 -0
- package/dist/generated/toggle.js.map +1 -0
- package/dist/generated/tooltip.js +5 -0
- package/dist/generated/tooltip.js.map +1 -0
- package/dist/index.d.ts +141 -34
- package/dist/index.js +73 -8623
- package/dist/lib/cn.js +12 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/focus.js +5 -0
- package/dist/lib/focus.js.map +1 -0
- package/dist/palette-cli.js +41 -0
- package/dist/palette-cli.js.map +1 -0
- package/dist/palette.d.ts +80 -0
- package/dist/palette.js +25 -0
- package/dist/palette.js.map +1 -0
- package/dist/primitives/dismissable-layer.js +35 -0
- package/dist/primitives/dismissable-layer.js.map +1 -0
- package/dist/primitives/focus-scope.js +58 -0
- package/dist/primitives/focus-scope.js.map +1 -0
- package/dist/primitives/merge-refs.js +13 -0
- package/dist/primitives/merge-refs.js.map +1 -0
- package/dist/primitives/portal.js +19 -0
- package/dist/primitives/portal.js.map +1 -0
- package/dist/primitives/presence.js +45 -0
- package/dist/primitives/presence.js.map +1 -0
- package/dist/primitives/slot.js +39 -0
- package/dist/primitives/slot.js.map +1 -0
- package/dist/primitives/use-controllable-state.js +24 -0
- package/dist/primitives/use-controllable-state.js.map +1 -0
- package/dist/primitives/use-floating.js +128 -0
- package/dist/primitives/use-floating.js.map +1 -0
- package/dist/primitives/use-hover-intent.js +50 -0
- package/dist/primitives/use-hover-intent.js.map +1 -0
- package/dist/primitives/use-roving-focus.js +40 -0
- package/dist/primitives/use-roving-focus.js.map +1 -0
- package/dist/primitives/walk-elements.js +13 -0
- package/dist/primitives/walk-elements.js.map +1 -0
- package/package.json +15 -5
- package/styles/ev.css +73 -0
- package/styles/theme.css +470 -0
- package/styles/tokens.css +129 -90
- package/dist/index.js.map +0 -1
package/styles/theme.css
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/* AUTO-GENERATED by `nix run .#gen` from the repo-root theme.css — do not edit. */
|
|
2
|
+
/*
|
|
3
|
+
* Toast (sonner) and Drawer enter/exit motion, shared by both ports. Imported by the token
|
|
4
|
+
* sheets so the lifecycle ships with the theme contract.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* ── Toast stacking (Sonner-style), shared by both ports via data-stack ──────
|
|
8
|
+
Both `ev_lib::uikit` (Dioxus) and `@evinvest/uikit` (React) set data-stack on the
|
|
9
|
+
toaster and drive the same machine: toasts are absolutely stacked at the
|
|
10
|
+
pinned edge, pile up collapsed (front three peeking, each lifted + scaled by
|
|
11
|
+
--index and clamped to --front-height), and spread to --offset on hover /
|
|
12
|
+
keyboard focus (pure CSS — no JS state). Vars: the toaster sets --front-height
|
|
13
|
+
+ --gap; each toast sets --index, --z-index, --offset, --initial-height. React
|
|
14
|
+
measures real heights; Dioxus can't (host-only), so it feeds a constant height
|
|
15
|
+
— collapse is exact, expansion is uniform. The enter is a keyframe (plays on
|
|
16
|
+
DOM insertion, so it works in both ports without a JS mount flip),
|
|
17
|
+
`data-state=closed` slides out, and the node is dropped on the transitionend. */
|
|
18
|
+
|
|
19
|
+
[data-slot="toaster"][data-stack] [data-slot="toast"] {
|
|
20
|
+
position: absolute;
|
|
21
|
+
--y: translateY(0);
|
|
22
|
+
opacity: 1;
|
|
23
|
+
z-index: var(--z-index, 1);
|
|
24
|
+
transform: var(--y) translateX(var(--swipe-x, 0px));
|
|
25
|
+
/* a plain easeOut (no overshoot) so a restack settles instead of bouncing
|
|
26
|
+
back past its slot */
|
|
27
|
+
transition:
|
|
28
|
+
transform 350ms cubic-bezier(0.21, 0.8, 0.4, 1),
|
|
29
|
+
opacity 350ms,
|
|
30
|
+
height 350ms;
|
|
31
|
+
/* the enter is a keyframe (plays on DOM insertion in both ports — no JS mount
|
|
32
|
+
flip, whose pre-paint timing the Dioxus effect couldn't drive). It animates
|
|
33
|
+
the independent `translate` property, NOT `transform`, so it *composes* with
|
|
34
|
+
the stack transform instead of overriding it: a toast pushed back mid-enter
|
|
35
|
+
keeps repositioning smoothly instead of fighting the keyframe (rapid-fire
|
|
36
|
+
lag). */
|
|
37
|
+
animation: ev-toast-enter 350ms cubic-bezier(0.21, 0.8, 0.4, 1) backwards;
|
|
38
|
+
}
|
|
39
|
+
@keyframes ev-toast-enter {
|
|
40
|
+
from {
|
|
41
|
+
opacity: 0;
|
|
42
|
+
translate: 0 var(--enter-y, 100%);
|
|
43
|
+
}
|
|
44
|
+
to {
|
|
45
|
+
opacity: 1;
|
|
46
|
+
translate: 0 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* pin to the toaster's edge; set the lift sign + the off-screen enter offset */
|
|
51
|
+
[data-slot="toaster"][data-stack][data-y-position="bottom"] [data-slot="toast"] {
|
|
52
|
+
bottom: 0;
|
|
53
|
+
--lift: -1;
|
|
54
|
+
--enter-y: 100%;
|
|
55
|
+
}
|
|
56
|
+
[data-slot="toaster"][data-stack][data-y-position="top"] [data-slot="toast"] {
|
|
57
|
+
top: 0;
|
|
58
|
+
--lift: 1;
|
|
59
|
+
--enter-y: -100%;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* closing: slide back off + fade out; the node is dropped on its transitionend */
|
|
63
|
+
[data-slot="toaster"][data-stack] [data-slot="toast"][data-state="closed"] {
|
|
64
|
+
--y: translateY(var(--enter-y));
|
|
65
|
+
opacity: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* collapsed: back toasts lift + shrink by depth, clamp to the front height */
|
|
69
|
+
[data-slot="toaster"][data-stack]
|
|
70
|
+
[data-slot="toast"][data-state="open"][data-front="false"] {
|
|
71
|
+
--y: translateY(calc(var(--lift) * var(--gap) * var(--index)))
|
|
72
|
+
scale(calc(1 - var(--index) * 0.05));
|
|
73
|
+
height: var(--front-height);
|
|
74
|
+
}
|
|
75
|
+
[data-slot="toaster"][data-stack] [data-slot="toast"][data-front="false"] > * {
|
|
76
|
+
opacity: 0;
|
|
77
|
+
transition: opacity 300ms;
|
|
78
|
+
}
|
|
79
|
+
/* only the front three show while collapsed */
|
|
80
|
+
[data-slot="toaster"][data-stack] [data-slot="toast"][data-visible="false"] {
|
|
81
|
+
opacity: 0;
|
|
82
|
+
pointer-events: none;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* expanded (hover / keyboard focus): spread to the offset, real height, content
|
|
86
|
+
+ overflow back */
|
|
87
|
+
[data-slot="toaster"][data-stack]:hover [data-slot="toast"][data-state="open"],
|
|
88
|
+
[data-slot="toaster"][data-stack]:focus-within
|
|
89
|
+
[data-slot="toast"][data-state="open"] {
|
|
90
|
+
--y: translateY(calc(var(--lift) * var(--offset)));
|
|
91
|
+
height: var(--initial-height);
|
|
92
|
+
}
|
|
93
|
+
[data-slot="toaster"][data-stack]:hover [data-slot="toast"] > *,
|
|
94
|
+
[data-slot="toaster"][data-stack]:focus-within [data-slot="toast"] > *,
|
|
95
|
+
[data-slot="toaster"][data-stack]:hover [data-slot="toast"][data-visible="false"],
|
|
96
|
+
[data-slot="toaster"][data-stack]:focus-within
|
|
97
|
+
[data-slot="toast"][data-visible="false"] {
|
|
98
|
+
opacity: 1;
|
|
99
|
+
pointer-events: auto;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* a transparent strip over the gap so the hover area stays contiguous between
|
|
103
|
+
spread toasts (otherwise the pointer falls through the gap and it collapses) */
|
|
104
|
+
[data-slot="toaster"][data-stack] [data-slot="toast"]::after {
|
|
105
|
+
content: "";
|
|
106
|
+
position: absolute;
|
|
107
|
+
left: 0;
|
|
108
|
+
width: 100%;
|
|
109
|
+
height: calc(var(--gap) + 1px);
|
|
110
|
+
}
|
|
111
|
+
[data-slot="toaster"][data-stack][data-y-position="bottom"]
|
|
112
|
+
[data-slot="toast"]::after {
|
|
113
|
+
bottom: 100%;
|
|
114
|
+
}
|
|
115
|
+
[data-slot="toaster"][data-stack][data-y-position="top"]
|
|
116
|
+
[data-slot="toast"]::after {
|
|
117
|
+
top: 100%;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* 1:1 finger tracking during a swipe — kill the transition */
|
|
121
|
+
[data-slot="toaster"][data-stack] [data-slot="toast"][data-swiping="true"] {
|
|
122
|
+
transition: none;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* auto-dismiss without a host timer: a no-op "life" animation runs for --life,
|
|
126
|
+
then its `animationend` fires (the toast closes itself). Hovering/focusing the
|
|
127
|
+
stack pauses just that animation (animation-play-state's 2nd slot), so the
|
|
128
|
+
countdown holds — and resumes with the elapsed time preserved — while the
|
|
129
|
+
enter (1st slot) keeps running. Persistent toasts set data-autodismiss=false,
|
|
130
|
+
so they get no life animation. (The React port uses setTimeout instead.) */
|
|
131
|
+
@keyframes ev-toast-life {
|
|
132
|
+
from {
|
|
133
|
+
--ev-life: 0;
|
|
134
|
+
}
|
|
135
|
+
to {
|
|
136
|
+
--ev-life: 1;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
[data-slot="toaster"][data-stack]
|
|
140
|
+
[data-slot="toast"][data-autodismiss="true"][data-state="open"] {
|
|
141
|
+
animation:
|
|
142
|
+
ev-toast-enter 350ms cubic-bezier(0.21, 0.8, 0.4, 1) backwards,
|
|
143
|
+
ev-toast-life var(--life) linear;
|
|
144
|
+
}
|
|
145
|
+
[data-slot="toaster"][data-stack]:hover
|
|
146
|
+
[data-slot="toast"][data-autodismiss="true"],
|
|
147
|
+
[data-slot="toaster"][data-stack]:focus-within
|
|
148
|
+
[data-slot="toast"][data-autodismiss="true"] {
|
|
149
|
+
animation-play-state: running, paused;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* reduced motion: opacity-only enter + near-instant transform (still fires
|
|
153
|
+
transitionend, so exit removal works), no height animation */
|
|
154
|
+
@keyframes ev-toast-fade-in {
|
|
155
|
+
from {
|
|
156
|
+
opacity: 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
@media (prefers-reduced-motion: reduce) {
|
|
160
|
+
[data-slot="toaster"][data-stack] [data-slot="toast"] {
|
|
161
|
+
transition:
|
|
162
|
+
transform 1ms linear,
|
|
163
|
+
opacity 200ms;
|
|
164
|
+
animation: ev-toast-fade-in 200ms;
|
|
165
|
+
}
|
|
166
|
+
/* keep the auto-dismiss life animation under reduced motion */
|
|
167
|
+
[data-slot="toaster"][data-stack]
|
|
168
|
+
[data-slot="toast"][data-autodismiss="true"][data-state="open"] {
|
|
169
|
+
animation:
|
|
170
|
+
ev-toast-fade-in 200ms,
|
|
171
|
+
ev-toast-life var(--life) linear;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* ── Drawer (Vaul-style) motion, shared by both ports via data-slot ──────────
|
|
176
|
+
Both ports render the panel as [data-slot="drawer-content"] with
|
|
177
|
+
data-vaul-drawer-direction + data-state, and the scrim as
|
|
178
|
+
[data-slot="drawer-overlay"] with data-state. The enter is a keyframe (plays
|
|
179
|
+
on DOM insertion — no JS mount flip, same reason as the toast above) on the
|
|
180
|
+
independent `translate` property, so it composes with the `transform` the
|
|
181
|
+
React port writes while a finger drags the panel. Closing flips
|
|
182
|
+
data-state=closed: `transform` transitions to the off-screen edge and the
|
|
183
|
+
node is dropped on that transitionend. A drag sets data-dragging on the panel
|
|
184
|
+
and the scrim to kill their transitions for 1:1 finger tracking, then clears
|
|
185
|
+
it on release so the same transition either snaps the panel home or (with
|
|
186
|
+
data-state=closed in the same frame) carries it off from where the finger
|
|
187
|
+
left it. Timing is Vaul's: 500ms cubic-bezier(0.32, 0.72, 0, 1) both ways.
|
|
188
|
+
|
|
189
|
+
touch-action:none on the panel keeps the browser from turning a touch into a
|
|
190
|
+
page pan (which would pointercancel the drag). It does NOT reach into a
|
|
191
|
+
scroll container nested in the panel — that one keeps native touch scrolling,
|
|
192
|
+
and the React port only starts a drag from it when it sits at its top. So
|
|
193
|
+
the scrollable region of a drawer belongs INSIDE the panel, not on it. */
|
|
194
|
+
|
|
195
|
+
[data-slot="drawer-content"] {
|
|
196
|
+
--ev-drawer-ease: cubic-bezier(0.32, 0.72, 0, 1);
|
|
197
|
+
touch-action: none;
|
|
198
|
+
will-change: transform;
|
|
199
|
+
transition: transform 500ms var(--ev-drawer-ease);
|
|
200
|
+
animation: ev-drawer-enter 500ms var(--ev-drawer-ease) backwards;
|
|
201
|
+
}
|
|
202
|
+
[data-slot="drawer-content"][data-vaul-drawer-direction="bottom"] {
|
|
203
|
+
--ev-drawer-from: 0 100%;
|
|
204
|
+
--ev-drawer-out: translate3d(0, 100%, 0);
|
|
205
|
+
}
|
|
206
|
+
[data-slot="drawer-content"][data-vaul-drawer-direction="top"] {
|
|
207
|
+
--ev-drawer-from: 0 -100%;
|
|
208
|
+
--ev-drawer-out: translate3d(0, -100%, 0);
|
|
209
|
+
}
|
|
210
|
+
[data-slot="drawer-content"][data-vaul-drawer-direction="left"] {
|
|
211
|
+
--ev-drawer-from: -100% 0;
|
|
212
|
+
--ev-drawer-out: translate3d(-100%, 0, 0);
|
|
213
|
+
}
|
|
214
|
+
[data-slot="drawer-content"][data-vaul-drawer-direction="right"] {
|
|
215
|
+
--ev-drawer-from: 100% 0;
|
|
216
|
+
--ev-drawer-out: translate3d(100%, 0, 0);
|
|
217
|
+
}
|
|
218
|
+
@keyframes ev-drawer-enter {
|
|
219
|
+
from {
|
|
220
|
+
translate: var(--ev-drawer-from, 0 100%);
|
|
221
|
+
}
|
|
222
|
+
to {
|
|
223
|
+
translate: 0 0;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
[data-slot="drawer-content"][data-state="closed"] {
|
|
227
|
+
transform: var(--ev-drawer-out, translate3d(0, 100%, 0));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* the over-drag away from the edge is dampened but still moves the panel, so
|
|
231
|
+
the panel's own background extends past its docked edge to cover the gap */
|
|
232
|
+
[data-slot="drawer-content"]::after {
|
|
233
|
+
content: "";
|
|
234
|
+
position: absolute;
|
|
235
|
+
background: inherit;
|
|
236
|
+
pointer-events: none;
|
|
237
|
+
}
|
|
238
|
+
[data-slot="drawer-content"][data-vaul-drawer-direction="bottom"]::after {
|
|
239
|
+
top: 100%;
|
|
240
|
+
left: 0;
|
|
241
|
+
right: 0;
|
|
242
|
+
height: 200%;
|
|
243
|
+
}
|
|
244
|
+
[data-slot="drawer-content"][data-vaul-drawer-direction="top"]::after {
|
|
245
|
+
bottom: 100%;
|
|
246
|
+
left: 0;
|
|
247
|
+
right: 0;
|
|
248
|
+
height: 200%;
|
|
249
|
+
}
|
|
250
|
+
[data-slot="drawer-content"][data-vaul-drawer-direction="left"]::after {
|
|
251
|
+
right: 100%;
|
|
252
|
+
top: 0;
|
|
253
|
+
bottom: 0;
|
|
254
|
+
width: 200%;
|
|
255
|
+
}
|
|
256
|
+
[data-slot="drawer-content"][data-vaul-drawer-direction="right"]::after {
|
|
257
|
+
left: 100%;
|
|
258
|
+
top: 0;
|
|
259
|
+
bottom: 0;
|
|
260
|
+
width: 200%;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
[data-slot="drawer-overlay"] {
|
|
264
|
+
touch-action: none;
|
|
265
|
+
will-change: opacity;
|
|
266
|
+
transition: opacity 500ms cubic-bezier(0.32, 0.72, 0, 1);
|
|
267
|
+
animation: ev-drawer-fade-in 500ms cubic-bezier(0.32, 0.72, 0, 1) backwards;
|
|
268
|
+
}
|
|
269
|
+
@keyframes ev-drawer-fade-in {
|
|
270
|
+
from {
|
|
271
|
+
opacity: 0;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
[data-slot="drawer-overlay"][data-state="closed"] {
|
|
275
|
+
opacity: 0;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* 1:1 finger tracking during a drag — kill the transitions */
|
|
279
|
+
[data-slot="drawer-content"][data-dragging="true"],
|
|
280
|
+
[data-slot="drawer-overlay"][data-dragging="true"] {
|
|
281
|
+
transition: none;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* a mouse drag would otherwise start a text selection alongside the panel */
|
|
285
|
+
@media (hover: hover) and (pointer: fine) {
|
|
286
|
+
[data-slot="drawer-content"] {
|
|
287
|
+
user-select: none;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* reduced motion: fade only. The transform transition stays (1ms) so its
|
|
292
|
+
transitionend still fires and the closing node is still dropped. */
|
|
293
|
+
@media (prefers-reduced-motion: reduce) {
|
|
294
|
+
[data-slot="drawer-content"] {
|
|
295
|
+
transition:
|
|
296
|
+
transform 1ms linear,
|
|
297
|
+
opacity 200ms;
|
|
298
|
+
animation: ev-drawer-fade-in 200ms;
|
|
299
|
+
}
|
|
300
|
+
[data-slot="drawer-content"][data-state="closed"] {
|
|
301
|
+
opacity: 0;
|
|
302
|
+
}
|
|
303
|
+
[data-slot="drawer-overlay"] {
|
|
304
|
+
transition: opacity 200ms;
|
|
305
|
+
animation: ev-drawer-fade-in 200ms;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* ═══ CONTRACT ═══════════════════════════════════════════════════ */
|
|
310
|
+
|
|
311
|
+
@theme inline {
|
|
312
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
313
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
314
|
+
--radius-lg: var(--radius);
|
|
315
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
316
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
317
|
+
|
|
318
|
+
/* Depth has to be a ladder, not a single drop shadow: on a dark theme the
|
|
319
|
+
* value steps alone are too close to separate a resting card from a menu
|
|
320
|
+
* from a modal, so each tier gets its own spread + opacity. */
|
|
321
|
+
--shadow-card: 0 1px 2px 0 rgb(0 0 0 / 0.30);
|
|
322
|
+
--shadow-elevated:
|
|
323
|
+
0 4px 12px -2px rgb(0 0 0 / 0.40),
|
|
324
|
+
0 2px 4px -2px rgb(0 0 0 / 0.30);
|
|
325
|
+
--shadow-overlay: 0 16px 48px -12px rgb(0 0 0 / 0.60);
|
|
326
|
+
|
|
327
|
+
/* The families are parameters: a brand scope sets `--brand-font-sans`,
|
|
328
|
+
* `--brand-font-display` and `--brand-font-mono` (evinvest-palette writes
|
|
329
|
+
* them from a brand file's [fonts]); `font-serif` is the display role under
|
|
330
|
+
* its older name. Unset, each falls through to EV: next/font (landing) sets
|
|
331
|
+
* `--font-inter` / `--font-playfair`, a Rust consumer `@font-face`s the same
|
|
332
|
+
* families itself. Every leading var() carries its own fallback — an
|
|
333
|
+
* undefined one would invalidate the whole `font-family` and drop the
|
|
334
|
+
* browser to its default, so it must never resolve to guaranteed-invalid.
|
|
335
|
+
* `inline` puts the var() chain in the utility itself, so it resolves on
|
|
336
|
+
* the element and a brand scope re-fonts its subtree. */
|
|
337
|
+
--font-sans: var(--brand-font-sans, var(--font-inter, "Inter")), ui-sans-serif, system-ui, sans-serif;
|
|
338
|
+
--font-serif: var(--brand-font-display, var(--font-playfair, "Playfair Display")), ui-serif, Georgia, serif;
|
|
339
|
+
--font-mono: var(--brand-font-mono, var(--font-inter, "Inter")), ui-monospace, monospace;
|
|
340
|
+
--font-display: var(--brand-font-display, var(--font-playfair, "Playfair Display")), ui-serif, Georgia, serif;
|
|
341
|
+
|
|
342
|
+
/* The colour contract: every `--color-X: var(--X)` below is a name a palette
|
|
343
|
+
* owes, except the derived ones in the next rule. `evinvest-palette` reads
|
|
344
|
+
* this block as the list, so there is no second copy of it to drift. */
|
|
345
|
+
|
|
346
|
+
/* surfaces */
|
|
347
|
+
--color-background: var(--background);
|
|
348
|
+
--color-card: var(--card);
|
|
349
|
+
--color-popover: var(--popover);
|
|
350
|
+
--color-muted: var(--muted);
|
|
351
|
+
--color-hover: var(--hover);
|
|
352
|
+
|
|
353
|
+
/* ink — hierarchy, loudest first */
|
|
354
|
+
--color-ink: var(--ink);
|
|
355
|
+
--color-ink-mid: var(--ink-mid);
|
|
356
|
+
--color-ink-soft: var(--ink-soft);
|
|
357
|
+
|
|
358
|
+
/* lines */
|
|
359
|
+
--color-border: var(--border);
|
|
360
|
+
--color-input: var(--input);
|
|
361
|
+
--color-ring: var(--ring);
|
|
362
|
+
|
|
363
|
+
/* roles */
|
|
364
|
+
--color-brand: var(--brand);
|
|
365
|
+
--color-primary: var(--primary);
|
|
366
|
+
--color-on-primary: var(--on-primary);
|
|
367
|
+
--color-primary-ink: var(--primary-ink);
|
|
368
|
+
--color-secondary: var(--secondary);
|
|
369
|
+
--color-on-secondary: var(--on-secondary);
|
|
370
|
+
--color-positive: var(--positive);
|
|
371
|
+
--color-on-positive: var(--on-positive);
|
|
372
|
+
--color-accent-trace: var(--accent-trace);
|
|
373
|
+
--color-on-accent-trace: var(--on-accent-trace);
|
|
374
|
+
--color-accent-debug: var(--accent-debug);
|
|
375
|
+
--color-on-accent-debug: var(--on-accent-debug);
|
|
376
|
+
--color-accent-info: var(--accent-info);
|
|
377
|
+
--color-on-accent-info: var(--on-accent-info);
|
|
378
|
+
--color-accent-warn: var(--accent-warn);
|
|
379
|
+
--color-on-accent-warn: var(--on-accent-warn);
|
|
380
|
+
--color-accent-error: var(--accent-error);
|
|
381
|
+
--color-on-accent-error: var(--on-accent-error);
|
|
382
|
+
|
|
383
|
+
/* charts — distinguishable hues carrying no significance */
|
|
384
|
+
--color-chart-1: var(--chart-1);
|
|
385
|
+
--color-chart-2: var(--chart-2);
|
|
386
|
+
--color-chart-3: var(--chart-3);
|
|
387
|
+
--color-chart-4: var(--chart-4);
|
|
388
|
+
--color-chart-5: var(--chart-5);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/* Derived from the palette, and redeclared on every scope a palette can be
|
|
392
|
+
* declared on. A var() inside a custom property is resolved where it is
|
|
393
|
+
* declared and the result is what inherits — declared on `:root` alone, a brand
|
|
394
|
+
* scope would change the text and keep EV's borders, hover and focus ring.
|
|
395
|
+
* Zero specificity, so a palette that sets one of these outright wins. */
|
|
396
|
+
:where(:root, .dark, .light, [data-brand]) {
|
|
397
|
+
/* the menu-item tint: a surface state, so it is named for the state */
|
|
398
|
+
--hover: color-mix(in srgb, var(--ink) 8%, transparent);
|
|
399
|
+
--ink-mid: color-mix(in srgb, var(--ink) 82%, transparent);
|
|
400
|
+
/* the most-used secondary text token, so it has to clear AA on its own */
|
|
401
|
+
--ink-soft: color-mix(in srgb, var(--ink) 65%, transparent);
|
|
402
|
+
--border: color-mix(in srgb, var(--ink) 14%, transparent);
|
|
403
|
+
--input: color-mix(in srgb, var(--ink) 20%, transparent);
|
|
404
|
+
--ring: var(--primary-ink);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/* Geometry. A `[data-brand]` scope is a theme root of its own, so it restarts
|
|
408
|
+
* from these defaults (and from the scale-ups below) rather than inheriting
|
|
409
|
+
* whatever an ancestor computed — `--control-radius` in particular is derived
|
|
410
|
+
* from `--radius` and has to be recomputed wherever `--radius` may change. */
|
|
411
|
+
:where(:root, [data-brand]) {
|
|
412
|
+
--radius: 0.375rem; /* 6px on mobile; bumped to 8px ≥ sm (see @media below) */
|
|
413
|
+
/* control geometry, so a consumer reshapes every button/input at once */
|
|
414
|
+
--control-radius: calc(var(--radius) - 2px);
|
|
415
|
+
--control-py: 0.5rem;
|
|
416
|
+
/* the Xl (call-to-action) button reads all three */
|
|
417
|
+
--control-px: 2rem;
|
|
418
|
+
--control-text: 1rem;
|
|
419
|
+
/* multiplies the display type scale (uikit <Display>) */
|
|
420
|
+
--display-scale: 1;
|
|
421
|
+
/* the vertical rhythm of a full-bleed <Section>; `tight` is the sub-page one */
|
|
422
|
+
--band-py: 2.25rem;
|
|
423
|
+
--band-py-tight: 2rem;
|
|
424
|
+
|
|
425
|
+
--sidebar-width: 14rem;
|
|
426
|
+
|
|
427
|
+
/* page container — responsive gutter + max width (uikit <Container>) */
|
|
428
|
+
--page-max: 90rem; /* 1440px */
|
|
429
|
+
--page-px: 1rem; /* 16px — mobile gutter, scales up below */
|
|
430
|
+
|
|
431
|
+
/* ── the mark ────────────────────────────────────────────────── *
|
|
432
|
+
* `--brand-mark` (a url() at your own SVG) and `--brand-aspect` (its ratio)
|
|
433
|
+
* are what `<Logo>` masks. Deliberately undefined: the kit ships no artwork,
|
|
434
|
+
* and a default here would put EV's crown on somebody else's 404. Undeclared,
|
|
435
|
+
* `mask-image` is invalid at computed-value time and the mark paints as a
|
|
436
|
+
* solid block — loud, which is the point. Declare both beside the palette:
|
|
437
|
+
*
|
|
438
|
+
* --brand-mark: url("/assets/logo.svg");
|
|
439
|
+
* --brand-aspect: 387 / 335;
|
|
440
|
+
*/
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
:root {
|
|
444
|
+
/* shell offset — viewport space reserved by whatever shell hosts the app.
|
|
445
|
+
Standalone apps get 0; a hosting shell overrides on :root. Size
|
|
446
|
+
viewport-bound surfaces with calc(100dvh - var(--ev-shell-offset, 0px)). */
|
|
447
|
+
--ev-shell-offset: 0px;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/* Mobile-first scale-ups: roomier gutters + slightly larger radii on bigger
|
|
451
|
+
viewports. Lives here (not per-component) so every consumer scales alike. */
|
|
452
|
+
@media (min-width: 640px) {
|
|
453
|
+
:where(:root, [data-brand]) {
|
|
454
|
+
--radius: 0.5rem;
|
|
455
|
+
--page-px: 1.5rem;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
@media (min-width: 768px) {
|
|
460
|
+
:where(:root, [data-brand]) {
|
|
461
|
+
--band-py: 4rem;
|
|
462
|
+
--band-py-tight: 3.5rem;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
@media (min-width: 1024px) {
|
|
467
|
+
:where(:root, [data-brand]) {
|
|
468
|
+
--page-px: 3rem;
|
|
469
|
+
}
|
|
470
|
+
}
|