@spunto/design-system 0.2.1 → 0.4.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/styles.css CHANGED
@@ -33,6 +33,13 @@
33
33
  --color-input: var(--input);
34
34
  --color-border: var(--border);
35
35
  --color-destructive: var(--destructive);
36
+ /* Status semantics — used by feedback surfaces (Toast…) */
37
+ --color-success: var(--success);
38
+ --color-success-foreground: var(--success-foreground);
39
+ --color-warning: var(--warning);
40
+ --color-warning-foreground: var(--warning-foreground);
41
+ --color-info: var(--info);
42
+ --color-info-foreground: var(--info-foreground);
36
43
  --color-accent-foreground: var(--accent-foreground);
37
44
  --color-accent: var(--accent);
38
45
  --color-muted-foreground: var(--muted-foreground);
@@ -77,6 +84,13 @@
77
84
  --accent: oklch(0.935 0.024 72);
78
85
  --accent-foreground: oklch(0.34 0.045 52);
79
86
  --destructive: oklch(0.577 0.245 27.325);
87
+ /* Status semantics — warm-leaning green / amber / blue, tuned for the cream bg */
88
+ --success: oklch(0.62 0.145 152);
89
+ --success-foreground: oklch(0.99 0.012 86);
90
+ --warning: oklch(0.74 0.16 68);
91
+ --warning-foreground: oklch(0.24 0.05 60);
92
+ --info: oklch(0.58 0.13 245);
93
+ --info-foreground: oklch(0.99 0.012 86);
80
94
  --border: oklch(0.89 0.016 76);
81
95
  --input: oklch(0.89 0.016 76);
82
96
  --ring: oklch(0.64 0.205 41);
@@ -122,6 +136,13 @@
122
136
  --accent: oklch(0.28 0.018 54);
123
137
  --accent-foreground: oklch(0.95 0.009 78);
124
138
  --destructive: oklch(0.704 0.191 22.216);
139
+ /* Status semantics — lifted for the warm charcoal bg */
140
+ --success: oklch(0.72 0.15 154);
141
+ --success-foreground: oklch(0.16 0.012 52);
142
+ --warning: oklch(0.80 0.155 72);
143
+ --warning-foreground: oklch(0.16 0.012 52);
144
+ --info: oklch(0.68 0.13 240);
145
+ --info-foreground: oklch(0.16 0.012 52);
125
146
  --border: oklch(0.92 0.03 70 / 11%);
126
147
  --input: oklch(0.92 0.03 70 / 14%);
127
148
  --ring: oklch(0.70 0.20 43);
@@ -184,3 +205,133 @@
184
205
  linear-gradient(to right, oklch(0.92 0.04 70 / 0.04) 1px, transparent 1px),
185
206
  linear-gradient(to bottom, oklch(0.92 0.04 70 / 0.04) 1px, transparent 1px);
186
207
  }
208
+
209
+ /* ─── Toast — stacking + enter/exit motion (mounted by SpuntoProvider) ─────
210
+ *
211
+ * The look (colors, spacing, typography) lives on the components as Tailwind
212
+ * utilities; this block owns only the parts Tailwind can't express cleanly —
213
+ * the position-aware stacking math driven by the CSS vars Base UI sets on each
214
+ * toast (`--toast-index`, `--toast-offset-y`, `--toast-frontmost-height`,
215
+ * `--toast-swipe-movement-*`). `data-position` on the viewport flips the whole
216
+ * system between the top and bottom anchors. Adapted from the Base UI toast
217
+ * reference example. */
218
+ [data-slot="toast-viewport"] {
219
+ --toast-gap: 0.75rem;
220
+ --toast-peek: 0.6rem;
221
+ position: fixed;
222
+ z-index: 60;
223
+ display: flex;
224
+ width: min(24rem, calc(100vw - 2rem));
225
+ }
226
+ [data-slot="toast-viewport"][data-position$="right"] { right: 1.25rem; left: auto; }
227
+ [data-slot="toast-viewport"][data-position$="left"] { left: 1.25rem; right: auto; }
228
+ [data-slot="toast-viewport"][data-position$="center"] {
229
+ left: 50%;
230
+ right: auto;
231
+ transform: translateX(-50%);
232
+ }
233
+ [data-slot="toast-viewport"][data-position^="top"] { top: 1.25rem; bottom: auto; }
234
+ [data-slot="toast-viewport"][data-position^="bottom"] { bottom: 1.25rem; top: auto; }
235
+
236
+ [data-slot="toast"] {
237
+ --scale: max(0, 1 - (var(--toast-index) * 0.1));
238
+ --shrink: calc(1 - var(--scale));
239
+ --height: var(--toast-frontmost-height, var(--toast-height));
240
+ position: absolute;
241
+ right: 0;
242
+ left: auto;
243
+ width: 100%;
244
+ box-sizing: border-box;
245
+ z-index: calc(1000 - var(--toast-index));
246
+ height: var(--height);
247
+ transition:
248
+ transform 0.5s cubic-bezier(0.22, 1, 0.36, 1),
249
+ opacity 0.4s ease,
250
+ height 0.2s ease;
251
+ }
252
+ /* Invisible bridge so the pointer can travel across the gap between toasts
253
+ without the stack collapsing. */
254
+ [data-slot="toast"]::after {
255
+ content: "";
256
+ position: absolute;
257
+ left: 0;
258
+ width: 100%;
259
+ height: calc(var(--toast-gap) + 1px);
260
+ }
261
+ [data-slot="toast"][data-limited],
262
+ [data-slot="toast"][data-starting-style],
263
+ [data-slot="toast"][data-ending-style] { opacity: 0; }
264
+
265
+ /* Bottom-anchored (default) — newest at the bottom, older peek upward. */
266
+ [data-position^="bottom"] [data-slot="toast"] {
267
+ bottom: 0;
268
+ transform-origin: bottom center;
269
+ --offset-y: calc(
270
+ var(--toast-offset-y) * -1 + (var(--toast-index) * var(--toast-gap) * -1) +
271
+ var(--toast-swipe-movement-y)
272
+ );
273
+ transform:
274
+ translateX(var(--toast-swipe-movement-x))
275
+ translateY(
276
+ calc(
277
+ var(--toast-swipe-movement-y) - (var(--toast-index) * var(--toast-peek)) -
278
+ (var(--shrink) * var(--height))
279
+ )
280
+ )
281
+ scale(var(--scale));
282
+ }
283
+ [data-position^="bottom"] [data-slot="toast"]::after { top: 100%; }
284
+ [data-position^="bottom"] [data-slot="toast"][data-expanded] {
285
+ transform: translateX(var(--toast-swipe-movement-x)) translateY(var(--offset-y));
286
+ height: var(--toast-height);
287
+ }
288
+ [data-position^="bottom"] [data-slot="toast"][data-starting-style],
289
+ [data-position^="bottom"] [data-slot="toast"][data-ending-style]:not([data-swipe-direction]) {
290
+ transform: translateY(150%);
291
+ }
292
+
293
+ /* Top-anchored — newest at the top, older peek downward. */
294
+ [data-position^="top"] [data-slot="toast"] {
295
+ top: 0;
296
+ transform-origin: top center;
297
+ --offset-y: calc(
298
+ var(--toast-offset-y) + (var(--toast-index) * var(--toast-gap)) +
299
+ var(--toast-swipe-movement-y)
300
+ );
301
+ transform:
302
+ translateX(var(--toast-swipe-movement-x))
303
+ translateY(
304
+ calc(
305
+ var(--toast-swipe-movement-y) + (var(--toast-index) * var(--toast-peek)) +
306
+ (var(--shrink) * var(--height))
307
+ )
308
+ )
309
+ scale(var(--scale));
310
+ }
311
+ [data-position^="top"] [data-slot="toast"]::after { bottom: 100%; }
312
+ [data-position^="top"] [data-slot="toast"][data-expanded] {
313
+ transform: translateX(var(--toast-swipe-movement-x)) translateY(var(--offset-y));
314
+ height: var(--toast-height);
315
+ }
316
+ [data-position^="top"] [data-slot="toast"][data-starting-style],
317
+ [data-position^="top"] [data-slot="toast"][data-ending-style]:not([data-swipe-direction]) {
318
+ transform: translateY(-150%);
319
+ }
320
+
321
+ /* Swipe-to-dismiss exits — fly out toward the swiped edge (both anchors). */
322
+ [data-slot="toast"][data-ending-style][data-swipe-direction="up"] {
323
+ transform: translateY(calc(var(--toast-swipe-movement-y) - 150%));
324
+ }
325
+ [data-slot="toast"][data-ending-style][data-swipe-direction="down"] {
326
+ transform: translateY(calc(var(--toast-swipe-movement-y) + 150%));
327
+ }
328
+ [data-slot="toast"][data-ending-style][data-swipe-direction="left"] {
329
+ transform: translateX(calc(var(--toast-swipe-movement-x) - 150%)) translateY(var(--offset-y));
330
+ }
331
+ [data-slot="toast"][data-ending-style][data-swipe-direction="right"] {
332
+ transform: translateX(calc(var(--toast-swipe-movement-x) + 150%)) translateY(var(--offset-y));
333
+ }
334
+
335
+ @media (prefers-reduced-motion: reduce) {
336
+ [data-slot="toast"] { transition-duration: 0.01ms; }
337
+ }