@rinzai/zen 0.8.6 → 0.9.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 (75) hide show
  1. package/dist/animated-number/index.d.ts.map +1 -1
  2. package/dist/animated-number/index.js +19 -18
  3. package/dist/breadcrumbs/index.d.ts +15 -0
  4. package/dist/breadcrumbs/index.d.ts.map +1 -0
  5. package/dist/breadcrumbs/index.js +39 -0
  6. package/dist/card/index.d.ts +3 -1
  7. package/dist/card/index.d.ts.map +1 -1
  8. package/dist/card/index.js +3 -2
  9. package/dist/chart/donut.d.ts.map +1 -1
  10. package/dist/chart/donut.js +72 -70
  11. package/dist/chart/index.d.ts.map +1 -1
  12. package/dist/chart/index.js +154 -152
  13. package/dist/code-block/index.js +1 -1
  14. package/dist/code-input/index.d.ts +20 -0
  15. package/dist/code-input/index.d.ts.map +1 -0
  16. package/dist/code-input/index.js +44 -0
  17. package/dist/command-palette/index.d.ts +37 -0
  18. package/dist/command-palette/index.d.ts.map +1 -0
  19. package/dist/command-palette/index.js +120 -0
  20. package/dist/dialog/index.d.ts +9 -1
  21. package/dist/dialog/index.d.ts.map +1 -1
  22. package/dist/dialog/index.js +116 -32
  23. package/dist/empty-state/index.d.ts +14 -0
  24. package/dist/empty-state/index.d.ts.map +1 -0
  25. package/dist/empty-state/index.js +31 -0
  26. package/dist/file-drop/index.d.ts +18 -0
  27. package/dist/file-drop/index.d.ts.map +1 -0
  28. package/dist/file-drop/index.js +49 -0
  29. package/dist/index.d.ts +13 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/lib.js +75 -63
  32. package/dist/pagination/index.d.ts +26 -0
  33. package/dist/pagination/index.d.ts.map +1 -0
  34. package/dist/pagination/index.js +62 -0
  35. package/dist/skeleton/index.d.ts +12 -2
  36. package/dist/skeleton/index.d.ts.map +1 -1
  37. package/dist/skeleton/index.js +11 -5
  38. package/dist/sparkline/index.d.ts +15 -0
  39. package/dist/sparkline/index.d.ts.map +1 -0
  40. package/dist/sparkline/index.js +56 -0
  41. package/dist/stepper/index.d.ts +19 -0
  42. package/dist/stepper/index.d.ts.map +1 -0
  43. package/dist/stepper/index.js +53 -0
  44. package/dist/table/index.d.ts +6 -1
  45. package/dist/table/index.d.ts.map +1 -1
  46. package/dist/table/index.js +78 -46
  47. package/dist/table-of-contents/index.d.ts +1 -0
  48. package/dist/table-of-contents/index.d.ts.map +1 -1
  49. package/dist/table-of-contents/index.js +25 -23
  50. package/dist/tag-input/index.d.ts +19 -0
  51. package/dist/tag-input/index.d.ts.map +1 -0
  52. package/dist/tag-input/index.js +61 -0
  53. package/dist/theme.css +159 -0
  54. package/dist/timeline/index.d.ts +18 -0
  55. package/dist/timeline/index.d.ts.map +1 -0
  56. package/dist/timeline/index.js +45 -0
  57. package/dist/tree/index.d.ts.map +1 -1
  58. package/dist/tree/index.js +68 -67
  59. package/dist/utils/indicator.d.ts.map +1 -1
  60. package/dist/utils/indicator.js +1 -1
  61. package/dist/utils/motion.d.ts +3 -0
  62. package/dist/utils/motion.d.ts.map +1 -0
  63. package/dist/utils/motion.js +7 -0
  64. package/dist/utils/section-link.d.ts +9 -0
  65. package/dist/utils/section-link.d.ts.map +1 -0
  66. package/dist/utils/section-link.js +10 -0
  67. package/dist/utils/theme-wave.d.ts.map +1 -1
  68. package/dist/utils/theme-wave.js +72 -71
  69. package/dist/utils/useAnchoredPopup.d.ts.map +1 -1
  70. package/dist/utils/useAnchoredPopup.js +6 -1
  71. package/dist/utils/useSeen.d.ts +4 -0
  72. package/dist/utils/useSeen.d.ts.map +1 -0
  73. package/dist/utils/useSeen.js +17 -0
  74. package/dist/zen.css +1 -1
  75. package/package.json +1 -1
@@ -1,107 +1,139 @@
1
1
  "use client";
2
2
  import { cx as e } from "../utils/cx.js";
3
- import t from "../icons/chevron-down.js";
4
- import n from "../icons/chevron-up.js";
5
- import { useCallback as r, useEffect as i, useMemo as a, useRef as o, useState as s } from "react";
6
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
3
+ import { reducedMotion as t } from "../utils/motion.js";
4
+ import n from "../icons/chevron-down.js";
5
+ import r from "../icons/chevron-up.js";
6
+ import { useCallback as i, useEffect as a, useLayoutEffect as o, useMemo as s, useRef as c, useState as l } from "react";
7
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
7
8
  //#region packages/table/index.tsx
8
- function u({ label: t, className: n, ref: a, onScroll: s, ...l }) {
9
- let u = o(null), d = r(() => {
10
- let e = u.current;
9
+ function f({ label: t, className: n, ref: r, onScroll: o, ...s }) {
10
+ let l = c(null), d = i(() => {
11
+ let e = l.current;
11
12
  if (!e) return;
12
13
  let t = (t, n) => n !== e.hasAttribute(t) && e.toggleAttribute(t, n);
13
14
  t("data-under-top", e.scrollTop > 0), t("data-under-left", e.scrollLeft > 0), t("data-under-bottom", e.scrollTop + e.clientHeight < e.scrollHeight - 1);
14
15
  }, []);
15
- return i(() => {
16
- let e = u.current;
16
+ return a(() => {
17
+ let e = l.current;
17
18
  if (!e) return;
18
19
  d();
19
20
  let t = typeof ResizeObserver > "u" ? null : new ResizeObserver(d);
20
21
  return t?.observe(e), e.firstElementChild && t?.observe(e.firstElementChild), () => t?.disconnect();
21
- }, [d]), /* @__PURE__ */ c("div", {
22
+ }, [d]), /* @__PURE__ */ u("div", {
22
23
  className: e("zen__table-panel glass glow-edge isolate flex flex-col overflow-hidden rounded-xl", n),
23
- children: /* @__PURE__ */ c("div", {
24
+ children: /* @__PURE__ */ u("div", {
24
25
  ref: (e) => {
25
- u.current = e, typeof a == "function" ? a(e) : a && (a.current = e);
26
+ l.current = e, typeof r == "function" ? r(e) : r && (r.current = e);
26
27
  },
27
28
  onScroll: (e) => {
28
- d(), s?.(e);
29
+ d(), o?.(e);
29
30
  },
30
31
  role: t ? "region" : void 0,
31
32
  "aria-label": t,
32
33
  tabIndex: t ? 0 : void 0,
33
34
  className: "zen__table-container focus-visible:ring-ring/30 min-h-0 overflow-auto rounded-[inherit] outline-hidden will-change-scroll focus-visible:ring-2 focus-visible:ring-inset",
34
- ...l
35
+ ...s
35
36
  })
36
37
  });
37
38
  }
38
- function d({ className: t, ...n }) {
39
- return /* @__PURE__ */ c("table", {
39
+ function p({ className: t, ...n }) {
40
+ return /* @__PURE__ */ u("table", {
40
41
  className: e("zen__table w-full border-separate border-spacing-0 text-sm", t),
41
42
  ...n
42
43
  });
43
44
  }
44
- function f({ className: t, ...n }) {
45
- return /* @__PURE__ */ c("thead", {
45
+ function m({ className: t, ...n }) {
46
+ return /* @__PURE__ */ u("thead", {
46
47
  className: e("zen__sticky-top sticky top-0 z-20", t),
47
48
  ...n
48
49
  });
49
50
  }
50
- function p(e) {
51
- return /* @__PURE__ */ c("tbody", { ...e });
51
+ function h({ ref: e, ...n }) {
52
+ let r = c(null), i = c(null);
53
+ return g(() => {
54
+ let e = r.current;
55
+ if (!e) return;
56
+ let n = [...e.rows], a = i.current;
57
+ if (a && n.length === a.rows.length && n.every((e, t) => e === a.rows[t])) return;
58
+ let o = new Map(n.map((e) => [e, e.offsetTop]));
59
+ if (i.current = {
60
+ rows: n,
61
+ tops: o
62
+ }, !(!a || t() || e.querySelector("[data-zen-spacer]"))) for (let e of n) {
63
+ let t = a.tops.get(e);
64
+ t === void 0 ? e.hasAttribute("data-tree-key") || e.animate?.({
65
+ opacity: [0, 1],
66
+ translate: ["0 -6px", "0 0"]
67
+ }, v) : t !== o.get(e) && e.animate?.({ translate: [`0 ${t - o.get(e)}px`, "0 0"] }, _);
68
+ }
69
+ }), /* @__PURE__ */ u("tbody", {
70
+ ref: (t) => {
71
+ if (r.current = t, typeof e == "function") return e(t);
72
+ e && (e.current = t);
73
+ },
74
+ ...n
75
+ });
52
76
  }
53
- function m({ className: t, ...n }) {
54
- return /* @__PURE__ */ c("tfoot", {
77
+ var g = typeof window > "u" ? a : o, _ = {
78
+ duration: 320,
79
+ easing: "cubic-bezier(0.2, 0.8, 0.2, 1)"
80
+ }, v = {
81
+ duration: 260,
82
+ easing: "ease-out"
83
+ };
84
+ function y({ className: t, ...n }) {
85
+ return /* @__PURE__ */ u("tfoot", {
55
86
  className: e("zen__sticky-bottom sticky bottom-0 z-20", t),
56
87
  ...n
57
88
  });
58
89
  }
59
- function h({ className: t, ...n }) {
60
- return /* @__PURE__ */ c("tr", {
90
+ function b({ className: t, ...n }) {
91
+ return /* @__PURE__ */ u("tr", {
61
92
  className: e("group", t),
62
93
  ...n
63
94
  });
64
95
  }
65
- function g({ numeric: r, sticky: i, sortDirection: a, onSort: o, scope: s = "col", className: u, children: d, ...f }) {
66
- return /* @__PURE__ */ c("th", {
96
+ function x({ numeric: t, sticky: i, sortDirection: a, onSort: o, scope: s = "col", className: c, children: l, ...f }) {
97
+ return /* @__PURE__ */ u("th", {
67
98
  scope: s,
68
99
  "aria-sort": a === "asc" ? "ascending" : a === "desc" ? "descending" : void 0,
69
- className: e("border-tint/[0.07] text-muted-foreground border-b px-3 py-2.5 align-middle text-xs leading-5 font-medium tracking-wider whitespace-nowrap uppercase", i === "left" && "zen__sticky-left sticky left-0 z-10", r ? "text-right" : "text-left", u),
100
+ className: e("border-tint/[0.07] text-muted-foreground border-b px-3 py-2.5 align-middle text-xs leading-5 font-medium tracking-wider whitespace-nowrap uppercase", i === "left" && "zen__sticky-left sticky left-0 z-10", t ? "text-right" : "text-left", c),
70
101
  ...f,
71
- children: o ? /* @__PURE__ */ l("button", {
102
+ children: o ? /* @__PURE__ */ d("button", {
72
103
  type: "button",
73
104
  onClick: o,
74
- className: e("hover:text-foreground inline-flex cursor-pointer items-center gap-1 align-middle leading-5 tracking-wider uppercase", r && "flex-row-reverse"),
75
- children: [d, /* @__PURE__ */ c("span", {
105
+ className: e("hover:text-foreground touch-target inline-flex cursor-pointer items-center gap-1 align-middle leading-5 tracking-wider uppercase", t && "flex-row-reverse"),
106
+ children: [l, /* @__PURE__ */ u("span", {
76
107
  "aria-hidden": !0,
77
108
  className: "inline-flex w-3",
78
- children: a === "asc" ? /* @__PURE__ */ c(n, {
109
+ children: a === "asc" ? /* @__PURE__ */ u(r, {
79
110
  className: "size-3",
80
111
  strokeWidth: 2.5
81
- }) : a === "desc" ? /* @__PURE__ */ c(t, {
112
+ }) : a === "desc" ? /* @__PURE__ */ u(n, {
82
113
  className: "size-3",
83
114
  strokeWidth: 2.5
84
115
  }) : null
85
116
  })]
86
- }) : d
117
+ }) : l
87
118
  });
88
119
  }
89
- function _({ numeric: t, sticky: n, className: r, ...i }) {
90
- return /* @__PURE__ */ c("td", {
120
+ function S({ numeric: t, sticky: n, className: r, ...i }) {
121
+ return /* @__PURE__ */ u("td", {
91
122
  className: e("border-tint/[0.045] border-b px-3 py-2.5 transition-colors duration-150", "group-hover:[background-image:linear-gradient(oklch(var(--tint)/0.035),oklch(var(--tint)/0.035))]", n === "left" && "zen__sticky-left sticky left-0 z-10 shadow-[inset_-1px_0_0_oklch(var(--tint)/0.06)]", t && "text-right tabular-nums", r),
92
123
  ...i
93
124
  });
94
125
  }
95
- function v({ numeric: t, sticky: n, className: r, ...i }) {
96
- return /* @__PURE__ */ c("td", {
126
+ function C({ numeric: t, sticky: n, className: r, ...i }) {
127
+ return /* @__PURE__ */ u("td", {
97
128
  className: e("border-tint/[0.07] h-9 border-t px-3 font-medium whitespace-nowrap", n === "left" && "zen__sticky-left sticky left-0 z-10 shadow-[inset_-1px_0_0_oklch(var(--tint)/0.06)]", t && "text-right tabular-nums", r),
98
129
  ...i
99
130
  });
100
131
  }
101
- function y({ height: e, colSpan: t }) {
102
- return e <= 0 ? null : /* @__PURE__ */ c("tr", {
132
+ function w({ height: e, colSpan: t }) {
133
+ return e <= 0 ? null : /* @__PURE__ */ u("tr", {
103
134
  "aria-hidden": !0,
104
- children: /* @__PURE__ */ c("td", {
135
+ "data-zen-spacer": !0,
136
+ children: /* @__PURE__ */ u("td", {
105
137
  colSpan: t,
106
138
  style: {
107
139
  height: e,
@@ -111,17 +143,17 @@ function y({ height: e, colSpan: t }) {
111
143
  })
112
144
  });
113
145
  }
114
- function b({ colSpan: e, children: t = "Nothing here yet." }) {
115
- return /* @__PURE__ */ c("tr", { children: /* @__PURE__ */ c("td", {
146
+ function T({ colSpan: e, children: t = "Nothing here yet." }) {
147
+ return /* @__PURE__ */ u("tr", { children: /* @__PURE__ */ u("td", {
116
148
  colSpan: e,
117
149
  className: "text-muted-foreground px-3 py-8 text-center",
118
150
  children: t
119
151
  }) });
120
152
  }
121
- function x(e, t, n) {
122
- let [r, i] = s(n ?? null);
153
+ function E(e, t, n) {
154
+ let [r, i] = l(n ?? null);
123
155
  return {
124
- rows: a(() => {
156
+ rows: s(() => {
125
157
  if (!r) return e;
126
158
  let n = t[r.key], i = [...e].sort(n);
127
159
  return r.direction === "desc" ? i.reverse() : i;
@@ -145,4 +177,4 @@ function x(e, t, n) {
145
177
  };
146
178
  }
147
179
  //#endregion
148
- export { p as TableBody, _ as TableCell, u as TableContainer, b as TableEmpty, m as TableFooter, v as TableFooterCell, g as TableHead, f as TableHeader, h as TableRow, y as TableSpacerRow, d as default, x as useSort };
180
+ export { h as TableBody, S as TableCell, f as TableContainer, T as TableEmpty, y as TableFooter, C as TableFooterCell, x as TableHead, m as TableHeader, b as TableRow, w as TableSpacerRow, p as default, E as useSort };
@@ -12,6 +12,7 @@ export interface TableOfContentsItem {
12
12
  }
13
13
  export interface TableOfContentsProps {
14
14
  items: TableOfContentsItem[];
15
+ /** Shown above the list, and names it. Empty: no heading shown (e.g. under a trigger that says it). */
15
16
  title?: string;
16
17
  className?: string;
17
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/table-of-contents/index.tsx"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,KAAK,EAAE,KAAsB,EAAE,SAAS,EAAE,EAAE,oBAAoB,sCA6CzG;AAED,MAAM,WAAW,mBAAmB;IAChC,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/table-of-contents/index.tsx"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,KAAK,EAAE,KAAsB,EAAE,SAAS,EAAE,EAAE,oBAAoB,sCA8CzG;AAED,MAAM,WAAW,mBAAmB;IAChC,iDAAiD;IACjD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,uGAAuG;IACvG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB"}
@@ -1,37 +1,39 @@
1
1
  "use client";
2
2
  import { cx as e } from "../utils/cx.js";
3
- import { useEffect as t, useState as n } from "react";
4
- import { jsx as r, jsxs as i } from "react/jsx-runtime";
3
+ import { followSectionLink as t } from "../utils/section-link.js";
4
+ import { useEffect as n, useState as r } from "react";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
5
6
  //#region packages/table-of-contents/index.tsx
6
- function a({ items: a, title: o = "On this page", className: s }) {
7
- let [c, l] = n();
8
- return t(() => {
7
+ function o({ items: o, title: s = "On this page", className: c }) {
8
+ let [l, u] = r();
9
+ return n(() => {
9
10
  if (typeof IntersectionObserver > "u") return;
10
- let e = a.map((e) => document.getElementById(e.id)).filter((e) => !!e), t = /* @__PURE__ */ new Set(), n = new IntersectionObserver((e) => {
11
+ let e = o.map((e) => document.getElementById(e.id)).filter((e) => !!e), t = /* @__PURE__ */ new Set(), n = new IntersectionObserver((e) => {
11
12
  for (let n of e) n.isIntersecting ? t.add(n.target.id) : t.delete(n.target.id);
12
- let n = a.find((e) => t.has(e.id));
13
- n && l(n.id);
13
+ let n = o.find((e) => t.has(e.id));
14
+ n && u(n.id);
14
15
  }, { rootMargin: "0px 0px -65% 0px" });
15
16
  return e.forEach((e) => n.observe(e)), () => n.disconnect();
16
- }, [a]), a.length ? /* @__PURE__ */ i("nav", {
17
- "aria-label": o,
18
- className: e("zen__toc flex flex-col gap-3", s),
19
- children: [/* @__PURE__ */ r("p", {
17
+ }, [o]), o.length ? /* @__PURE__ */ a("nav", {
18
+ "aria-label": s || "On this page",
19
+ className: e("zen__toc flex flex-col gap-3", c),
20
+ children: [s && /* @__PURE__ */ i("p", {
20
21
  className: "text-muted-foreground text-2xs mt-0! tracking-widest uppercase",
21
- children: o
22
- }), /* @__PURE__ */ r("ul", {
22
+ children: s
23
+ }), /* @__PURE__ */ i("ul", {
23
24
  className: "border-tint/[0.07] flex flex-col gap-2 border-l text-sm",
24
- children: a.map((t) => /* @__PURE__ */ r("li", {
25
- className: e("-ml-px", t.depth === 2 && "pl-3"),
26
- children: /* @__PURE__ */ r("a", {
27
- href: `#${t.id}`,
28
- "aria-current": t.id === c ? "location" : void 0,
29
- className: e("text-muted-foreground hover:text-foreground block border-l border-transparent pl-3 transition-colors", "aria-[current=location]:border-primary aria-[current=location]:text-foreground"),
30
- children: t.label
25
+ children: o.map((n) => /* @__PURE__ */ i("li", {
26
+ className: e("-ml-px", n.depth === 2 && "pl-3"),
27
+ children: /* @__PURE__ */ i("a", {
28
+ href: `#${n.id}`,
29
+ onClick: t,
30
+ "aria-current": n.id === l ? "location" : void 0,
31
+ className: e("text-muted-foreground hover:text-foreground block border-l border-transparent pl-3 transition-colors pointer-coarse:py-1.5", "aria-[current=location]:border-primary aria-[current=location]:text-foreground"),
32
+ children: n.label
31
33
  })
32
- }, t.id))
34
+ }, n.id))
33
35
  })]
34
36
  }) : null;
35
37
  }
36
38
  //#endregion
37
- export { a as default };
39
+ export { o as default };
@@ -0,0 +1,19 @@
1
+ import { ComponentProps } from 'react';
2
+ /**
3
+ * A field of short values (tags, emails, labels): typing one and pressing
4
+ * Enter or a comma adds it, pasting a list adds each, Backspace in the empty
5
+ * field takes the last one back. Each is removed with its ×. Values are
6
+ * trimmed and kept once. Past about three rows the tags scroll, under a
7
+ * typing line that stays in view (a max-h-* class sets the field's height).
8
+ */
9
+ export default function TagInput({ value: controlled, defaultValue, onValueChange, validate, removeLabel, className, disabled, ...rest }: TagInputProps): import('react').JSX.Element;
10
+ export interface TagInputProps extends Omit<ComponentProps<'input'>, 'value' | 'defaultValue'> {
11
+ value?: string[];
12
+ defaultValue?: string[];
13
+ onValueChange?: (value: string[]) => void;
14
+ /** Whether an entry may be added (e.g. looks like an email). */
15
+ validate?: (entry: string) => boolean;
16
+ /** The × button's label, for screen readers. */
17
+ removeLabel?: (tag: string) => string;
18
+ }
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/tag-input/index.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAkB,cAAc,EAAoD,MAAM,OAAO,CAAC;AAEzG;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAC7B,KAAK,EAAE,UAAU,EACjB,YAAiB,EACjB,aAAa,EACb,QAAQ,EACR,WAAsC,EACtC,SAAS,EACT,QAAQ,EACR,GAAG,IAAI,EACV,EAAE,aAAa,+BAgGf;AAED,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IAC1F,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC1C,gEAAgE;IAChE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,gDAAgD;IAChD,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACzC"}
@@ -0,0 +1,61 @@
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 r from "../icons/micro/x-mark.js";
6
+ import { useLayoutEffect as i, useRef as a, useState as o } from "react";
7
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
8
+ //#region packages/tag-input/index.tsx
9
+ function l({ value: l, defaultValue: u = [], onValueChange: d, validate: f, removeLabel: p = (e) => `Remove ${e}`, className: m, disabled: h, ...g }) {
10
+ let [_, v] = o(u), y = l ?? _, [b, x] = o(""), S = n(g), C = a(null), w = y.length;
11
+ i(() => {
12
+ let e = C.current;
13
+ e?.parentElement?.contains(document.activeElement) && (e.scrollTop = e.scrollHeight);
14
+ }, [w]);
15
+ let T = (e) => {
16
+ l === void 0 && v(e), d?.(e);
17
+ }, E = (e) => {
18
+ let t = [...y];
19
+ for (let n of e.map((e) => e.trim())) n && !t.includes(n) && (f?.(n) ?? !0) && t.push(n);
20
+ t.length !== y.length && T(t);
21
+ };
22
+ return /* @__PURE__ */ c("div", {
23
+ className: e("zen__tag-input", t, "flex h-auto max-h-36 min-h-10 w-full cursor-text flex-col gap-1.5 py-1.5", "has-[input:focus-visible]:border-glow/60 has-[input:focus-visible]:bg-tint/[0.05] has-[input:focus-visible]:shadow-glow-focus has-[input:focus-visible]:[--glow-border-color:transparent]", h && "cursor-not-allowed opacity-50", m),
24
+ onClick: (e) => e.currentTarget.querySelector("input")?.focus(),
25
+ children: [w > 0 && /* @__PURE__ */ s("div", {
26
+ ref: C,
27
+ className: "flex min-h-0 flex-wrap gap-1.5 overflow-y-auto",
28
+ children: y.map((e) => /* @__PURE__ */ c("span", {
29
+ className: "zen__tag bg-primary/12 text-foreground inline-flex items-center gap-1 rounded-md py-0.5 pr-1 pl-2 text-xs shadow-[inset_0_0_0_1px_oklch(var(--primary)/0.25)]",
30
+ children: [e, /* @__PURE__ */ s("button", {
31
+ type: "button",
32
+ disabled: h,
33
+ "aria-label": p(e),
34
+ onClick: () => T(y.filter((t) => t !== e)),
35
+ className: "text-muted-foreground hover:text-foreground hover:bg-tint/10 focus-visible:ring-ring/50 touch-target grid size-4 cursor-pointer place-items-center rounded-sm outline-hidden focus-visible:ring-2",
36
+ children: /* @__PURE__ */ s(r, { className: "size-3" })
37
+ })]
38
+ }, e))
39
+ }), /* @__PURE__ */ s("input", {
40
+ ...g,
41
+ ...S,
42
+ disabled: h,
43
+ value: b,
44
+ onChange: (e) => x(e.target.value),
45
+ onKeyDown: (e) => {
46
+ g.onKeyDown?.(e), !(e.defaultPrevented || e.nativeEvent.isComposing) && ((e.key === "Enter" || e.key === ",") && b.trim() ? (e.preventDefault(), E([b]), x("")) : e.key === "Backspace" && !b && y.length && (e.preventDefault(), x(y[y.length - 1]), T(y.slice(0, -1))));
47
+ },
48
+ onBlur: (e) => {
49
+ g.onBlur?.(e), b.trim() && (E([b]), x(""));
50
+ },
51
+ onPaste: (e) => {
52
+ g.onPaste?.(e);
53
+ let t = e.clipboardData.getData("text");
54
+ !e.defaultPrevented && /[,\n]/.test(t) && (e.preventDefault(), E(t.split(/[,\n]/)));
55
+ },
56
+ className: "h-7 w-full shrink-0 bg-transparent outline-hidden placeholder:text-[color:oklch(var(--muted-foreground)/var(--zen-placeholder))]"
57
+ })]
58
+ });
59
+ }
60
+ //#endregion
61
+ export { l as default };
package/dist/theme.css CHANGED
@@ -224,6 +224,25 @@
224
224
  * surface's own `!` background (a Dialog's) is: an unlayered !important rule
225
225
  * loses to a layered one.
226
226
  */
227
+ /*
228
+ * On touch screens, a small control's hit area grows to at least 44px (centred on
229
+ * it), while it looks the same. For controls that aren't positioned themselves.
230
+ */
231
+ @utility touch-target {
232
+ @media (pointer: coarse) {
233
+ position: relative;
234
+ &::after {
235
+ content: '';
236
+ position: absolute;
237
+ top: 50%;
238
+ left: 50%;
239
+ translate: -50% -50%;
240
+ width: max(100%, 44px);
241
+ height: max(100%, 44px);
242
+ }
243
+ }
244
+ }
245
+
227
246
  @utility glass-blur {
228
247
  @apply backdrop-blur-[18px] backdrop-saturate-140;
229
248
  /*
@@ -383,6 +402,53 @@ html[data-zen-graphics='lite'] .zen__table-container[data-under-bottom] .zen__st
383
402
  --sh-comment: oklch(var(--muted-foreground));
384
403
  }
385
404
 
405
+ /*
406
+ * Code wider than its block fades out at the edge it carries on past. The mask is
407
+ * only in the keyframes: code that fits has no scroll timeline, so no mask at all.
408
+ */
409
+ @property --zen-code-l {
410
+ syntax: '<length>';
411
+ inherits: false;
412
+ initial-value: 0px;
413
+ }
414
+ @property --zen-code-r {
415
+ syntax: '<length>';
416
+ inherits: false;
417
+ initial-value: 0px;
418
+ }
419
+ @keyframes zen-code-fade {
420
+ 0% {
421
+ --zen-code-l: 0px;
422
+ --zen-code-r: 2rem;
423
+ }
424
+ 5% {
425
+ --zen-code-l: 2rem;
426
+ }
427
+ 95% {
428
+ --zen-code-r: 2rem;
429
+ }
430
+ 100% {
431
+ --zen-code-l: 2rem;
432
+ --zen-code-r: 0px;
433
+ }
434
+ 0%,
435
+ 100% {
436
+ mask-image: linear-gradient(
437
+ to right,
438
+ transparent,
439
+ #000 var(--zen-code-l),
440
+ #000 calc(100% - var(--zen-code-r)),
441
+ transparent
442
+ );
443
+ }
444
+ }
445
+ @supports (animation-timeline: scroll()) {
446
+ .zen__code-block pre {
447
+ animation: zen-code-fade linear both;
448
+ animation-timeline: scroll(self inline);
449
+ }
450
+ }
451
+
386
452
  /* ───────────────────────── Backdrop: contours / dots + light ───────────────────────── */
387
453
 
388
454
  .zen-backdrop {
@@ -930,6 +996,13 @@ html.zen-theme-closing::view-transition-old(zen-theme-area) {
930
996
  .zen__dialog:not([open])::backdrop {
931
997
  opacity: 0;
932
998
  }
999
+ /* A dialog opened from a button grows out of it, and shrinks back into it (useModal sets the origin). */
1000
+ .zen__dialog[data-zen-from] {
1001
+ transition-duration: 280ms;
1002
+ }
1003
+ .zen__dialog[data-zen-from]:not([open]) {
1004
+ scale: 0.4;
1005
+ }
933
1006
  /* Sheets slide from their edge instead of scaling up. */
934
1007
  .zen__dialog[data-side] {
935
1008
  transition:
@@ -953,6 +1026,18 @@ html.zen-theme-closing::view-transition-old(zen-theme-area) {
953
1026
  .zen__dialog[data-side='left']:not([open]) {
954
1027
  translate: -100% 0;
955
1028
  }
1029
+ /* A sheet being swiped back to its edge (useSheetSwipe): it follows the finger, and the scrim fades with it. */
1030
+ .zen__dialog[data-side][open] {
1031
+ translate: var(--zen-swipe, 0 0);
1032
+ }
1033
+ .zen__dialog[data-side][open]::backdrop {
1034
+ opacity: calc(1 - var(--zen-swipe-progress, 0));
1035
+ }
1036
+ .zen__dialog[data-swiping],
1037
+ .zen__dialog[data-swiping]::backdrop {
1038
+ transition: none;
1039
+ user-select: none;
1040
+ }
956
1041
  @starting-style {
957
1042
  .zen__popover:popover-open,
958
1043
  .zen__dialog[open] {
@@ -962,9 +1047,15 @@ html.zen-theme-closing::view-transition-old(zen-theme-area) {
962
1047
  .zen__dialog[open]::backdrop {
963
1048
  opacity: 0;
964
1049
  }
1050
+ .zen__dialog[data-zen-from][open] {
1051
+ scale: 0.4;
1052
+ }
965
1053
  .zen__dialog[data-side][open] {
966
1054
  scale: none;
967
1055
  }
1056
+ .zen__dialog[data-side][open]::backdrop {
1057
+ opacity: 0;
1058
+ }
968
1059
  .zen__dialog[data-side='bottom'][open] {
969
1060
  translate: 0 100%;
970
1061
  }
@@ -1096,6 +1187,37 @@ html.zen-theme-closing::view-transition-old(zen-theme-area) {
1096
1187
  }
1097
1188
  }
1098
1189
 
1190
+ /*
1191
+ * Morphs: a card opening into its page. Give the pair the view-transition class
1192
+ * zen-morph (React: <ViewTransition name=… share="zen-morph">). The box moves and
1193
+ * resizes; what's in it keeps its size, clipped to the box, so text never stretches.
1194
+ */
1195
+ ::view-transition-group(*.zen-morph) {
1196
+ animation-duration: 0.42s;
1197
+ animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
1198
+ }
1199
+ ::view-transition-image-pair(*.zen-morph) {
1200
+ overflow: clip;
1201
+ border-radius: var(--radius-xl);
1202
+ }
1203
+ ::view-transition-old(*.zen-morph),
1204
+ ::view-transition-new(*.zen-morph) {
1205
+ height: 100%;
1206
+ object-fit: none;
1207
+ object-position: top left;
1208
+ }
1209
+
1210
+ /* Content arriving where its placeholder was. */
1211
+ .zen__reveal {
1212
+ animation: zen-reveal 0.45s cubic-bezier(0.2, 0.8, 0.2, 1) both;
1213
+ }
1214
+ @keyframes zen-reveal {
1215
+ from {
1216
+ opacity: 0;
1217
+ translate: 0 4px;
1218
+ }
1219
+ }
1220
+
1099
1221
  /* Time left before a toast goes away. */
1100
1222
  .zen__toast-timer {
1101
1223
  animation: zen-toast-timer linear forwards;
@@ -1116,6 +1238,21 @@ html.zen-theme-closing::view-transition-old(zen-theme-area) {
1116
1238
  }
1117
1239
  }
1118
1240
 
1241
+ /* A tag added to a TagInput pops in. */
1242
+ .zen__tag {
1243
+ animation: zen-pop 0.3s var(--ease-out-soft) backwards;
1244
+ }
1245
+
1246
+ /* CodeInput's caret, in the box typing goes into. */
1247
+ .zen__code-caret {
1248
+ animation: zen-caret 1s steps(1) infinite;
1249
+ }
1250
+ @keyframes zen-caret {
1251
+ 50% {
1252
+ opacity: 0;
1253
+ }
1254
+ }
1255
+
1119
1256
  /* Charts: lines draw themselves in, bars grow from the baseline, fills and donut segments fade up. */
1120
1257
  .zen__chart-draw {
1121
1258
  stroke-dasharray: 1;
@@ -1150,6 +1287,28 @@ html.zen-theme-closing::view-transition-old(zen-theme-area) {
1150
1287
  opacity: 0;
1151
1288
  }
1152
1289
  }
1290
+ /* Held at their start until the chart is first on screen, so they're seen. */
1291
+ /*
1292
+ * A sparkline is revealed from the left instead: its stroke doesn't scale with the
1293
+ * stretched drawing (non-scaling-stroke), and Chrome then measures a dash in screen
1294
+ * pixels, not along the path, breaking the line up. Its points only go rightwards,
1295
+ * so the reveal draws it just the same.
1296
+ */
1297
+ .zen__sparkline-draw {
1298
+ animation: zen-sparkline-draw 0.9s cubic-bezier(0.3, 0.7, 0.2, 1) both;
1299
+ }
1300
+ @keyframes zen-sparkline-draw {
1301
+ from {
1302
+ clip-path: inset(0 100% 0 0);
1303
+ }
1304
+ to {
1305
+ clip-path: inset(0);
1306
+ }
1307
+ }
1308
+ [data-zen-unseen] :is(.zen__chart-draw, .zen__sparkline-draw, .zen__chart-grow, .zen__chart-fade),
1309
+ [data-zen-unseen]:is(.zen__chart-draw, .zen__sparkline-draw, .zen__chart-grow, .zen__chart-fade) {
1310
+ animation-play-state: paused;
1311
+ }
1153
1312
 
1154
1313
  /*
1155
1314
  * Reduced motion: the OS setting, or opt in with html.reduce-motion. It reaches
@@ -0,0 +1,18 @@
1
+ import { ComponentProps, ReactNode } from 'react';
2
+ /** Events in order, each on a dot joined by a line: an activity feed, a history. */
3
+ export default function Timeline({ className, ...rest }: ComponentProps<'ol'>): import('react').JSX.Element;
4
+ /**
5
+ * One event: its title, when (`time`), and anything more as children. `icon`
6
+ * replaces the dot; `active` lights it in the accent, e.g. what's happening now.
7
+ */
8
+ export declare function TimelineItem({ title, time, icon, active, className, children, ...rest }: TimelineItemProps): import('react').JSX.Element;
9
+ export interface TimelineItemProps extends Omit<ComponentProps<'li'>, 'title'> {
10
+ title: ReactNode;
11
+ /** When it happened, e.g. a <time> or "2 hours ago". */
12
+ time?: ReactNode;
13
+ /** An icon in place of the dot. */
14
+ icon?: ReactNode;
15
+ /** Lit in the accent: the current or latest event. */
16
+ active?: boolean;
17
+ }
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../packages/timeline/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElD,oFAAoF;AACpF,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,CAAC,IAAI,CAAC,+BAE5E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,iBAAiB,+BA8B1G;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAC1E,KAAK,EAAE,SAAS,CAAC;IACjB,wDAAwD;IACxD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,mCAAmC;IACnC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,sDAAsD;IACtD,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB"}
@@ -0,0 +1,45 @@
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/timeline/index.tsx
5
+ function r({ className: n, ...r }) {
6
+ return /* @__PURE__ */ t("ol", {
7
+ className: e("zen__timeline flex flex-col", n),
8
+ ...r
9
+ });
10
+ }
11
+ function i({ title: r, time: i, icon: a, active: o, className: s, children: c, ...l }) {
12
+ return /* @__PURE__ */ n("li", {
13
+ className: e("group/timeline relative flex gap-3 pb-6 last:pb-0", s),
14
+ ...l,
15
+ children: [
16
+ /* @__PURE__ */ t("span", {
17
+ "aria-hidden": !0,
18
+ className: "bg-tint/10 absolute top-7 bottom-1 left-[11px] w-px group-last/timeline:hidden"
19
+ }),
20
+ /* @__PURE__ */ t("span", {
21
+ "aria-hidden": !0,
22
+ className: e("relative mt-0.5 grid size-6 shrink-0 place-items-center rounded-full [&_svg]:size-3.5", a ? "bg-tint/[0.06] text-muted-foreground shadow-[inset_0_0_0_1px_oklch(var(--tint)/0.1)]" : "after:bg-tint/30 after:size-2 after:rounded-full", o && "bg-primary/15 text-primary shadow-[inset_0_0_0_1px_oklch(var(--primary)/0.35),0_0_16px_-2px_oklch(var(--glow)/calc(0.7*var(--glow-k)))] after:bg-primary"),
23
+ children: a
24
+ }),
25
+ /* @__PURE__ */ n("div", {
26
+ className: "flex min-w-0 flex-1 flex-col gap-1",
27
+ children: [/* @__PURE__ */ n("div", {
28
+ className: "flex flex-wrap items-baseline justify-between gap-x-3",
29
+ children: [/* @__PURE__ */ t("span", {
30
+ className: "text-foreground text-sm font-medium",
31
+ children: r
32
+ }), i && /* @__PURE__ */ t("span", {
33
+ className: "text-muted-foreground text-xs tabular-nums",
34
+ children: i
35
+ })]
36
+ }), c && /* @__PURE__ */ t("div", {
37
+ className: "text-muted-foreground text-sm leading-6",
38
+ children: c
39
+ })]
40
+ })
41
+ ]
42
+ });
43
+ }
44
+ //#endregion
45
+ export { i as TimelineItem, r as default };