@rinzai/zen 0.5.0 → 0.6.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.
Files changed (172) hide show
  1. package/README.md +2 -2
  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 +96 -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 +362 -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 +262 -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.js +41 -0
  81. package/dist/money-input/index.d.ts +77 -7
  82. package/dist/money-input/index.d.ts.map +1 -1
  83. package/dist/money-input/index.js +304 -0
  84. package/dist/month-picker/index.d.ts +4 -3
  85. package/dist/month-picker/index.d.ts.map +1 -1
  86. package/dist/month-picker/index.js +93 -0
  87. package/dist/page-header/index.js +26 -0
  88. package/dist/pills/index.d.ts +35 -0
  89. package/dist/pills/index.d.ts.map +1 -0
  90. package/dist/pills/index.js +50 -0
  91. package/dist/popover/index.d.ts +41 -22
  92. package/dist/popover/index.d.ts.map +1 -1
  93. package/dist/popover/index.js +75 -0
  94. package/dist/progress-ring/index.js +49 -0
  95. package/dist/radio-cards/index.d.ts +34 -0
  96. package/dist/radio-cards/index.d.ts.map +1 -0
  97. package/dist/radio-cards/index.js +48 -0
  98. package/dist/radio-group/index.d.ts +39 -0
  99. package/dist/radio-group/index.d.ts.map +1 -0
  100. package/dist/radio-group/index.js +63 -0
  101. package/dist/segmented/index.d.ts +16 -6
  102. package/dist/segmented/index.d.ts.map +1 -1
  103. package/dist/segmented/index.js +58 -0
  104. package/dist/select/index.d.ts +28 -14
  105. package/dist/select/index.d.ts.map +1 -1
  106. package/dist/select/index.js +187 -0
  107. package/dist/side-nav/index.js +37 -0
  108. package/dist/skeleton/index.js +12 -0
  109. package/dist/slider/index.js +34 -0
  110. package/dist/spinner/index.js +14 -0
  111. package/dist/tab-bar/index.d.ts +3 -0
  112. package/dist/tab-bar/index.d.ts.map +1 -1
  113. package/dist/tab-bar/index.js +34 -0
  114. package/dist/table/index.js +148 -0
  115. package/dist/table-of-contents/index.js +37 -0
  116. package/dist/tabs/index.d.ts +3 -2
  117. package/dist/tabs/index.d.ts.map +1 -1
  118. package/dist/tabs/index.js +114 -0
  119. package/dist/tailwind.css +1 -1
  120. package/dist/textarea/index.d.ts.map +1 -1
  121. package/dist/textarea/index.js +16 -0
  122. package/dist/theme-toggle/index.js +43 -0
  123. package/dist/theme.css +178 -13
  124. package/dist/toast/index.d.ts +6 -1
  125. package/dist/toast/index.d.ts.map +1 -1
  126. package/dist/toast/index.js +248 -0
  127. package/dist/toggle/index.d.ts.map +1 -1
  128. package/dist/toggle/index.js +26 -0
  129. package/dist/tooltip/index.d.ts +25 -0
  130. package/dist/tooltip/index.d.ts.map +1 -0
  131. package/dist/tooltip/index.js +108 -0
  132. package/dist/tree/index.d.ts.map +1 -1
  133. package/dist/tree/index.js +135 -0
  134. package/dist/utils/cva.js +25 -0
  135. package/dist/utils/cx.js +6 -0
  136. package/dist/utils/date.d.ts +37 -0
  137. package/dist/utils/date.d.ts.map +1 -0
  138. package/dist/utils/date.js +68 -0
  139. package/dist/utils/field-chevron.js +19 -0
  140. package/dist/utils/fx.d.ts +30 -0
  141. package/dist/utils/fx.d.ts.map +1 -0
  142. package/dist/utils/fx.js +21 -0
  143. package/dist/utils/graphics.js +33 -0
  144. package/dist/utils/indicator.d.ts +24 -0
  145. package/dist/utils/indicator.d.ts.map +1 -0
  146. package/dist/utils/indicator.js +37 -0
  147. package/dist/utils/merge.js +305 -0
  148. package/dist/utils/money.js +73 -0
  149. package/dist/utils/month.js +46 -0
  150. package/dist/utils/slot.d.ts +9 -5
  151. package/dist/utils/slot.d.ts.map +1 -1
  152. package/dist/utils/slot.js +25 -0
  153. package/dist/utils/status-icons.js +48 -0
  154. package/dist/utils/styles.d.ts +6 -6
  155. package/dist/utils/styles.d.ts.map +1 -1
  156. package/dist/utils/styles.js +6 -0
  157. package/dist/utils/theme.js +200 -0
  158. package/dist/utils/useAnchoredPopup.d.ts +8 -2
  159. package/dist/utils/useAnchoredPopup.d.ts.map +1 -1
  160. package/dist/utils/useAnchoredPopup.js +63 -0
  161. package/dist/utils/useHydrated.js +9 -0
  162. package/dist/utils/useVirtualList.js +45 -0
  163. package/dist/variables.css +22 -0
  164. package/dist/zen.css +1 -1
  165. package/package.json +9 -4
  166. package/dist/actions-menu/index.d.ts +0 -18
  167. package/dist/actions-menu/index.d.ts.map +0 -1
  168. package/dist/dropdown/index.d.ts +0 -28
  169. package/dist/dropdown/index.d.ts.map +0 -1
  170. package/dist/nav-pills/index.d.ts +0 -31
  171. package/dist/nav-pills/index.d.ts.map +0 -1
  172. 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,28 +138,71 @@
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
208
  * properties correctly. Phones: a live blur over scrolling content is the main
@@ -172,6 +231,20 @@
172
231
  }
173
232
  }
174
233
 
234
+ /*
235
+ * Over the dot grid, the Header is lightly frosted so the dots stay visible
236
+ * behind it (a heavy blur smears them into a grey band). Only a Header after
237
+ * that Backdrop (the page's own backdrop comes first in <body>; a backdrop in a
238
+ * demo frame doesn't reach the page's header). :where keeps this below the
239
+ * lite-graphics and touch rules that follow.
240
+ */
241
+ :where(.zen-backdrop[data-pattern='dots'] ~ *) .zen__header,
242
+ :where(.zen-backdrop[data-pattern='dots']) ~ .zen__header {
243
+ background-color: oklch(var(--background) / 0.75);
244
+ -webkit-backdrop-filter: blur(2px);
245
+ backdrop-filter: blur(2px);
246
+ }
247
+
175
248
  /* ───────────────────────── Lite graphics ───────────────────────── */
176
249
 
177
250
  /*
@@ -710,6 +783,13 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
710
783
  display 150ms allow-discrete;
711
784
  }
712
785
  .zen__dialog {
786
+ /*
787
+ * Fixed to the viewport, as the browser places modal dialogs. glow-edge sets
788
+ * position: relative (so its light has a box), and in the top layer relative
789
+ * computes to absolute: the dialog would be placed from the top of the
790
+ * document, off screen once the page is scrolled.
791
+ */
792
+ position: fixed;
713
793
  transition:
714
794
  opacity 200ms var(--ease-out-soft),
715
795
  scale 200ms var(--ease-out-soft),
@@ -730,6 +810,26 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
730
810
  .zen__dialog:not([open])::backdrop {
731
811
  opacity: 0;
732
812
  }
813
+ /* Sheets slide from their edge instead of scaling up. */
814
+ .zen__dialog[data-side] {
815
+ transition:
816
+ translate 320ms cubic-bezier(0.2, 0.8, 0.2, 1),
817
+ opacity 200ms,
818
+ overlay 320ms allow-discrete,
819
+ display 320ms allow-discrete;
820
+ }
821
+ .zen__dialog[data-side]:not([open]) {
822
+ scale: none;
823
+ }
824
+ .zen__dialog[data-side='bottom']:not([open]) {
825
+ translate: 0 100%;
826
+ }
827
+ .zen__dialog[data-side='right']:not([open]) {
828
+ translate: 100% 0;
829
+ }
830
+ .zen__dialog[data-side='left']:not([open]) {
831
+ translate: -100% 0;
832
+ }
733
833
  @starting-style {
734
834
  .zen__popover:popover-open,
735
835
  .zen__dialog[open] {
@@ -739,6 +839,18 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
739
839
  .zen__dialog[open]::backdrop {
740
840
  opacity: 0;
741
841
  }
842
+ .zen__dialog[data-side][open] {
843
+ scale: none;
844
+ }
845
+ .zen__dialog[data-side='bottom'][open] {
846
+ translate: 0 100%;
847
+ }
848
+ .zen__dialog[data-side='right'][open] {
849
+ translate: 100% 0;
850
+ }
851
+ .zen__dialog[data-side='left'][open] {
852
+ translate: -100% 0;
853
+ }
742
854
  }
743
855
  /*
744
856
  * The page behind a modal dialog doesn't scroll. Hiding the overflow removes
@@ -800,7 +912,12 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
800
912
  transition: border-color 200ms;
801
913
  }
802
914
 
803
- /* Direct children of a .rise container enter one after another. */
915
+ /*
916
+ * Direct children of a .rise container enter one after another. Filled backwards
917
+ * only: holding the end state (both/forwards) keeps a transform on the page,
918
+ * and Chrome then stops frosted glass inside it (e.g. sticky table parts) from
919
+ * blurring the sticky cells beneath. The end state is the natural style anyway.
920
+ */
804
921
  @keyframes zen-rise {
805
922
  from {
806
923
  opacity: 0;
@@ -808,7 +925,7 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
808
925
  }
809
926
  }
810
927
  .rise > * {
811
- animation: zen-rise 0.5s var(--ease-out-soft) both;
928
+ animation: zen-rise 0.5s var(--ease-out-soft) backwards;
812
929
  }
813
930
  .rise > *:nth-child(2) {
814
931
  animation-delay: 50ms;
@@ -823,23 +940,36 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
823
940
  animation-delay: 200ms;
824
941
  }
825
942
 
826
- /* Loading placeholders: a soft light sweeping across. */
943
+ /*
944
+ * Loading placeholders: a soft light sweeping across. The light is a layer
945
+ * three times as wide sliding through the placeholder, moved by transform so
946
+ * the compositor runs it: animating background-position repainted every
947
+ * placeholder on every frame.
948
+ */
827
949
  .zen__skeleton {
828
- background: linear-gradient(
950
+ position: relative;
951
+ overflow: hidden;
952
+ isolation: isolate;
953
+ &::before {
954
+ content: '';
955
+ position: absolute;
956
+ inset: 0 auto 0 0;
957
+ width: 300%;
958
+ background: linear-gradient(
829
959
  100deg,
830
960
  oklch(var(--tint) / 0.04) 30%,
831
961
  oklch(var(--tint) / 0.09) 50%,
832
962
  oklch(var(--tint) / 0.04) 70%
833
- )
834
- 0 0 / 300% 100%;
835
- animation: zen-shimmer 1.6s ease-in-out infinite;
963
+ );
964
+ animation: zen-shimmer 1.6s ease-in-out infinite;
965
+ }
836
966
  }
837
967
  @keyframes zen-shimmer {
838
968
  from {
839
- background-position: 100% 0;
969
+ transform: translateX(-66.6667%);
840
970
  }
841
971
  to {
842
- background-position: 0 0;
972
+ transform: translateX(0);
843
973
  }
844
974
  }
845
975
 
@@ -863,6 +993,41 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
863
993
  }
864
994
  }
865
995
 
996
+ /* Charts: lines draw themselves in, bars grow from the baseline, fills and donut segments fade up. */
997
+ .zen__chart-draw {
998
+ stroke-dasharray: 1;
999
+ animation: zen-chart-draw 0.9s cubic-bezier(0.3, 0.7, 0.2, 1) both;
1000
+ }
1001
+ @keyframes zen-chart-draw {
1002
+ from {
1003
+ stroke-dashoffset: 1;
1004
+ }
1005
+ to {
1006
+ stroke-dashoffset: 0;
1007
+ }
1008
+ }
1009
+ .zen__chart-grow {
1010
+ transform-box: fill-box;
1011
+ transform-origin: bottom;
1012
+ animation: zen-chart-grow 0.6s cubic-bezier(0.2, 0.8, 0.2, 1) both;
1013
+ }
1014
+ .zen__chart-grow[data-negative] {
1015
+ transform-origin: top;
1016
+ }
1017
+ @keyframes zen-chart-grow {
1018
+ from {
1019
+ transform: scaleY(0);
1020
+ }
1021
+ }
1022
+ .zen__chart-fade {
1023
+ animation: zen-chart-fade 0.8s ease-out both;
1024
+ }
1025
+ @keyframes zen-chart-fade {
1026
+ from {
1027
+ opacity: 0;
1028
+ }
1029
+ }
1030
+
866
1031
  /* Reduced motion: the OS setting, or opt in with html.reduce-motion. */
867
1032
  @media (prefers-reduced-motion: reduce) {
868
1033
  .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"}
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { cx as e } from "../utils/cx.js";
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
+ //#region packages/toggle/index.tsx
5
+ function r(r) {
6
+ let { className: i, onChange: a, onKeyDown: o, disabled: s, ...c } = r;
7
+ return /* @__PURE__ */ n("label", {
8
+ className: e("zen__toggle border-tint/10 bg-tint/[0.06] relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border p-0.5", "has-focus-visible:ring-glow/50 transition-[background-color,box-shadow,border-color] duration-300 has-focus-visible:ring-2", "has-checked:border-glow/60 has-checked:bg-glow/40 has-checked:shadow-[0_0_18px_-2px_oklch(var(--glow)/0.8)]", "has-disabled:cursor-not-allowed has-disabled:opacity-50", i),
9
+ children: [/* @__PURE__ */ t("input", {
10
+ type: "checkbox",
11
+ role: "switch",
12
+ className: "peer absolute inset-0 z-10 m-0 size-full cursor-pointer appearance-none rounded-full opacity-0 disabled:cursor-not-allowed",
13
+ disabled: s,
14
+ onChange: (e) => a?.(e.target.checked),
15
+ onKeyDown: (e) => {
16
+ o?.(e), e.key === "Enter" && !e.defaultPrevented && (e.preventDefault(), e.currentTarget.click());
17
+ },
18
+ ...c
19
+ }), /* @__PURE__ */ t("span", {
20
+ "aria-hidden": !0,
21
+ className: e("size-[1.125rem] rounded-full bg-white/70 shadow-md", "transition-[translate,background-color] duration-300 ease-[cubic-bezier(0.2,0.8,0.2,1)]", "peer-checked:translate-x-5 peer-checked:bg-white")
22
+ })]
23
+ });
24
+ }
25
+ //#endregion
26
+ export { r as default };
@@ -0,0 +1,25 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ /**
3
+ * A short hint shown while the pointer is over its trigger or the trigger has
4
+ * keyboard focus; Escape hides it. The trigger is described by it for screen
5
+ * readers. Put a TooltipTrigger and a TooltipContent inside. For anything to
6
+ * click or fill in, use Popover.
7
+ */
8
+ export default function Tooltip({ children }: {
9
+ children?: ReactNode;
10
+ }): import('react').JSX.Element;
11
+ /** What the tooltip describes: a button by default. With `asChild`, your own focusable element instead. */
12
+ export declare function TooltipTrigger({ asChild, style, onPointerEnter, onPointerLeave, onFocus, onBlur, onKeyDown, children, ...rest }: TooltipTriggerProps): import('react').JSX.Element;
13
+ /** The hint: glass, below the trigger (above it if there's no room), centred on it by default. */
14
+ export declare function TooltipContent({ align, offset, className, style, onPointerEnter, onPointerLeave, children, ...rest }: TooltipContentProps): import('react').JSX.Element;
15
+ export interface TooltipTriggerProps extends ComponentProps<'button'> {
16
+ /** Put the trigger's props on your own focusable element instead of rendering a button. */
17
+ asChild?: boolean;
18
+ }
19
+ export interface TooltipContentProps extends ComponentProps<'div'> {
20
+ /** Centred on the trigger (default), or lined up with its start or end edge. */
21
+ align?: 'start' | 'end' | 'center';
22
+ /** Gap from the trigger, in px. */
23
+ offset?: number;
24
+ }
25
+ //# sourceMappingURL=index.d.ts.map