@rinzai/zen 0.5.0 → 0.6.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.
Files changed (174) hide show
  1. package/README.md +13 -5
  2. package/dist/animated-number/index.js +33 -0
  3. package/dist/avatar/index.js +38 -0
  4. package/dist/backdrop/index.d.ts +7 -3
  5. package/dist/backdrop/index.d.ts.map +1 -1
  6. package/dist/backdrop/index.js +98 -0
  7. package/dist/badge/index.d.ts +1 -1
  8. package/dist/badge/index.js +24 -0
  9. package/dist/button/index.d.ts +10 -3
  10. package/dist/button/index.d.ts.map +1 -1
  11. package/dist/button/index.js +54 -0
  12. package/dist/calendar/index.d.ts +44 -0
  13. package/dist/calendar/index.d.ts.map +1 -0
  14. package/dist/calendar/index.js +161 -0
  15. package/dist/card/index.d.ts +15 -6
  16. package/dist/card/index.d.ts.map +1 -1
  17. package/dist/card/index.js +60 -0
  18. package/dist/chart/donut.d.ts +30 -0
  19. package/dist/chart/donut.d.ts.map +1 -0
  20. package/dist/chart/donut.js +107 -0
  21. package/dist/chart/index.d.ts +81 -0
  22. package/dist/chart/index.d.ts.map +1 -0
  23. package/dist/chart/index.js +364 -0
  24. package/dist/chart/tooltip.d.ts +25 -0
  25. package/dist/chart/tooltip.d.ts.map +1 -0
  26. package/dist/chart/tooltip.js +51 -0
  27. package/dist/checkbox/index.d.ts +20 -0
  28. package/dist/checkbox/index.d.ts.map +1 -0
  29. package/dist/checkbox/index.js +61 -0
  30. package/dist/chip/index.d.ts +12 -0
  31. package/dist/chip/index.d.ts.map +1 -0
  32. package/dist/chip/index.js +14 -0
  33. package/dist/code-block/index.js +36 -0
  34. package/dist/collapse/index.d.ts +17 -7
  35. package/dist/collapse/index.d.ts.map +1 -1
  36. package/dist/collapse/index.js +82 -0
  37. package/dist/combobox/index.d.ts +89 -0
  38. package/dist/combobox/index.d.ts.map +1 -0
  39. package/dist/combobox/index.js +264 -0
  40. package/dist/confirm-dialog/index.d.ts.map +1 -1
  41. package/dist/confirm-dialog/index.js +25 -0
  42. package/dist/date-picker/index.d.ts +48 -0
  43. package/dist/date-picker/index.d.ts.map +1 -0
  44. package/dist/date-picker/index.js +112 -0
  45. package/dist/dialog/index.d.ts +14 -2
  46. package/dist/dialog/index.d.ts.map +1 -1
  47. package/dist/dialog/index.js +77 -0
  48. package/dist/disclosure/index.d.ts +25 -0
  49. package/dist/disclosure/index.d.ts.map +1 -0
  50. package/dist/disclosure/index.js +66 -0
  51. package/dist/editable-cell/index.js +24 -0
  52. package/dist/field/index.d.ts +42 -3
  53. package/dist/field/index.d.ts.map +1 -1
  54. package/dist/field/index.js +66 -0
  55. package/dist/header/index.js +17 -0
  56. package/dist/icons/chevron-down.js +21 -0
  57. package/dist/icons/chevron-left.js +21 -0
  58. package/dist/icons/chevron-right.js +21 -0
  59. package/dist/icons/chevron-up.js +21 -0
  60. package/dist/icons/ellipsis.d.ts +4 -0
  61. package/dist/icons/ellipsis.d.ts.map +1 -0
  62. package/dist/icons/ellipsis.js +31 -0
  63. package/dist/icons/index.d.ts +1 -0
  64. package/dist/icons/index.d.ts.map +1 -1
  65. package/dist/icons/search.js +21 -0
  66. package/dist/icons/x-mark.js +21 -0
  67. package/dist/index.d.ts +22 -10
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/input/index.d.ts.map +1 -1
  70. package/dist/input/index.js +16 -0
  71. package/dist/input-group/index.d.ts.map +1 -1
  72. package/dist/input-group/index.js +36 -0
  73. package/dist/inset/index.d.ts +16 -0
  74. package/dist/inset/index.d.ts.map +1 -0
  75. package/dist/inset/index.js +23 -0
  76. package/dist/lib.js +74 -0
  77. package/dist/menu/index.d.ts +55 -0
  78. package/dist/menu/index.d.ts.map +1 -0
  79. package/dist/menu/index.js +118 -0
  80. package/dist/meter/index.d.ts +4 -3
  81. package/dist/meter/index.d.ts.map +1 -1
  82. package/dist/meter/index.js +42 -0
  83. package/dist/money-input/index.d.ts +84 -15
  84. package/dist/money-input/index.d.ts.map +1 -1
  85. package/dist/money-input/index.js +322 -0
  86. package/dist/month-picker/index.d.ts +4 -3
  87. package/dist/month-picker/index.d.ts.map +1 -1
  88. package/dist/month-picker/index.js +93 -0
  89. package/dist/page-header/index.js +26 -0
  90. package/dist/pills/index.d.ts +35 -0
  91. package/dist/pills/index.d.ts.map +1 -0
  92. package/dist/pills/index.js +50 -0
  93. package/dist/popover/index.d.ts +41 -22
  94. package/dist/popover/index.d.ts.map +1 -1
  95. package/dist/popover/index.js +76 -0
  96. package/dist/progress-ring/index.js +49 -0
  97. package/dist/radio-cards/index.d.ts +34 -0
  98. package/dist/radio-cards/index.d.ts.map +1 -0
  99. package/dist/radio-cards/index.js +48 -0
  100. package/dist/radio-group/index.d.ts +39 -0
  101. package/dist/radio-group/index.d.ts.map +1 -0
  102. package/dist/radio-group/index.js +63 -0
  103. package/dist/segmented/index.d.ts +16 -6
  104. package/dist/segmented/index.d.ts.map +1 -1
  105. package/dist/segmented/index.js +58 -0
  106. package/dist/select/index.d.ts +28 -14
  107. package/dist/select/index.d.ts.map +1 -1
  108. package/dist/select/index.js +187 -0
  109. package/dist/side-nav/index.js +37 -0
  110. package/dist/skeleton/index.js +12 -0
  111. package/dist/slider/index.js +34 -0
  112. package/dist/spinner/index.js +14 -0
  113. package/dist/tab-bar/index.d.ts +3 -0
  114. package/dist/tab-bar/index.d.ts.map +1 -1
  115. package/dist/tab-bar/index.js +34 -0
  116. package/dist/table/index.js +148 -0
  117. package/dist/table-of-contents/index.js +37 -0
  118. package/dist/tabs/index.d.ts +3 -2
  119. package/dist/tabs/index.d.ts.map +1 -1
  120. package/dist/tabs/index.js +114 -0
  121. package/dist/tailwind.css +1 -1
  122. package/dist/textarea/index.d.ts.map +1 -1
  123. package/dist/textarea/index.js +16 -0
  124. package/dist/theme-toggle/index.js +43 -0
  125. package/dist/theme.css +197 -31
  126. package/dist/toast/index.d.ts +6 -1
  127. package/dist/toast/index.d.ts.map +1 -1
  128. package/dist/toast/index.js +248 -0
  129. package/dist/toggle/index.d.ts.map +1 -1
  130. package/dist/toggle/index.js +26 -0
  131. package/dist/tooltip/index.d.ts +25 -0
  132. package/dist/tooltip/index.d.ts.map +1 -0
  133. package/dist/tooltip/index.js +110 -0
  134. package/dist/tree/index.d.ts.map +1 -1
  135. package/dist/tree/index.js +135 -0
  136. package/dist/utils/cva.js +25 -0
  137. package/dist/utils/cx.js +6 -0
  138. package/dist/utils/date.d.ts +37 -0
  139. package/dist/utils/date.d.ts.map +1 -0
  140. package/dist/utils/date.js +68 -0
  141. package/dist/utils/field-chevron.js +19 -0
  142. package/dist/utils/fx.d.ts +30 -0
  143. package/dist/utils/fx.d.ts.map +1 -0
  144. package/dist/utils/fx.js +21 -0
  145. package/dist/utils/graphics.js +33 -0
  146. package/dist/utils/indicator.d.ts +24 -0
  147. package/dist/utils/indicator.d.ts.map +1 -0
  148. package/dist/utils/indicator.js +37 -0
  149. package/dist/utils/merge.js +305 -0
  150. package/dist/utils/money.js +73 -0
  151. package/dist/utils/month.js +46 -0
  152. package/dist/utils/slot.d.ts +9 -5
  153. package/dist/utils/slot.d.ts.map +1 -1
  154. package/dist/utils/slot.js +25 -0
  155. package/dist/utils/status-icons.js +48 -0
  156. package/dist/utils/styles.d.ts +6 -6
  157. package/dist/utils/styles.d.ts.map +1 -1
  158. package/dist/utils/styles.js +6 -0
  159. package/dist/utils/theme.js +200 -0
  160. package/dist/utils/useAnchoredPopup.d.ts +28 -6
  161. package/dist/utils/useAnchoredPopup.d.ts.map +1 -1
  162. package/dist/utils/useAnchoredPopup.js +119 -0
  163. package/dist/utils/useHydrated.js +9 -0
  164. package/dist/utils/useVirtualList.js +45 -0
  165. package/dist/variables.css +22 -0
  166. package/dist/zen.css +1 -1
  167. package/package.json +9 -4
  168. package/dist/actions-menu/index.d.ts +0 -18
  169. package/dist/actions-menu/index.d.ts.map +0 -1
  170. package/dist/dropdown/index.d.ts +0 -28
  171. package/dist/dropdown/index.d.ts.map +0 -1
  172. package/dist/nav-pills/index.d.ts +0 -31
  173. package/dist/nav-pills/index.d.ts.map +0 -1
  174. package/dist/zen.js +0 -2970
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/textarea/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAK,EAAE,aAAa,+BAcpD;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/textarea/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,KAAK,EAAE,aAAa,+BAgBpD;AAED,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { cx as e } from "../utils/cx.js";
3
+ import { FIELD as t } from "../utils/styles.js";
4
+ import { useFieldProps as n } from "../field/index.js";
5
+ import { jsx as r } from "react/jsx-runtime";
6
+ //#region packages/textarea/index.tsx
7
+ function i(i) {
8
+ let { className: a, ...o } = i, s = n(o);
9
+ return /* @__PURE__ */ r("textarea", {
10
+ className: e(t.replace("h-10", ""), "h-32 w-full resize-y py-2", "read-only:text-foreground read-only:cursor-default read-only:border-none! read-only:bg-transparent read-only:shadow-none! read-only:outline-hidden!", a),
11
+ ...o,
12
+ ...s
13
+ });
14
+ }
15
+ //#endregion
16
+ export { i as default };
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { cx as e } from "../utils/cx.js";
3
+ import { useEffect as t, useState as n } from "react";
4
+ import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
5
+ //#region packages/theme-toggle/index.tsx
6
+ var o = (e = "theme") => `try{var t=localStorage.getItem(${JSON.stringify(e)}),r=document.documentElement;if(t==='light'||t==='dark'){r.classList.remove('light','dark');r.classList.add(t)}}catch(e){}`;
7
+ function s({ storageKey: e = "theme" }) {
8
+ return /* @__PURE__ */ i("script", { dangerouslySetInnerHTML: { __html: o(e) } });
9
+ }
10
+ function c({ storageKey: o = "theme", className: s }) {
11
+ let [c, l] = n("dark");
12
+ t(() => l(document.documentElement.classList.contains("light") ? "light" : "dark"), []);
13
+ let u = c === "dark" ? "light" : "dark";
14
+ return /* @__PURE__ */ i("button", {
15
+ type: "button",
16
+ "aria-label": `Switch to ${u} theme`,
17
+ onClick: () => {
18
+ let e = document.documentElement;
19
+ e.classList.remove("dark", "light"), e.classList.add(u);
20
+ try {
21
+ localStorage.setItem(o, u);
22
+ } catch {}
23
+ l(u);
24
+ },
25
+ className: e("zen__theme-toggle text-muted-foreground hover:bg-tint/[0.06] hover:text-foreground focus-visible:ring-ring/50 grid size-9 place-items-center rounded-lg outline-hidden focus-visible:ring-2", s),
26
+ children: /* @__PURE__ */ i("svg", {
27
+ viewBox: "0 0 16 16",
28
+ fill: "none",
29
+ stroke: "currentColor",
30
+ strokeWidth: "1.5",
31
+ strokeLinecap: "round",
32
+ className: "size-4",
33
+ "aria-hidden": !0,
34
+ children: c === "dark" ? /* @__PURE__ */ i("path", { d: "M13.5 9.5A5.5 5.5 0 0 1 6.5 2.5a5.5 5.5 0 1 0 7 7Z" }) : /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i("circle", {
35
+ cx: "8",
36
+ cy: "8",
37
+ r: "3"
38
+ }), /* @__PURE__ */ i("path", { d: "M8 1v1.5M8 13.5V15M1 8h1.5M13.5 8H15M3.05 3.05l1.06 1.06M11.89 11.89l1.06 1.06M3.05 12.95l1.06-1.06M11.89 4.11l1.06-1.06" })] })
39
+ })
40
+ });
41
+ }
42
+ //#endregion
43
+ export { s as ThemeScript, c as default, o as themeScript };
package/dist/theme.css CHANGED
@@ -10,6 +10,22 @@
10
10
  @custom-variant dark (&:is(.dark *, [data-theme='dark'] *));
11
11
  @custom-variant light (&:is(.light *, [data-theme='light'] *));
12
12
 
13
+ /*
14
+ * A trigger stays hovered while its popup is open (Zen's popups set
15
+ * data-popup-open on it): moving the pointer into a menu doesn't drop the
16
+ * trigger's hover look, or shift a popup anchored to a trigger that scales on hover.
17
+ */
18
+ @custom-variant hover {
19
+ @media (hover: hover) {
20
+ &:hover {
21
+ @slot;
22
+ }
23
+ }
24
+ &[data-popup-open] {
25
+ @slot;
26
+ }
27
+ }
28
+
13
29
  /*
14
30
  * inline: utilities use oklch(var(--primary)) directly rather than through
15
31
  * --color-primary, so tokens set on any element (applyTheme's target, a .light
@@ -122,38 +138,92 @@
122
138
  --gx: inherit;
123
139
  --gy: inherit;
124
140
  position: absolute;
125
- /* Inside the box (over its 1px border), so it never causes overflow or scrollbars. */
141
+ /* Inside the box (along its border), so it never causes overflow or scrollbars. */
126
142
  inset: 0;
127
143
  border-radius: inherit;
128
- padding: 1px;
144
+ /*
145
+ * A ring as wide as the element's own border on each side: a bar with
146
+ * only a bottom border (Header) lights only that line.
147
+ */
148
+ border-width: inherit;
149
+ border-style: solid;
150
+ border-color: transparent;
129
151
  background: radial-gradient(
130
152
  360px circle at var(--gx, -999px) var(--gy, -999px),
131
153
  oklch(var(--glow) / calc(0.7 * var(--glow-strength))),
132
154
  oklch(var(--glow-2) / calc(0.2 * var(--glow-strength))) 40%,
133
155
  transparent 65%
134
156
  );
157
+ background-origin: border-box;
135
158
  -webkit-mask:
136
- linear-gradient(#000 0 0) content-box,
159
+ linear-gradient(#000 0 0) padding-box,
137
160
  linear-gradient(#000 0 0);
138
161
  -webkit-mask-composite: xor;
139
162
  mask:
140
- linear-gradient(#000 0 0) content-box exclude,
163
+ linear-gradient(#000 0 0) padding-box exclude,
141
164
  linear-gradient(#000 0 0);
142
165
  pointer-events: none;
143
166
  z-index: 1;
144
167
  }
145
168
  }
146
169
 
170
+ /*
171
+ * The same pointer light, painted into the element's own border instead of a
172
+ * ::before layer, for fields: <input> and <textarea> can't have pseudo-elements.
173
+ * The border colour (--glow-border-color) is painted as a layer beneath the
174
+ * light, as glow-edge's light sits above a card's border; a real border would
175
+ * be drawn over the light and wash it out. The trailing `none` layer keeps the
176
+ * background colour clipped as before. Browsers without border-area keep a
177
+ * plain border. In the components layer, so a border colour utility (focus,
178
+ * an error state) still wins, drawn over it all.
179
+ */
180
+ @property --glow-border-color {
181
+ syntax: '<color>';
182
+ inherits: false;
183
+ initial-value: transparent;
184
+ }
185
+ @layer components {
186
+ .glow-border {
187
+ border-color: var(--glow-border-color);
188
+ }
189
+ @supports (background-clip: border-area) {
190
+ .glow-border {
191
+ border-color: transparent;
192
+ background-image:
193
+ radial-gradient(
194
+ 360px circle at var(--gx, -999px) var(--gy, -999px),
195
+ oklch(var(--glow) / calc(0.7 * var(--glow-strength))),
196
+ oklch(var(--glow-2) / calc(0.2 * var(--glow-strength))) 40%,
197
+ transparent 65%
198
+ ),
199
+ linear-gradient(var(--glow-border-color) 0 0), none;
200
+ background-origin: border-box;
201
+ background-clip: border-area, border-area, border-box;
202
+ }
203
+ }
204
+ }
205
+
147
206
  /*
148
207
  * Built from Tailwind's backdrop utilities, which emit the standard and -webkit-
149
- * properties correctly. Phones: a live blur over scrolling content is the main
150
- * cause of jank, so touch screens get a solid tint instead.
208
+ * properties correctly. Where there's no live blur, the surface is solid: a
209
+ * translucent one lets sharp text behind show through (the blur is what hides
210
+ * it). No blur on touch screens (a live blur over scrolling content is the main
211
+ * cause of jank), without a GPU (lite graphics) and with the OS's "reduce
212
+ * transparency". The fallbacks live here, in the utilities layer, where a
213
+ * surface's own `!` background (a Dialog's) is: an unlayered !important rule
214
+ * loses to a layered one.
151
215
  */
152
216
  @utility glass-blur {
153
217
  @apply backdrop-blur-[18px] backdrop-saturate-140;
154
- /* !: glass's `background` shorthand would otherwise reset the colour. */
155
- @apply pointer-coarse:bg-card/96! pointer-coarse:backdrop-filter-none;
156
- @apply [@media(hover:none)]:bg-card/96! [@media(hover:none)]:backdrop-filter-none;
218
+ /*
219
+ * !: glass's `background` shorthand would otherwise reset the colour. [:root_&]
220
+ * adds specificity, so each fallback beats a surface's own `!` background (a
221
+ * Dialog's bg-card/90!) whatever order the rules come in.
222
+ */
223
+ @apply pointer-coarse:[:root_&]:bg-card! pointer-coarse:backdrop-filter-none;
224
+ @apply [@media(hover:none)]:[:root_&]:bg-card! [@media(hover:none)]:backdrop-filter-none;
225
+ @apply [@media(prefers-reduced-transparency:reduce)]:[:root_&]:bg-card! [@media(prefers-reduced-transparency:reduce)]:backdrop-filter-none;
226
+ @apply [html[data-zen-graphics='lite']_&]:bg-card! [html[data-zen-graphics='lite']_&]:backdrop-filter-none;
157
227
  }
158
228
 
159
229
  @utility text-glow {
@@ -172,20 +242,29 @@
172
242
  }
173
243
  }
174
244
 
245
+ /*
246
+ * Over the dot grid, the Header is lightly frosted so the dots stay visible
247
+ * behind it (a heavy blur smears them into a grey band). Only a Header after
248
+ * that Backdrop (the page's own backdrop comes first in <body>; a backdrop in a
249
+ * demo frame doesn't reach the page's header). :where keeps this below the
250
+ * lite-graphics and touch rules that follow.
251
+ */
252
+ :where(.zen-backdrop[data-pattern='dots'] ~ *) .zen__header,
253
+ :where(.zen-backdrop[data-pattern='dots']) ~ .zen__header {
254
+ background-color: oklch(var(--background) / 0.75);
255
+ -webkit-backdrop-filter: blur(2px);
256
+ backdrop-filter: blur(2px);
257
+ }
258
+
175
259
  /* ───────────────────────── Lite graphics ───────────────────────── */
176
260
 
177
261
  /*
178
262
  * Without hardware acceleration (html[data-zen-graphics='lite'], set by
179
263
  * utils/graphics.ts) every blur, full-screen mask and animation is drawn on the
180
- * CPU each frame. Keep the look, drop the cost: solid tints instead of live
181
- * blur (as on phones), a still backdrop, no pointer light. The OS "reduce
182
- * transparency" setting gets the same tints.
264
+ * CPU each frame. Keep the look, drop the cost: solid surfaces instead of live
265
+ * blur (as on phones; see glass-blur), a still backdrop, no pointer light. The
266
+ * OS "reduce transparency" setting gets the same.
183
267
  */
184
- html[data-zen-graphics='lite'] .glass-blur {
185
- -webkit-backdrop-filter: none !important;
186
- backdrop-filter: none !important;
187
- background: oklch(var(--card) / 0.96) !important;
188
- }
189
268
  html[data-zen-graphics='lite'] .zen__header {
190
269
  -webkit-backdrop-filter: none;
191
270
  backdrop-filter: none;
@@ -203,11 +282,6 @@ html[data-zen-graphics='lite'] :is(.zen-topo--lit, .zen-dots--lit) {
203
282
  display: none;
204
283
  }
205
284
  @media (prefers-reduced-transparency: reduce) {
206
- .glass-blur {
207
- -webkit-backdrop-filter: none !important;
208
- backdrop-filter: none !important;
209
- background: oklch(var(--card) / 0.96) !important;
210
- }
211
285
  .zen__header {
212
286
  -webkit-backdrop-filter: none;
213
287
  backdrop-filter: none;
@@ -710,6 +784,13 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
710
784
  display 150ms allow-discrete;
711
785
  }
712
786
  .zen__dialog {
787
+ /*
788
+ * Fixed to the viewport, as the browser places modal dialogs. glow-edge sets
789
+ * position: relative (so its light has a box), and in the top layer relative
790
+ * computes to absolute: the dialog would be placed from the top of the
791
+ * document, off screen once the page is scrolled.
792
+ */
793
+ position: fixed;
713
794
  transition:
714
795
  opacity 200ms var(--ease-out-soft),
715
796
  scale 200ms var(--ease-out-soft),
@@ -730,6 +811,26 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
730
811
  .zen__dialog:not([open])::backdrop {
731
812
  opacity: 0;
732
813
  }
814
+ /* Sheets slide from their edge instead of scaling up. */
815
+ .zen__dialog[data-side] {
816
+ transition:
817
+ translate 320ms cubic-bezier(0.2, 0.8, 0.2, 1),
818
+ opacity 200ms,
819
+ overlay 320ms allow-discrete,
820
+ display 320ms allow-discrete;
821
+ }
822
+ .zen__dialog[data-side]:not([open]) {
823
+ scale: none;
824
+ }
825
+ .zen__dialog[data-side='bottom']:not([open]) {
826
+ translate: 0 100%;
827
+ }
828
+ .zen__dialog[data-side='right']:not([open]) {
829
+ translate: 100% 0;
830
+ }
831
+ .zen__dialog[data-side='left']:not([open]) {
832
+ translate: -100% 0;
833
+ }
733
834
  @starting-style {
734
835
  .zen__popover:popover-open,
735
836
  .zen__dialog[open] {
@@ -739,6 +840,18 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
739
840
  .zen__dialog[open]::backdrop {
740
841
  opacity: 0;
741
842
  }
843
+ .zen__dialog[data-side][open] {
844
+ scale: none;
845
+ }
846
+ .zen__dialog[data-side='bottom'][open] {
847
+ translate: 0 100%;
848
+ }
849
+ .zen__dialog[data-side='right'][open] {
850
+ translate: 100% 0;
851
+ }
852
+ .zen__dialog[data-side='left'][open] {
853
+ translate: -100% 0;
854
+ }
742
855
  }
743
856
  /*
744
857
  * The page behind a modal dialog doesn't scroll. Hiding the overflow removes
@@ -800,7 +913,12 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
800
913
  transition: border-color 200ms;
801
914
  }
802
915
 
803
- /* Direct children of a .rise container enter one after another. */
916
+ /*
917
+ * Direct children of a .rise container enter one after another. Filled backwards
918
+ * only: holding the end state (both/forwards) keeps a transform on the page,
919
+ * and Chrome then stops frosted glass inside it (e.g. sticky table parts) from
920
+ * blurring the sticky cells beneath. The end state is the natural style anyway.
921
+ */
804
922
  @keyframes zen-rise {
805
923
  from {
806
924
  opacity: 0;
@@ -808,7 +926,7 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
808
926
  }
809
927
  }
810
928
  .rise > * {
811
- animation: zen-rise 0.5s var(--ease-out-soft) both;
929
+ animation: zen-rise 0.5s var(--ease-out-soft) backwards;
812
930
  }
813
931
  .rise > *:nth-child(2) {
814
932
  animation-delay: 50ms;
@@ -823,23 +941,36 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
823
941
  animation-delay: 200ms;
824
942
  }
825
943
 
826
- /* Loading placeholders: a soft light sweeping across. */
944
+ /*
945
+ * Loading placeholders: a soft light sweeping across. The light is a layer
946
+ * three times as wide sliding through the placeholder, moved by transform so
947
+ * the compositor runs it: animating background-position repainted every
948
+ * placeholder on every frame.
949
+ */
827
950
  .zen__skeleton {
828
- background: linear-gradient(
951
+ position: relative;
952
+ overflow: hidden;
953
+ isolation: isolate;
954
+ &::before {
955
+ content: '';
956
+ position: absolute;
957
+ inset: 0 auto 0 0;
958
+ width: 300%;
959
+ background: linear-gradient(
829
960
  100deg,
830
961
  oklch(var(--tint) / 0.04) 30%,
831
962
  oklch(var(--tint) / 0.09) 50%,
832
963
  oklch(var(--tint) / 0.04) 70%
833
- )
834
- 0 0 / 300% 100%;
835
- animation: zen-shimmer 1.6s ease-in-out infinite;
964
+ );
965
+ animation: zen-shimmer 1.6s ease-in-out infinite;
966
+ }
836
967
  }
837
968
  @keyframes zen-shimmer {
838
969
  from {
839
- background-position: 100% 0;
970
+ transform: translateX(-66.6667%);
840
971
  }
841
972
  to {
842
- background-position: 0 0;
973
+ transform: translateX(0);
843
974
  }
844
975
  }
845
976
 
@@ -863,6 +994,41 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
863
994
  }
864
995
  }
865
996
 
997
+ /* Charts: lines draw themselves in, bars grow from the baseline, fills and donut segments fade up. */
998
+ .zen__chart-draw {
999
+ stroke-dasharray: 1;
1000
+ animation: zen-chart-draw 0.9s cubic-bezier(0.3, 0.7, 0.2, 1) both;
1001
+ }
1002
+ @keyframes zen-chart-draw {
1003
+ from {
1004
+ stroke-dashoffset: 1;
1005
+ }
1006
+ to {
1007
+ stroke-dashoffset: 0;
1008
+ }
1009
+ }
1010
+ .zen__chart-grow {
1011
+ transform-box: fill-box;
1012
+ transform-origin: bottom;
1013
+ animation: zen-chart-grow 0.6s cubic-bezier(0.2, 0.8, 0.2, 1) both;
1014
+ }
1015
+ .zen__chart-grow[data-negative] {
1016
+ transform-origin: top;
1017
+ }
1018
+ @keyframes zen-chart-grow {
1019
+ from {
1020
+ transform: scaleY(0);
1021
+ }
1022
+ }
1023
+ .zen__chart-fade {
1024
+ animation: zen-chart-fade 0.8s ease-out both;
1025
+ }
1026
+ @keyframes zen-chart-fade {
1027
+ from {
1028
+ opacity: 0;
1029
+ }
1030
+ }
1031
+
866
1032
  /* Reduced motion: the OS setting, or opt in with html.reduce-motion. */
867
1033
  @media (prefers-reduced-motion: reduce) {
868
1034
  .zen-backdrop *,
@@ -21,7 +21,12 @@ export interface ToastProviderProps {
21
21
  /** Classes for the column the toasts stack in (position, width…). */
22
22
  viewportClassName?: string;
23
23
  }
24
- /** Mount once near the root; `useToast()` works anywhere inside. */
24
+ /**
25
+ * Mount once near the root; `useToast()` works anywhere inside. Toasts stack in
26
+ * a deck in the corner, newest in front with up to two peeking out behind; it
27
+ * fans out while pointed at or focused, and the countdowns wait meanwhile.
28
+ * Swipe a toast right to dismiss it.
29
+ */
25
30
  export default function ToastProvider({ children, offset, viewportClassName }: ToastProviderProps): import('react').JSX.Element;
26
31
  /**
27
32
  * Makes an element (a modal dialog, while it's open) the place toasts render, so
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/toast/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGH,SAAS,EACT,SAAS,EAMZ,MAAM,OAAO,CAAC;AAKf,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,YAAY;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,sCAAsC;IACtC,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChD,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAmBD,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,oEAAoE;AACpE,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,kBAAkB,+BAiFhG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,QAO/E;AAYD,+EAA+E;AAC/E,wBAAgB,QAAQ,YA7HoB,MAAM,YAAY,YAAY,KAAK,MAAM,CAiIpF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/toast/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIH,SAAS,EACT,SAAS,EAMZ,MAAM,OAAO,CAAC;AAKf,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,YAAY;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,sCAAsC;IACtC,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAChD,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AA4BD,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,kBAAkB,+BA4IhG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,QAO/E;AAYD,+EAA+E;AAC/E,wBAAgB,QAAQ,YA7LoB,MAAM,YAAY,YAAY,KAAK,MAAM,CAiMpF"}
@@ -0,0 +1,248 @@
1
+ "use client";
2
+ import { cx as e } from "../utils/cx.js";
3
+ import { useGraphicsMode as t } from "../utils/graphics.js";
4
+ import { AlertIcon as n, CheckIcon as r, InfoIcon as i } from "../utils/status-icons.js";
5
+ import { createContext as a, useCallback as o, useContext as s, useEffect as c, useRef as l, useState as u } from "react";
6
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
7
+ import { createPortal as p } from "react-dom";
8
+ //#region packages/toast/index.tsx
9
+ var m = 5e3, h = 3, g = 300, _ = 14, v = .05, y = 10, b = 60, x = .45, S = a(null), C = a(null);
10
+ function w({ children: n, offset: r, viewportClassName: i }) {
11
+ t();
12
+ let [a, s] = u([]), b = l(0), x = l(/* @__PURE__ */ new Map()), w = l(/* @__PURE__ */ new Set()), [T, D] = u([]), [O, A] = u(!1);
13
+ c(() => A(!0), []);
14
+ let j = o((e) => (D((t) => [...t, e]), () => D((t) => t.filter((t) => t !== e))), []), M = T.at(-1) ?? (O ? document.body : null), [N, P] = u({}), F = o((e, t) => P((n) => n[e] === t ? n : {
15
+ ...n,
16
+ [e]: t
17
+ }), []), [I, L] = u(!1), [R, z] = u(!1), B = o((e, t = "fade") => {
18
+ s((n) => n.map((n) => n.id === e ? {
19
+ ...n,
20
+ leaving: t
21
+ } : n)), setTimeout(() => {
22
+ s((t) => {
23
+ let n = t.filter((t) => t.id !== e);
24
+ return n.length || L(!1), n;
25
+ }), P(({ [e]: t, ...n }) => n), x.current.delete(e), w.current.delete(e);
26
+ }, g);
27
+ }, []), V = o((e, { description: t, tone: n = "info", action: r, timeout: i } = {}) => {
28
+ let a = b.current++, o = {
29
+ id: a,
30
+ title: e,
31
+ description: t,
32
+ tone: n,
33
+ action: r,
34
+ timeout: i ?? (r ? 1e4 : m)
35
+ };
36
+ return s((e) => [...e, o]), a;
37
+ }, []), H = a.filter((e) => !e.leaving), U = (I || R) && H.length > 0, W = H.at(-1), G = W ? N[W.id] : void 0, K = H.slice(-3), q = U ? K.reduce((e, t) => e + (N[t.id] ?? 0), 0) + y * (K.length - 1) : (G ?? 0) + _ * (K.length - 1), J = (e) => {
38
+ let t = H.filter((t) => t.id > e.id), n = t.length;
39
+ return {
40
+ index: n,
41
+ front: n === 0,
42
+ hidden: n >= h,
43
+ y: U ? -(t.reduce((e, t) => e + (N[t.id] ?? 0), 0) + y * n) : -14 * Math.min(n, 2),
44
+ scale: U ? 1 : 1 - v * Math.min(n, 2),
45
+ height: !U && n > 0 ? G : void 0
46
+ };
47
+ };
48
+ return /* @__PURE__ */ f(S.Provider, {
49
+ value: V,
50
+ children: [/* @__PURE__ */ d(C.Provider, {
51
+ value: j,
52
+ children: n
53
+ }), M && p(/* @__PURE__ */ d("section", {
54
+ ref: E,
55
+ popover: "manual",
56
+ "aria-label": "Notifications",
57
+ "data-expanded": U || void 0,
58
+ onMouseEnter: () => L(!0),
59
+ onMouseLeave: () => L(!1),
60
+ onFocus: () => z(!0),
61
+ onBlur: (e) => {
62
+ e.currentTarget.contains(e.relatedTarget) || z(!1);
63
+ },
64
+ className: e("zen__toast-viewport fixed top-auto right-4 bottom-[calc(var(--zen-toast-offset,1rem)+env(safe-area-inset-bottom))] left-auto z-50 m-0 w-[calc(100vw-2rem)] overflow-visible border-0 bg-transparent p-0 text-inherit md:bottom-5 md:w-[24rem]", "transition-[height] duration-300 ease-[cubic-bezier(0.2,0.8,0.2,1)]", i),
65
+ style: {
66
+ height: q,
67
+ ...r && { "--zen-toast-offset": r }
68
+ },
69
+ children: a.map((e, t) => /* @__PURE__ */ d(k, {
70
+ toast: e,
71
+ layout: J(e),
72
+ z: t + 1,
73
+ paused: U,
74
+ onDismiss: B,
75
+ onHeight: F,
76
+ clocks: x.current,
77
+ entered: w.current
78
+ }, e.id))
79
+ }), M)]
80
+ });
81
+ }
82
+ function T(e, t) {
83
+ let n = s(C);
84
+ c(() => {
85
+ let r = e.current;
86
+ if (n && t && r) return n(r);
87
+ }, [
88
+ n,
89
+ t,
90
+ e
91
+ ]);
92
+ }
93
+ function E(e) {
94
+ if (e?.showPopover) try {
95
+ e.showPopover();
96
+ } catch {}
97
+ }
98
+ function D() {
99
+ let e = s(S);
100
+ if (!e) throw Error("useToast() needs a <ToastProvider> above it");
101
+ return e;
102
+ }
103
+ var O = {
104
+ success: {
105
+ icon: r,
106
+ ring: "border-primary/30",
107
+ badge: "bg-primary/15 text-primary",
108
+ bar: "bg-primary",
109
+ glow: "shadow-[0_18px_50px_-18px_oklch(var(--glow)/0.55)]"
110
+ },
111
+ error: {
112
+ icon: n,
113
+ ring: "border-destructive/40",
114
+ badge: "bg-destructive/15 text-destructive",
115
+ bar: "bg-destructive",
116
+ glow: "shadow-[0_18px_50px_-18px_oklch(var(--destructive)/0.55)]"
117
+ },
118
+ info: {
119
+ icon: i,
120
+ ring: "border-tint/10",
121
+ badge: "bg-tint/[0.08] text-foreground",
122
+ bar: "bg-muted-foreground",
123
+ glow: "shadow-[var(--toast-shadow)]"
124
+ }
125
+ };
126
+ function k({ toast: t, layout: n, z: r, paused: i, onDismiss: a, onHeight: o, clocks: s, entered: p }) {
127
+ let m = O[t.tone] ?? O.info, h = m.icon, g = l(null), _ = l(null), [v] = u(() => !p.has(t.id));
128
+ c(() => {
129
+ g.current?.isConnected && p.add(t.id);
130
+ }, [p, t.id]), s.has(t.id) || s.set(t.id, {
131
+ spent: 0,
132
+ since: null
133
+ });
134
+ let y = s.get(t.id), [S] = u(() => y.spent + (y.since === null ? 0 : Date.now() - y.since));
135
+ c(() => {
136
+ let e = _.current;
137
+ if (!e) return;
138
+ let n = () => o(t.id, e.offsetHeight);
139
+ n();
140
+ let r = new ResizeObserver(n);
141
+ return r.observe(e), () => r.disconnect();
142
+ }, [o, t.id]), c(() => {
143
+ if (!t.timeout || i || t.leaving) return;
144
+ y.since = Date.now();
145
+ let e = setTimeout(() => a(t.id), Math.max(0, t.timeout - y.spent));
146
+ return () => {
147
+ clearTimeout(e), y.since !== null && (y.spent += Date.now() - y.since), y.since = null;
148
+ };
149
+ }, [
150
+ i,
151
+ t.id,
152
+ t.timeout,
153
+ t.leaving,
154
+ a,
155
+ y
156
+ ]);
157
+ let C = l(null), w = (e) => {
158
+ t.leaving || e.button !== 0 || e.target.closest("button") || (C.current = {
159
+ x: e.clientX,
160
+ dx: 0,
161
+ t: e.timeStamp,
162
+ speed: 0
163
+ }, e.currentTarget.setPointerCapture(e.pointerId), e.currentTarget.dataset.swiping = "");
164
+ }, T = (e) => {
165
+ if (!C.current) return;
166
+ let t = C.current, n = e.clientX - t.x;
167
+ t.speed = (n - t.dx) / Math.max(1, e.timeStamp - t.t), t.dx = n, t.t = e.timeStamp, e.currentTarget.style.setProperty("--zen-swipe", `${n > 0 ? n : n / 6}px`);
168
+ }, E = (e) => {
169
+ let n = C.current;
170
+ n && (C.current = null, delete e.currentTarget.dataset.swiping, n.dx > b || n.dx > 0 && n.speed > x ? a(t.id, "swipe") : e.currentTarget.style.setProperty("--zen-swipe", "0px"));
171
+ };
172
+ return /* @__PURE__ */ f("div", {
173
+ ref: g,
174
+ role: t.tone === "error" ? "alert" : "status",
175
+ "aria-atomic": "true",
176
+ "data-front": n.front || void 0,
177
+ "data-behind": !n.front && n.height !== void 0 || void 0,
178
+ inert: n.hidden || !!t.leaving,
179
+ onPointerDown: w,
180
+ onPointerMove: T,
181
+ onPointerUp: E,
182
+ onPointerCancel: E,
183
+ className: e("zen__toast group glass glass-blur glow-edge text-card-foreground absolute! inset-x-0 bottom-0 origin-bottom touch-pan-y overflow-hidden rounded-2xl border select-none", "transition-[transform,translate,opacity,height] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] data-swiping:transition-none", v && "starting:translate-y-full starting:opacity-0", n.hidden && "opacity-0", t.leaving === "fade" && "translate-y-[35%] opacity-0", t.leaving === "swipe" && "translate-x-full opacity-0", m.ring, m.glow),
184
+ style: {
185
+ zIndex: r,
186
+ height: n.height,
187
+ transform: `translateX(var(--zen-swipe, 0px)) translateY(${n.y}px) scale(${n.scale})`
188
+ },
189
+ children: [/* @__PURE__ */ f("div", {
190
+ ref: _,
191
+ className: "flex items-start gap-3 p-3.5 pr-10 transition-opacity duration-300 group-data-behind:opacity-0",
192
+ children: [
193
+ /* @__PURE__ */ d("span", {
194
+ className: e("mt-0.5 grid size-8 shrink-0 place-items-center rounded-full", m.badge),
195
+ "aria-hidden": !0,
196
+ children: /* @__PURE__ */ d(h, { className: "size-4" })
197
+ }),
198
+ /* @__PURE__ */ f("div", {
199
+ className: "flex min-w-0 flex-1 flex-col gap-0.5 pt-0.5",
200
+ children: [
201
+ /* @__PURE__ */ d("div", {
202
+ className: "text-sm font-semibold",
203
+ children: t.title
204
+ }),
205
+ t.description && /* @__PURE__ */ d("div", {
206
+ className: "text-muted-foreground text-sm leading-5",
207
+ children: t.description
208
+ }),
209
+ t.action && /* @__PURE__ */ d("button", {
210
+ type: "button",
211
+ onClick: () => {
212
+ t.action?.onClick(), a(t.id);
213
+ },
214
+ className: "border-tint/10 bg-tint/[0.06] hover:bg-tint/[0.12] focus-visible:ring-ring/50 mt-2 self-start rounded-lg border px-3 py-1 text-xs font-medium outline-hidden transition-colors focus-visible:ring-2",
215
+ children: t.action.label
216
+ })
217
+ ]
218
+ }),
219
+ /* @__PURE__ */ d("button", {
220
+ type: "button",
221
+ "aria-label": "Dismiss",
222
+ onClick: () => a(t.id),
223
+ className: "text-muted-foreground hover:bg-tint/[0.07] hover:text-foreground focus-visible:ring-ring/50 absolute top-2.5 right-2.5 grid size-7 place-items-center rounded-lg outline-hidden transition-colors focus-visible:ring-2",
224
+ children: /* @__PURE__ */ d("svg", {
225
+ viewBox: "0 0 16 16",
226
+ fill: "none",
227
+ stroke: "currentColor",
228
+ strokeWidth: "1.8",
229
+ strokeLinecap: "round",
230
+ className: "size-3.5",
231
+ "aria-hidden": !0,
232
+ children: /* @__PURE__ */ d("path", { d: "m4 4 8 8M12 4l-8 8" })
233
+ })
234
+ })
235
+ ]
236
+ }), t.timeout > 0 && /* @__PURE__ */ d("span", {
237
+ "aria-hidden": !0,
238
+ className: e("zen__toast-timer absolute bottom-0 left-0 h-0.5 w-full origin-left opacity-60 transition-opacity group-data-behind:opacity-0", m.bar),
239
+ style: {
240
+ animationDuration: `${t.timeout}ms`,
241
+ animationDelay: `${-S}ms`,
242
+ animationPlayState: i ? "paused" : void 0
243
+ }
244
+ })]
245
+ });
246
+ }
247
+ //#endregion
248
+ export { w as default, D as useToast, T as useToastHost };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/toggle/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACnF,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,WAAW,+BAsChD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/toggle/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACnF,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,WAAW,+BAwChD"}