@evinvest/uikit 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evinvest/uikit",
3
- "version": "0.10.0",
3
+ "version": "0.11.1",
4
4
  "description": "Dep-light React UI kit: shadcn-semantics components with zero @radix-ui / cva, mirroring the ev_lib::uikit Rust feature. Ships the shared design tokens.",
5
5
  "license": "BlueOak-1.0.0",
6
6
  "publishConfig": {
@@ -17,7 +17,9 @@
17
17
  "types": "./dist/index.d.ts",
18
18
  "import": "./dist/index.js"
19
19
  },
20
- "./styles/tokens.css": "./styles/tokens.css"
20
+ "./styles/tokens.css": "./styles/tokens.css",
21
+ "./styles/tokens-legacy.css": "./styles/tokens-legacy.css",
22
+ "./styles/motion.css": "./styles/motion.css"
21
23
  },
22
24
  "types": "./dist/index.d.ts",
23
25
  "main": "./dist/index.js",
@@ -35,7 +37,7 @@
35
37
  "build": "tsup",
36
38
  "test": "vitest run",
37
39
  "typecheck": "tsc --noEmit",
38
- "prepare": "mkdir -p styles && cp ../../tokens.css styles/tokens.css && tsup",
40
+ "prepare": "mkdir -p styles && cp ../../tokens.css ../../tokens-legacy.css ../../motion.css styles/ && tsup",
39
41
  "prepublishOnly": "node scripts/verify-pack.mjs"
40
42
  },
41
43
  "peerDependencies": {
@@ -0,0 +1,172 @@
1
+ /*
2
+ * Toast (sonner) enter/exit motion, shared by both ports. Imported by the token
3
+ * sheets so the lifecycle ships with the theme contract.
4
+ */
5
+
6
+ /* ── Toast stacking (Sonner-style), shared by both ports via data-stack ──────
7
+ Both `ev_lib::uikit` (Dioxus) and `@evinvest/uikit` (React) set data-stack on the
8
+ toaster and drive the same machine: toasts are absolutely stacked at the
9
+ pinned edge, pile up collapsed (front three peeking, each lifted + scaled by
10
+ --index and clamped to --front-height), and spread to --offset on hover /
11
+ keyboard focus (pure CSS — no JS state). Vars: the toaster sets --front-height
12
+ + --gap; each toast sets --index, --z-index, --offset, --initial-height. React
13
+ measures real heights; Dioxus can't (host-only), so it feeds a constant height
14
+ — collapse is exact, expansion is uniform. The enter is a keyframe (plays on
15
+ DOM insertion, so it works in both ports without a JS mount flip),
16
+ `data-state=closed` slides out, and the node is dropped on the transitionend. */
17
+
18
+ [data-slot="toaster"][data-stack] [data-slot="toast"] {
19
+ position: absolute;
20
+ --y: translateY(0);
21
+ opacity: 1;
22
+ z-index: var(--z-index, 1);
23
+ transform: var(--y) translateX(var(--swipe-x, 0px));
24
+ /* a plain easeOut (no overshoot) so a restack settles instead of bouncing
25
+ back past its slot */
26
+ transition:
27
+ transform 350ms cubic-bezier(0.21, 0.8, 0.4, 1),
28
+ opacity 350ms,
29
+ height 350ms;
30
+ /* the enter is a keyframe (plays on DOM insertion in both ports — no JS mount
31
+ flip, whose pre-paint timing the Dioxus effect couldn't drive). It animates
32
+ the independent `translate` property, NOT `transform`, so it *composes* with
33
+ the stack transform instead of overriding it: a toast pushed back mid-enter
34
+ keeps repositioning smoothly instead of fighting the keyframe (rapid-fire
35
+ lag). */
36
+ animation: ev-toast-enter 350ms cubic-bezier(0.21, 0.8, 0.4, 1) backwards;
37
+ }
38
+ @keyframes ev-toast-enter {
39
+ from {
40
+ opacity: 0;
41
+ translate: 0 var(--enter-y, 100%);
42
+ }
43
+ to {
44
+ opacity: 1;
45
+ translate: 0 0;
46
+ }
47
+ }
48
+
49
+ /* pin to the toaster's edge; set the lift sign + the off-screen enter offset */
50
+ [data-slot="toaster"][data-stack][data-y-position="bottom"] [data-slot="toast"] {
51
+ bottom: 0;
52
+ --lift: -1;
53
+ --enter-y: 100%;
54
+ }
55
+ [data-slot="toaster"][data-stack][data-y-position="top"] [data-slot="toast"] {
56
+ top: 0;
57
+ --lift: 1;
58
+ --enter-y: -100%;
59
+ }
60
+
61
+ /* closing: slide back off + fade out; the node is dropped on its transitionend */
62
+ [data-slot="toaster"][data-stack] [data-slot="toast"][data-state="closed"] {
63
+ --y: translateY(var(--enter-y));
64
+ opacity: 0;
65
+ }
66
+
67
+ /* collapsed: back toasts lift + shrink by depth, clamp to the front height */
68
+ [data-slot="toaster"][data-stack]
69
+ [data-slot="toast"][data-state="open"][data-front="false"] {
70
+ --y: translateY(calc(var(--lift) * var(--gap) * var(--index)))
71
+ scale(calc(1 - var(--index) * 0.05));
72
+ height: var(--front-height);
73
+ }
74
+ [data-slot="toaster"][data-stack] [data-slot="toast"][data-front="false"] > * {
75
+ opacity: 0;
76
+ transition: opacity 300ms;
77
+ }
78
+ /* only the front three show while collapsed */
79
+ [data-slot="toaster"][data-stack] [data-slot="toast"][data-visible="false"] {
80
+ opacity: 0;
81
+ pointer-events: none;
82
+ }
83
+
84
+ /* expanded (hover / keyboard focus): spread to the offset, real height, content
85
+ + overflow back */
86
+ [data-slot="toaster"][data-stack]:hover [data-slot="toast"][data-state="open"],
87
+ [data-slot="toaster"][data-stack]:focus-within
88
+ [data-slot="toast"][data-state="open"] {
89
+ --y: translateY(calc(var(--lift) * var(--offset)));
90
+ height: var(--initial-height);
91
+ }
92
+ [data-slot="toaster"][data-stack]:hover [data-slot="toast"] > *,
93
+ [data-slot="toaster"][data-stack]:focus-within [data-slot="toast"] > *,
94
+ [data-slot="toaster"][data-stack]:hover [data-slot="toast"][data-visible="false"],
95
+ [data-slot="toaster"][data-stack]:focus-within
96
+ [data-slot="toast"][data-visible="false"] {
97
+ opacity: 1;
98
+ pointer-events: auto;
99
+ }
100
+
101
+ /* a transparent strip over the gap so the hover area stays contiguous between
102
+ spread toasts (otherwise the pointer falls through the gap and it collapses) */
103
+ [data-slot="toaster"][data-stack] [data-slot="toast"]::after {
104
+ content: "";
105
+ position: absolute;
106
+ left: 0;
107
+ width: 100%;
108
+ height: calc(var(--gap) + 1px);
109
+ }
110
+ [data-slot="toaster"][data-stack][data-y-position="bottom"]
111
+ [data-slot="toast"]::after {
112
+ bottom: 100%;
113
+ }
114
+ [data-slot="toaster"][data-stack][data-y-position="top"]
115
+ [data-slot="toast"]::after {
116
+ top: 100%;
117
+ }
118
+
119
+ /* 1:1 finger tracking during a swipe — kill the transition */
120
+ [data-slot="toaster"][data-stack] [data-slot="toast"][data-swiping="true"] {
121
+ transition: none;
122
+ }
123
+
124
+ /* auto-dismiss without a host timer: a no-op "life" animation runs for --life,
125
+ then its `animationend` fires (the toast closes itself). Hovering/focusing the
126
+ stack pauses just that animation (animation-play-state's 2nd slot), so the
127
+ countdown holds — and resumes with the elapsed time preserved — while the
128
+ enter (1st slot) keeps running. Persistent toasts set data-autodismiss=false,
129
+ so they get no life animation. (The React port uses setTimeout instead.) */
130
+ @keyframes ev-toast-life {
131
+ from {
132
+ --ev-life: 0;
133
+ }
134
+ to {
135
+ --ev-life: 1;
136
+ }
137
+ }
138
+ [data-slot="toaster"][data-stack]
139
+ [data-slot="toast"][data-autodismiss="true"][data-state="open"] {
140
+ animation:
141
+ ev-toast-enter 350ms cubic-bezier(0.21, 0.8, 0.4, 1) backwards,
142
+ ev-toast-life var(--life) linear;
143
+ }
144
+ [data-slot="toaster"][data-stack]:hover
145
+ [data-slot="toast"][data-autodismiss="true"],
146
+ [data-slot="toaster"][data-stack]:focus-within
147
+ [data-slot="toast"][data-autodismiss="true"] {
148
+ animation-play-state: running, paused;
149
+ }
150
+
151
+ /* reduced motion: opacity-only enter + near-instant transform (still fires
152
+ transitionend, so exit removal works), no height animation */
153
+ @keyframes ev-toast-fade-in {
154
+ from {
155
+ opacity: 0;
156
+ }
157
+ }
158
+ @media (prefers-reduced-motion: reduce) {
159
+ [data-slot="toaster"][data-stack] [data-slot="toast"] {
160
+ transition:
161
+ transform 1ms linear,
162
+ opacity 200ms;
163
+ animation: ev-toast-fade-in 200ms;
164
+ }
165
+ /* keep the auto-dismiss life animation under reduced motion */
166
+ [data-slot="toaster"][data-stack]
167
+ [data-slot="toast"][data-autodismiss="true"][data-state="open"] {
168
+ animation:
169
+ ev-toast-fade-in 200ms,
170
+ ev-toast-life var(--life) linear;
171
+ }
172
+ }
@@ -0,0 +1,66 @@
1
+ /*
2
+ * The pre-0.10 token vocabulary, layered over the current one.
3
+ *
4
+ * Import this instead of `tokens.css` while a consumer still writes
5
+ * `text-main-mist`, `bg-sidebar`, `text-muted-foreground` and friends in its own
6
+ * markup. It re-declares every old utility name and re-points the current tokens
7
+ * at the old values, so a kit component styled `bg-card text-ink` renders exactly
8
+ * what `bg-card text-card-foreground` rendered.
9
+ *
10
+ * Paired with the `legacy` Cargo feature and the `./styles/tokens-legacy.css`
11
+ * export of `@evinvest/uikit`. Both go away together once every consumer has
12
+ * moved; see docs/spec/accents.md for the model that replaces this.
13
+ */
14
+
15
+ @import "./tokens.css";
16
+
17
+ @theme inline {
18
+ --color-foreground: var(--ink);
19
+ --color-card-foreground: var(--ink);
20
+ --color-popover-foreground: var(--ink);
21
+ --color-primary-foreground: var(--on-primary);
22
+ --color-secondary-foreground: var(--on-secondary);
23
+ --color-accent: var(--hover);
24
+ --color-accent-foreground: var(--ink);
25
+ --color-destructive: var(--accent-error);
26
+ --color-destructive-foreground: var(--on-accent-error);
27
+
28
+ /* the sidebar namespace was eight aliases of tokens that already existed */
29
+ --color-sidebar: var(--secondary);
30
+ --color-sidebar-foreground: var(--ink);
31
+ --color-sidebar-primary: var(--primary);
32
+ --color-sidebar-primary-foreground: var(--on-primary);
33
+ --color-sidebar-accent: var(--hover);
34
+ --color-sidebar-accent-foreground: var(--ink);
35
+ --color-sidebar-border: var(--border);
36
+ --color-sidebar-ring: var(--ring);
37
+
38
+ --color-main-brand: var(--brand);
39
+ --color-main-black: var(--background);
40
+ --color-main-surface: var(--secondary);
41
+ --color-main-card: var(--card);
42
+ --color-main-mist: #e6e1d3;
43
+ --color-main-accent-t1: var(--accent-debug);
44
+ --color-main-accent-t2: var(--positive);
45
+ --color-main-accent-t3: var(--accent-warn);
46
+ --color-main-accent-t4: var(--chart-4);
47
+
48
+ --color-level-trace: var(--accent-trace);
49
+ --color-level-debug: var(--accent-debug);
50
+ --color-level-info: var(--accent-info);
51
+ --color-level-warn: var(--accent-warn);
52
+ --color-level-error: #da251d;
53
+ }
54
+
55
+ /* The seven tokens whose value moved. Everything else in `tokens.css` already
56
+ * carries its pre-0.10 value. */
57
+ :root,
58
+ .dark {
59
+ --ink: white;
60
+ --ink-mid: #e6e1d3;
61
+ --ink-soft: color-mix(in srgb, #e6e1d3 65%, transparent);
62
+ --hover: color-mix(in srgb, #e6e1d3 8%, transparent);
63
+ --border: color-mix(in srgb, #e6e1d3 14%, transparent);
64
+ --input: color-mix(in srgb, #e6e1d3 20%, transparent);
65
+ --on-secondary: white;
66
+ }