@krizaka/ui 2.5.0 → 2.8.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 (267) hide show
  1. package/README.md +49 -5
  2. package/dist/action-bar.d.ts +38 -0
  3. package/dist/action-bar.js +52 -0
  4. package/dist/action-bar.js.map +1 -0
  5. package/dist/argument-card.d.ts +67 -0
  6. package/dist/argument-card.js +69 -0
  7. package/dist/argument-card.js.map +1 -0
  8. package/dist/audio-player.js +1 -1
  9. package/dist/block-link-BAg4eoZk.d.ts +12 -0
  10. package/dist/blocks.css +529 -0
  11. package/dist/button.js +5 -94
  12. package/dist/button.js.map +1 -1
  13. package/dist/card-grid.d.ts +42 -0
  14. package/dist/card-grid.js +47 -0
  15. package/dist/card-grid.js.map +1 -0
  16. package/dist/chunk-2AGSO3WH.js +20 -0
  17. package/dist/chunk-2AGSO3WH.js.map +1 -0
  18. package/dist/chunk-AB5D3KBG.js +37 -0
  19. package/dist/chunk-AB5D3KBG.js.map +1 -0
  20. package/dist/{chunk-YX6CNVJA.js → chunk-CPA5CF35.js} +1 -1
  21. package/dist/chunk-CPA5CF35.js.map +1 -0
  22. package/dist/chunk-K3SWZXYT.js +92 -0
  23. package/dist/chunk-K3SWZXYT.js.map +1 -0
  24. package/dist/chunk-NOVUREEC.js +274 -0
  25. package/dist/chunk-NOVUREEC.js.map +1 -0
  26. package/dist/{chunk-XUMJA5ZI.js → chunk-X6TW3X6Y.js} +2 -2
  27. package/dist/chunk-XCBVFMNV.js +41 -0
  28. package/dist/{chunk-YX6CNVJA.js.map → chunk-XCBVFMNV.js.map} +1 -1
  29. package/dist/chunk-XVLWVTQA.js +28 -0
  30. package/dist/chunk-XVLWVTQA.js.map +1 -0
  31. package/dist/chunk-Z6FUPB3Q.js +102 -0
  32. package/dist/chunk-Z6FUPB3Q.js.map +1 -0
  33. package/dist/code-block.d.ts +42 -0
  34. package/dist/code-block.js +202 -0
  35. package/dist/code-block.js.map +1 -0
  36. package/dist/combobox.js +2 -2
  37. package/dist/cta-panel.d.ts +23 -0
  38. package/dist/cta-panel.js +20 -0
  39. package/dist/cta-panel.js.map +1 -0
  40. package/dist/data-table.js +1 -1
  41. package/dist/date-picker.js +1 -1
  42. package/dist/decision-list.d.ts +34 -0
  43. package/dist/decision-list.js +67 -0
  44. package/dist/decision-list.js.map +1 -0
  45. package/dist/file-upload.js +1 -1
  46. package/dist/filter-bar.js +1 -1
  47. package/dist/geometry-CXrAW34x.d.ts +19 -0
  48. package/dist/index.d.ts +10 -2
  49. package/dist/index.js +86 -4
  50. package/dist/index.js.map +1 -1
  51. package/dist/link-card.d.ts +35 -0
  52. package/dist/link-card.js +46 -0
  53. package/dist/link-card.js.map +1 -0
  54. package/dist/mascot-quote.d.ts +43 -0
  55. package/dist/mascot-quote.js +287 -0
  56. package/dist/mascot-quote.js.map +1 -0
  57. package/dist/mascot-state.d.ts +128 -0
  58. package/dist/mascot-state.js +95 -0
  59. package/dist/mascot-state.js.map +1 -0
  60. package/dist/mascots.d.ts +5 -20
  61. package/dist/mascots.js +5 -246
  62. package/dist/mascots.js.map +1 -1
  63. package/dist/media-capture.js +1 -1
  64. package/dist/motion.css +25 -1
  65. package/dist/native.d.ts +54 -7
  66. package/dist/native.js +334 -166
  67. package/dist/native.js.map +1 -1
  68. package/dist/page-hero.d.ts +44 -0
  69. package/dist/page-hero.js +41 -0
  70. package/dist/page-hero.js.map +1 -0
  71. package/dist/page.d.ts +116 -0
  72. package/dist/page.js +17 -0
  73. package/dist/page.js.map +1 -0
  74. package/dist/pagination.js +25 -44
  75. package/dist/pagination.js.map +1 -1
  76. package/dist/pointer-light.d.ts +20 -0
  77. package/dist/pointer-light.js +12 -0
  78. package/dist/pointer-light.js.map +1 -0
  79. package/dist/search-field.js +1 -1
  80. package/dist/section-backdrop.js +4 -22
  81. package/dist/section-backdrop.js.map +1 -1
  82. package/dist/tag-input.js +2 -2
  83. package/dist/terminal-replay.d.ts +68 -0
  84. package/dist/terminal-replay.js +231 -0
  85. package/dist/terminal-replay.js.map +1 -0
  86. package/dist/toc.d.ts +23 -0
  87. package/dist/toc.js +39 -0
  88. package/dist/toc.js.map +1 -0
  89. package/dist/video-player.js +1 -1
  90. package/package.json +208 -8
  91. package/registry/action-bar.json +205 -0
  92. package/registry/alert.json +1 -1
  93. package/registry/argument-card.json +327 -0
  94. package/registry/audio-player.json +2 -2
  95. package/registry/avatar.json +1 -1
  96. package/registry/badge.json +1 -1
  97. package/registry/button.json +5 -5
  98. package/registry/card-grid.json +221 -0
  99. package/registry/card.json +3 -3
  100. package/registry/checkbox.json +1 -1
  101. package/registry/chip-link.json +1 -1
  102. package/registry/chip.json +1 -1
  103. package/registry/code-block.json +262 -0
  104. package/registry/combobox.json +2 -2
  105. package/registry/command.json +1 -1
  106. package/registry/confirm-button.json +3 -3
  107. package/registry/countdown.json +1 -1
  108. package/registry/cta-panel.json +154 -0
  109. package/registry/data-table.json +2 -2
  110. package/registry/date-picker.json +2 -2
  111. package/registry/decision-list.json +144 -0
  112. package/registry/dialog.json +1 -1
  113. package/registry/dropdown-menu.json +1 -1
  114. package/registry/empty-state.json +1 -1
  115. package/registry/examples/action-bar/buttons.d.ts +4 -0
  116. package/registry/examples/action-bar/buttons.js +22 -0
  117. package/registry/examples/action-bar/buttons.tsx +17 -0
  118. package/registry/examples/action-bar/icons.d.ts +4 -0
  119. package/registry/examples/action-bar/icons.js +24 -0
  120. package/registry/examples/action-bar/icons.tsx +23 -0
  121. package/registry/examples/argument-card/building-block.d.ts +4 -0
  122. package/registry/examples/argument-card/building-block.js +29 -0
  123. package/registry/examples/argument-card/building-block.tsx +29 -0
  124. package/registry/examples/argument-card/grid.d.ts +4 -0
  125. package/registry/examples/argument-card/grid.js +17 -0
  126. package/registry/examples/argument-card/grid.tsx +19 -0
  127. package/registry/examples/argument-card/unfold.d.ts +4 -0
  128. package/registry/examples/argument-card/unfold.js +26 -0
  129. package/registry/examples/argument-card/unfold.tsx +21 -0
  130. package/registry/examples/card-grid/products.d.ts +4 -0
  131. package/registry/examples/card-grid/products.js +16 -0
  132. package/registry/examples/card-grid/products.tsx +13 -0
  133. package/registry/examples/card-grid/reveal.d.ts +4 -0
  134. package/registry/examples/card-grid/reveal.js +13 -0
  135. package/registry/examples/card-grid/reveal.tsx +16 -0
  136. package/registry/examples/code-block/build-tools.d.ts +4 -0
  137. package/registry/examples/code-block/build-tools.js +30 -0
  138. package/registry/examples/code-block/build-tools.tsx +25 -0
  139. package/registry/examples/code-block/file.d.ts +4 -0
  140. package/registry/examples/code-block/file.js +17 -0
  141. package/registry/examples/code-block/file.tsx +13 -0
  142. package/registry/examples/cta-panel/discuss.d.ts +4 -0
  143. package/registry/examples/cta-panel/discuss.js +31 -0
  144. package/registry/examples/cta-panel/discuss.tsx +23 -0
  145. package/registry/examples/decision-list/product.d.ts +4 -0
  146. package/registry/examples/decision-list/product.js +35 -0
  147. package/registry/examples/decision-list/product.tsx +30 -0
  148. package/registry/examples/link-card/docs-hub.d.ts +4 -0
  149. package/registry/examples/link-card/docs-hub.js +18 -0
  150. package/registry/examples/link-card/docs-hub.tsx +20 -0
  151. package/registry/examples/link-card/external.d.ts +4 -0
  152. package/registry/examples/link-card/external.js +22 -0
  153. package/registry/examples/link-card/external.tsx +16 -0
  154. package/registry/examples/link-card/stack.d.ts +4 -0
  155. package/registry/examples/link-card/stack.js +26 -0
  156. package/registry/examples/link-card/stack.tsx +21 -0
  157. package/registry/examples/mascot-quote/callout.d.ts +4 -0
  158. package/registry/examples/mascot-quote/callout.js +11 -0
  159. package/registry/examples/mascot-quote/callout.tsx +10 -0
  160. package/registry/examples/mascot-quote/inline.d.ts +4 -0
  161. package/registry/examples/mascot-quote/inline.js +11 -0
  162. package/registry/examples/mascot-quote/inline.tsx +10 -0
  163. package/registry/examples/mascot-state/empty.d.ts +4 -0
  164. package/registry/examples/mascot-state/empty.js +22 -0
  165. package/registry/examples/mascot-state/empty.tsx +20 -0
  166. package/registry/examples/mascot-state/error.d.ts +4 -0
  167. package/registry/examples/mascot-state/error.js +23 -0
  168. package/registry/examples/mascot-state/error.tsx +21 -0
  169. package/registry/examples/mascot-state/loading.d.ts +4 -0
  170. package/registry/examples/mascot-state/loading.js +22 -0
  171. package/registry/examples/mascot-state/loading.tsx +16 -0
  172. package/registry/examples/mascot-state/native/default.d.ts +4 -0
  173. package/registry/examples/mascot-state/native/default.dark.png +0 -0
  174. package/registry/examples/mascot-state/native/default.js +25 -0
  175. package/registry/examples/mascot-state/native/default.light.png +0 -0
  176. package/registry/examples/mascot-state/native/default.tsx +19 -0
  177. package/registry/examples/mascot-state/success.d.ts +4 -0
  178. package/registry/examples/mascot-state/success.js +21 -0
  179. package/registry/examples/mascot-state/success.tsx +19 -0
  180. package/registry/examples/mascot-state/welcome.d.ts +4 -0
  181. package/registry/examples/mascot-state/welcome.js +21 -0
  182. package/registry/examples/mascot-state/welcome.tsx +19 -0
  183. package/registry/examples/mascots/flock.tsx +1 -1
  184. package/registry/examples/mascots/lovebird.d.ts +4 -0
  185. package/registry/examples/mascots/lovebird.js +19 -0
  186. package/registry/examples/mascots/lovebird.tsx +18 -0
  187. package/registry/examples/mascots/native/lovebird.d.ts +4 -0
  188. package/registry/examples/mascots/native/lovebird.dark.png +0 -0
  189. package/registry/examples/mascots/native/lovebird.js +21 -0
  190. package/registry/examples/mascots/native/lovebird.light.png +0 -0
  191. package/registry/examples/mascots/native/lovebird.tsx +18 -0
  192. package/registry/examples/page/backdrop.d.ts +4 -0
  193. package/registry/examples/page/backdrop.js +23 -0
  194. package/registry/examples/page/backdrop.tsx +18 -0
  195. package/registry/examples/page/facts.d.ts +4 -0
  196. package/registry/examples/page/facts.js +24 -0
  197. package/registry/examples/page/facts.tsx +21 -0
  198. package/registry/examples/page/frame.d.ts +4 -0
  199. package/registry/examples/page/frame.js +15 -0
  200. package/registry/examples/page/frame.tsx +17 -0
  201. package/registry/examples/page/sections.d.ts +4 -0
  202. package/registry/examples/page/sections.js +14 -0
  203. package/registry/examples/page/sections.tsx +15 -0
  204. package/registry/examples/page-hero/building-block.d.ts +4 -0
  205. package/registry/examples/page-hero/building-block.js +24 -0
  206. package/registry/examples/page-hero/building-block.tsx +20 -0
  207. package/registry/examples/page-hero/hub.d.ts +4 -0
  208. package/registry/examples/page-hero/hub.js +21 -0
  209. package/registry/examples/page-hero/hub.tsx +15 -0
  210. package/registry/examples/pointer-light/list.d.ts +4 -0
  211. package/registry/examples/pointer-light/list.js +16 -0
  212. package/registry/examples/pointer-light/list.tsx +14 -0
  213. package/registry/examples/terminal-replay/at-rest.d.ts +4 -0
  214. package/registry/examples/terminal-replay/at-rest.js +32 -0
  215. package/registry/examples/terminal-replay/at-rest.tsx +26 -0
  216. package/registry/examples/terminal-replay/session.d.ts +4 -0
  217. package/registry/examples/terminal-replay/session.js +34 -0
  218. package/registry/examples/terminal-replay/session.tsx +28 -0
  219. package/registry/examples/toc/reading-page.d.ts +4 -0
  220. package/registry/examples/toc/reading-page.js +21 -0
  221. package/registry/examples/toc/reading-page.tsx +21 -0
  222. package/registry/field.json +1 -1
  223. package/registry/file-upload.json +2 -2
  224. package/registry/filter-bar.json +2 -2
  225. package/registry/glow-card.json +1 -1
  226. package/registry/image-cropper.json +1 -1
  227. package/registry/index.json +265 -5
  228. package/registry/iso.json +1 -1
  229. package/registry/kbd.json +1 -1
  230. package/registry/link-card.json +279 -0
  231. package/registry/loader.json +1 -1
  232. package/registry/marquee.json +1 -1
  233. package/registry/mascot-quote.json +191 -0
  234. package/registry/mascot-state.json +1249 -0
  235. package/registry/mascots.json +41 -21
  236. package/registry/media-capture.json +4 -4
  237. package/registry/meter.json +1 -1
  238. package/registry/nav-bar.json +1 -1
  239. package/registry/number-ticker.json +1 -1
  240. package/registry/page-header.json +1 -1
  241. package/registry/page-hero.json +254 -0
  242. package/registry/page.json +497 -0
  243. package/registry/pagination.json +2 -2
  244. package/registry/pointer-light.json +119 -0
  245. package/registry/popover.json +1 -1
  246. package/registry/progress.json +1 -1
  247. package/registry/radio-group.json +1 -1
  248. package/registry/search-field.json +2 -2
  249. package/registry/section-backdrop.json +1 -1
  250. package/registry/separator.json +1 -1
  251. package/registry/skeleton.json +3 -3
  252. package/registry/slider.json +1 -1
  253. package/registry/slot.json +1 -1
  254. package/registry/spinner.json +1 -1
  255. package/registry/stat.json +1 -1
  256. package/registry/stepper.json +1 -1
  257. package/registry/switch.json +1 -1
  258. package/registry/tabs.json +1 -1
  259. package/registry/tag-input.json +1 -1
  260. package/registry/terminal-replay.json +317 -0
  261. package/registry/theme.json +1 -1
  262. package/registry/toast.json +1 -1
  263. package/registry/toc.json +157 -0
  264. package/registry/tooltip.json +1 -1
  265. package/registry/video-player.json +4 -4
  266. package/registry/video-trimmer.json +3 -3
  267. /package/dist/{chunk-XUMJA5ZI.js.map → chunk-X6TW3X6Y.js.map} +0 -0
@@ -0,0 +1,231 @@
1
+ "use client";
2
+ import {
3
+ cn
4
+ } from "./chunk-5AXLA4LK.js";
5
+
6
+ // src/terminal-replay/terminal-replay.tsx
7
+ import * as React from "react";
8
+
9
+ // src/glyphs.tsx
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ function Glyph({ className = "h-4 w-4", fill, children }) {
12
+ return /* @__PURE__ */ jsx(
13
+ "svg",
14
+ {
15
+ viewBox: "0 0 24 24",
16
+ className,
17
+ fill: fill ? "currentColor" : "none",
18
+ stroke: fill ? "none" : "currentColor",
19
+ strokeWidth: "2",
20
+ strokeLinecap: "round",
21
+ strokeLinejoin: "round",
22
+ "aria-hidden": true,
23
+ focusable: "false",
24
+ children
25
+ }
26
+ );
27
+ }
28
+ var PlayGlyph = (p) => /* @__PURE__ */ jsx(Glyph, { ...p, fill: true, children: /* @__PURE__ */ jsx("path", { d: "M8 5.5v13a1 1 0 0 0 1.5.86l10.4-6.5a1 1 0 0 0 0-1.72L9.5 4.64A1 1 0 0 0 8 5.5Z" }) });
29
+ var PauseGlyph = (p) => /* @__PURE__ */ jsxs(Glyph, { ...p, fill: true, children: [
30
+ /* @__PURE__ */ jsx("rect", { x: "6", y: "5", width: "4", height: "14", rx: "1" }),
31
+ /* @__PURE__ */ jsx("rect", { x: "14", y: "5", width: "4", height: "14", rx: "1" })
32
+ ] });
33
+ var CheckGlyph = (p) => /* @__PURE__ */ jsx(Glyph, { ...p, children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
34
+ var RetryGlyph = (p) => /* @__PURE__ */ jsxs(Glyph, { ...p, children: [
35
+ /* @__PURE__ */ jsx("path", { d: "M4 12a8 8 0 1 0 2.3-5.7L4 8.5" }),
36
+ /* @__PURE__ */ jsx("path", { d: "M4 4v4.5h4.5" })
37
+ ] });
38
+
39
+ // src/terminal-replay/terminal-replay.tsx
40
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
41
+ var TONE = {
42
+ muted: "text-fg-secondary",
43
+ accent: "text-fg-accent",
44
+ success: "text-fg-success",
45
+ warning: "text-fg-warning",
46
+ danger: "text-fg-danger"
47
+ };
48
+ var line = (entry) => typeof entry === "string" ? { text: entry } : entry;
49
+ function advance(steps, pos, timing) {
50
+ const current = steps[pos.step];
51
+ if (!current) return null;
52
+ const output = current.output ?? [];
53
+ if (pos.chars < current.command.length) {
54
+ const pause = current.command[pos.chars] === " " ? timing.typing * 2 : timing.typing;
55
+ return [{ ...pos, chars: pos.chars + 1 }, pause];
56
+ }
57
+ if (pos.lines < output.length) return [{ ...pos, lines: pos.lines + 1 }, pos.lines === 0 ? timing.line * 4 : timing.line];
58
+ if (pos.step < steps.length - 1) return [{ step: pos.step + 1, chars: 0, lines: 0 }, timing.step];
59
+ return null;
60
+ }
61
+ function TerminalReplay({
62
+ steps,
63
+ label,
64
+ title,
65
+ prompt = "$",
66
+ playLabel,
67
+ pauseLabel,
68
+ replayLabel,
69
+ copyLabel,
70
+ copiedLabel,
71
+ typingSpeed = 34,
72
+ lineDelay = 70,
73
+ stepDelay = 900,
74
+ rows = 18,
75
+ autoPlay = true,
76
+ className,
77
+ style,
78
+ ...props
79
+ }) {
80
+ const root = React.useRef(null);
81
+ const screenRef = React.useRef(null);
82
+ const [phase, setPhase] = React.useState("final");
83
+ const [pos, setPos] = React.useState({ step: 0, chars: 0, lines: 0 });
84
+ const [visible, setVisible] = React.useState(false);
85
+ const [copied, setCopied] = React.useState(false);
86
+ React.useEffect(() => {
87
+ const el = root.current;
88
+ if (!el || !autoPlay || window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
89
+ setPhase("idle");
90
+ const io = new IntersectionObserver(
91
+ ([entry]) => {
92
+ const seen = Boolean(entry?.isIntersecting);
93
+ setVisible(seen);
94
+ if (seen) setPhase((current) => current === "idle" ? "playing" : current);
95
+ },
96
+ { threshold: 0.35 }
97
+ );
98
+ io.observe(el);
99
+ return () => io.disconnect();
100
+ }, [autoPlay]);
101
+ const ended = phase === "playing" && !advance(steps, pos, { typing: typingSpeed, line: lineDelay, step: stepDelay });
102
+ const state = ended ? "done" : phase;
103
+ React.useEffect(() => {
104
+ if (phase !== "playing" || !visible) return;
105
+ const next = advance(steps, pos, { typing: typingSpeed, line: lineDelay, step: stepDelay });
106
+ if (!next) return;
107
+ const timer = setTimeout(() => setPos(next[0]), next[1]);
108
+ return () => clearTimeout(timer);
109
+ }, [phase, visible, pos, steps, typingSpeed, lineDelay, stepDelay]);
110
+ React.useEffect(() => {
111
+ const el = screenRef.current;
112
+ if (el && state === "playing") el.scrollTop = el.scrollHeight;
113
+ }, [pos, state]);
114
+ React.useEffect(() => {
115
+ if (!copied) return;
116
+ const timer = setTimeout(() => setCopied(false), 1800);
117
+ return () => clearTimeout(timer);
118
+ }, [copied]);
119
+ const whole = state === "final" || state === "done";
120
+ const shown = whole ? steps.length - 1 : pos.step;
121
+ const toggle = () => {
122
+ if (state === "playing") setPhase("paused");
123
+ else if (state === "paused" || state === "idle") setPhase("playing");
124
+ else {
125
+ setVisible(true);
126
+ setPos({ step: 0, chars: 0, lines: 0 });
127
+ setPhase("playing");
128
+ }
129
+ };
130
+ const control = state === "playing" ? { text: pauseLabel, Glyph: PauseGlyph } : state === "done" ? { text: replayLabel, Glyph: RetryGlyph } : { text: playLabel, Glyph: PlayGlyph };
131
+ const commands = steps.map((s) => s.command).join("\n");
132
+ const transcript = steps.map((s) => [`${prompt} ${s.command}`, ...(s.output ?? []).map((o) => line(o).text)].join("\n")).join("\n\n");
133
+ return /* @__PURE__ */ jsxs2(
134
+ "figure",
135
+ {
136
+ ref: root,
137
+ "data-state": state,
138
+ "data-autoplay": autoPlay ? "" : void 0,
139
+ className: cn("kz-replay overflow-hidden rounded-xl border border-border-default bg-surface-1 shadow-md", className),
140
+ style: { "--kz-replay-rows": rows, ...style },
141
+ ...props,
142
+ children: [
143
+ /* @__PURE__ */ jsxs2("figcaption", { className: "flex items-center gap-3 border-b border-border-subtle bg-surface-2 px-3 py-2 text-xs text-fg-secondary", children: [
144
+ /* @__PURE__ */ jsxs2("span", { "aria-hidden": true, className: "flex shrink-0 gap-1.5", children: [
145
+ /* @__PURE__ */ jsx2("span", { className: "h-2.5 w-2.5 rounded-full bg-border-strong" }),
146
+ /* @__PURE__ */ jsx2("span", { className: "h-2.5 w-2.5 rounded-full bg-border-strong" }),
147
+ /* @__PURE__ */ jsx2("span", { className: "h-2.5 w-2.5 rounded-full bg-border-strong" })
148
+ ] }),
149
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate font-mono", children: title }),
150
+ /* @__PURE__ */ jsxs2(
151
+ "button",
152
+ {
153
+ type: "button",
154
+ onClick: toggle,
155
+ className: "inline-flex shrink-0 items-center gap-1.5 rounded-md px-2 py-1 font-medium text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg focus-visible:outline-2 focus-visible:outline-ring",
156
+ children: [
157
+ /* @__PURE__ */ jsx2(control.Glyph, { className: "h-3.5 w-3.5" }),
158
+ control.text
159
+ ]
160
+ }
161
+ ),
162
+ copyLabel && /* @__PURE__ */ jsxs2(
163
+ "button",
164
+ {
165
+ type: "button",
166
+ onClick: () => navigator.clipboard?.writeText(commands).then(() => setCopied(true)),
167
+ "data-copied": copied ? "" : void 0,
168
+ className: "inline-flex shrink-0 items-center gap-1.5 rounded-md px-2 py-1 font-medium text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg focus-visible:outline-2 focus-visible:outline-ring",
169
+ children: [
170
+ copied ? /* @__PURE__ */ jsx2(CheckGlyph, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx2(CopyGlyph, {}),
171
+ /* @__PURE__ */ jsx2("span", { "aria-live": "polite", children: copied ? copiedLabel ?? copyLabel : copyLabel })
172
+ ]
173
+ }
174
+ )
175
+ ] }),
176
+ /* @__PURE__ */ jsxs2(
177
+ "div",
178
+ {
179
+ ref: screenRef,
180
+ role: "region",
181
+ "aria-label": label,
182
+ tabIndex: 0,
183
+ className: "kz-replay-screen relative overflow-auto bg-surface-0 px-4 py-3 font-mono text-[0.8125rem] leading-relaxed text-fg focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring",
184
+ children: [
185
+ /* @__PURE__ */ jsxs2("div", { "aria-hidden": true, className: "kz-replay-live", children: [
186
+ steps.slice(0, state === "idle" ? 0 : shown + 1).map((step, i) => {
187
+ const current = !whole && i === shown;
188
+ const typed = current ? step.command.slice(0, pos.chars) : step.command;
189
+ const output = (step.output ?? []).slice(0, current ? pos.lines : void 0);
190
+ const typing = current && pos.chars < step.command.length;
191
+ return /* @__PURE__ */ jsxs2("div", { className: i > 0 ? "mt-3" : void 0, children: [
192
+ /* @__PURE__ */ jsxs2("div", { className: "whitespace-pre", children: [
193
+ /* @__PURE__ */ jsxs2("span", { className: "text-fg-accent select-none", children: [
194
+ prompt,
195
+ " "
196
+ ] }),
197
+ /* @__PURE__ */ jsx2("span", { className: "font-medium", children: typed }),
198
+ typing && /* @__PURE__ */ jsx2("span", { className: "kz-replay-caret" })
199
+ ] }),
200
+ output.map((entry, j) => {
201
+ const { text, tone } = line(entry);
202
+ return /* @__PURE__ */ jsx2("div", { className: cn("min-h-[1lh] whitespace-pre", tone ? TONE[tone] : "text-fg"), children: text }, j);
203
+ })
204
+ ] }, i);
205
+ }),
206
+ (state === "idle" || whole) && /* @__PURE__ */ jsxs2("div", { className: cn("whitespace-pre", state !== "idle" && "mt-3"), children: [
207
+ /* @__PURE__ */ jsxs2("span", { className: "text-fg-accent select-none", children: [
208
+ prompt,
209
+ " "
210
+ ] }),
211
+ /* @__PURE__ */ jsx2("span", { className: "kz-replay-caret" })
212
+ ] })
213
+ ] }),
214
+ /* @__PURE__ */ jsx2("pre", { className: "sr-only", children: transcript })
215
+ ]
216
+ }
217
+ )
218
+ ]
219
+ }
220
+ );
221
+ }
222
+ function CopyGlyph() {
223
+ return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", className: "h-3.5 w-3.5", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, focusable: "false", children: [
224
+ /* @__PURE__ */ jsx2("rect", { x: "9", y: "9", width: "11", height: "11", rx: "2" }),
225
+ /* @__PURE__ */ jsx2("path", { d: "M5 15V6a2 2 0 0 1 2-2h8" })
226
+ ] });
227
+ }
228
+ export {
229
+ TerminalReplay
230
+ };
231
+ //# sourceMappingURL=terminal-replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/terminal-replay/terminal-replay.tsx","../src/glyphs.tsx"],"sourcesContent":["// Client (a timer, an observer). A terminal session played back: each command is typed at the prompt, its output\n// arrives line by line, the screen follows the last line like a real terminal. What a reader sees without the motion\n// is the session itself: the server renders it whole (no JavaScript, reduced motion and assistive technology all get\n// the full transcript), the screen has a fixed height (no layout shift while it plays), the replay starts when it\n// scrolls into view, waits while it is off screen, and pauses or replays on demand (WCAG 2.2.2). A bounded chain of\n// timeouts, never a permanent animation frame.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { CheckGlyph, PauseGlyph, PlayGlyph, RetryGlyph } from \"../glyphs\";\n\n/** The colour of an output line — the tokens' text roles, all AA on the screen: secondary, accent, success, warning, danger. */\nexport type TerminalTone = \"muted\" | \"accent\" | \"success\" | \"warning\" | \"danger\";\n\nexport interface TerminalLine {\n /** The line as the program printed it (no colour codes). */\n text: string;\n /** Its colour, when the program coloured it. */\n tone?: TerminalTone;\n}\n\nexport interface TerminalStep {\n /** What is typed at the prompt (`npx orazaka install`). */\n command: string;\n /** What it printed, line by line. */\n output?: readonly (string | TerminalLine)[];\n}\n\nexport type TerminalReplayProps = Omit<React.ComponentProps<\"figure\">, \"children\" | \"title\"> & {\n /** The session, in order. */\n steps: readonly TerminalStep[];\n /** The accessible name of the screen (“Terminal session: install, start, dev”) — passed translated. */\n label: string;\n /** The window's title, shown in its bar (`~/projects — zsh`). */\n title?: React.ReactNode;\n /**\n * What the prompt shows before each command.\n * @default \"$\"\n */\n prompt?: string;\n /** The play button's words (the replay is waiting or paused). */\n playLabel: string;\n /** The pause button's words (the replay is running). */\n pauseLabel: string;\n /** The replay button's words (the session is shown whole). */\n replayLabel: string;\n /** The copy button's words: it copies the commands, one per line. Without it, no copy button. */\n copyLabel?: string;\n /** What the copy button says once the commands are copied (announced politely). */\n copiedLabel?: string;\n /**\n * Milliseconds per typed character.\n * @default 34\n */\n typingSpeed?: number;\n /**\n * Milliseconds between two output lines.\n * @default 70\n */\n lineDelay?: number;\n /**\n * Milliseconds between a command's last line and the next command.\n * @default 900\n */\n stepDelay?: number;\n /**\n * The screen's height, in lines; longer sessions scroll.\n * @default 18\n */\n rows?: number;\n /**\n * Plays the first time it scrolls into view. `false`: the session rests whole until the reader presses play.\n * @default true\n */\n autoPlay?: boolean;\n};\n\ntype Phase = \"final\" | \"idle\" | \"playing\" | \"paused\" | \"done\";\ninterface Position {\n step: number;\n chars: number;\n lines: number;\n}\n\nconst TONE: Record<TerminalTone, string> = {\n muted: \"text-fg-secondary\",\n accent: \"text-fg-accent\",\n success: \"text-fg-success\",\n warning: \"text-fg-warning\",\n danger: \"text-fg-danger\",\n};\n\nconst line = (entry: string | TerminalLine): TerminalLine => (typeof entry === \"string\" ? { text: entry } : entry);\n\n/** The next position of the replay and how long to wait for it; null at the end of the session. */\nfunction advance(steps: readonly TerminalStep[], pos: Position, timing: { typing: number; line: number; step: number }): [Position, number] | null {\n const current = steps[pos.step];\n if (!current) return null;\n const output = current.output ?? [];\n if (pos.chars < current.command.length) {\n // A space is a beat longer: the rhythm of someone typing, not of a printer.\n const pause = current.command[pos.chars] === \" \" ? timing.typing * 2 : timing.typing;\n return [{ ...pos, chars: pos.chars + 1 }, pause];\n }\n if (pos.lines < output.length) return [{ ...pos, lines: pos.lines + 1 }, pos.lines === 0 ? timing.line * 4 : timing.line];\n if (pos.step < steps.length - 1) return [{ step: pos.step + 1, chars: 0, lines: 0 }, timing.step];\n return null;\n}\n\n/** A terminal session played back: commands typed at the prompt, their output line by line — or the whole session at rest. */\nexport function TerminalReplay({\n steps,\n label,\n title,\n prompt = \"$\",\n playLabel,\n pauseLabel,\n replayLabel,\n copyLabel,\n copiedLabel,\n typingSpeed = 34,\n lineDelay = 70,\n stepDelay = 900,\n rows = 18,\n autoPlay = true,\n className,\n style,\n ...props\n}: TerminalReplayProps) {\n const root = React.useRef<HTMLElement>(null);\n const screenRef = React.useRef<HTMLDivElement>(null);\n // The server renders the session whole; the client takes it over unless the reader asked for less motion.\n const [phase, setPhase] = React.useState<Phase>(\"final\");\n const [pos, setPos] = React.useState<Position>({ step: 0, chars: 0, lines: 0 });\n const [visible, setVisible] = React.useState(false);\n const [copied, setCopied] = React.useState(false);\n\n React.useEffect(() => {\n const el = root.current;\n if (!el || !autoPlay || window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n setPhase(\"idle\");\n // Starts the first time it is seen; off screen, it waits where it is.\n const io = new IntersectionObserver(\n ([entry]) => {\n const seen = Boolean(entry?.isIntersecting);\n setVisible(seen);\n if (seen) setPhase((current) => (current === \"idle\" ? \"playing\" : current));\n },\n { threshold: 0.35 },\n );\n io.observe(el);\n return () => io.disconnect();\n }, [autoPlay]);\n\n const ended = phase === \"playing\" && !advance(steps, pos, { typing: typingSpeed, line: lineDelay, step: stepDelay });\n // The end of the session is where the replay stands, not an event: derived, never set from an effect.\n const state: Phase = ended ? \"done\" : phase;\n\n React.useEffect(() => {\n if (phase !== \"playing\" || !visible) return;\n const next = advance(steps, pos, { typing: typingSpeed, line: lineDelay, step: stepDelay });\n if (!next) return;\n const timer = setTimeout(() => setPos(next[0]), next[1]);\n return () => clearTimeout(timer);\n }, [phase, visible, pos, steps, typingSpeed, lineDelay, stepDelay]);\n\n // The screen follows the last line while it plays, like a terminal.\n React.useEffect(() => {\n const el = screenRef.current;\n if (el && state === \"playing\") el.scrollTop = el.scrollHeight;\n }, [pos, state]);\n\n React.useEffect(() => {\n if (!copied) return;\n const timer = setTimeout(() => setCopied(false), 1800);\n return () => clearTimeout(timer);\n }, [copied]);\n\n const whole = state === \"final\" || state === \"done\";\n const shown = whole ? steps.length - 1 : pos.step;\n const toggle = () => {\n if (state === \"playing\") setPhase(\"paused\");\n else if (state === \"paused\" || state === \"idle\") setPhase(\"playing\");\n else {\n // Played on demand — also under reduced motion: the reader asked for it. Off screen it would wait: it is on screen.\n setVisible(true);\n setPos({ step: 0, chars: 0, lines: 0 });\n setPhase(\"playing\");\n }\n };\n const control =\n state === \"playing\"\n ? { text: pauseLabel, Glyph: PauseGlyph }\n : state === \"done\"\n ? { text: replayLabel, Glyph: RetryGlyph }\n : { text: playLabel, Glyph: PlayGlyph };\n const commands = steps.map((s) => s.command).join(\"\\n\");\n const transcript = steps.map((s) => [`${prompt} ${s.command}`, ...(s.output ?? []).map((o) => line(o).text)].join(\"\\n\")).join(\"\\n\\n\");\n\n return (\n <figure\n ref={root}\n data-state={state}\n data-autoplay={autoPlay ? \"\" : undefined}\n className={cn(\"kz-replay overflow-hidden rounded-xl border border-border-default bg-surface-1 shadow-md\", className)}\n style={{ \"--kz-replay-rows\": rows, ...style } as React.CSSProperties}\n {...props}\n >\n <figcaption className=\"flex items-center gap-3 border-b border-border-subtle bg-surface-2 px-3 py-2 text-xs text-fg-secondary\">\n <span aria-hidden className=\"flex shrink-0 gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full bg-border-strong\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-border-strong\" />\n <span className=\"h-2.5 w-2.5 rounded-full bg-border-strong\" />\n </span>\n <span className=\"min-w-0 flex-1 truncate font-mono\">{title}</span>\n <button\n type=\"button\"\n onClick={toggle}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-md px-2 py-1 font-medium text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <control.Glyph className=\"h-3.5 w-3.5\" />\n {control.text}\n </button>\n {copyLabel && (\n <button\n type=\"button\"\n onClick={() => navigator.clipboard?.writeText(commands).then(() => setCopied(true))}\n data-copied={copied ? \"\" : undefined}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-md px-2 py-1 font-medium text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {copied ? <CheckGlyph className=\"h-3.5 w-3.5\" /> : <CopyGlyph />}\n <span aria-live=\"polite\">{copied ? (copiedLabel ?? copyLabel) : copyLabel}</span>\n </button>\n )}\n </figcaption>\n <div\n ref={screenRef}\n role=\"region\"\n aria-label={label}\n tabIndex={0}\n className=\"kz-replay-screen relative overflow-auto bg-surface-0 px-4 py-3 font-mono text-[0.8125rem] leading-relaxed text-fg focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring\"\n >\n <div aria-hidden className=\"kz-replay-live\">\n {steps.slice(0, state === \"idle\" ? 0 : shown + 1).map((step, i) => {\n const current = !whole && i === shown;\n const typed = current ? step.command.slice(0, pos.chars) : step.command;\n const output = (step.output ?? []).slice(0, current ? pos.lines : undefined);\n const typing = current && pos.chars < step.command.length;\n return (\n <div key={i} className={i > 0 ? \"mt-3\" : undefined}>\n <div className=\"whitespace-pre\">\n <span className=\"text-fg-accent select-none\">{prompt} </span>\n <span className=\"font-medium\">{typed}</span>\n {typing && <span className=\"kz-replay-caret\" />}\n </div>\n {output.map((entry, j) => {\n const { text, tone } = line(entry);\n return (\n <div key={j} className={cn(\"min-h-[1lh] whitespace-pre\", tone ? TONE[tone] : \"text-fg\")}>\n {text}\n </div>\n );\n })}\n </div>\n );\n })}\n {(state === \"idle\" || whole) && (\n <div className={cn(\"whitespace-pre\", state !== \"idle\" && \"mt-3\")}>\n <span className=\"text-fg-accent select-none\">{prompt} </span>\n <span className=\"kz-replay-caret\" />\n </div>\n )}\n </div>\n <pre className=\"sr-only\">{transcript}</pre>\n </div>\n </figure>\n );\n}\n\n/** Two sheets, one over the other: copy. Drawn here, like the other glyphs of the primitives (decorative). */\nfunction CopyGlyph() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-3.5 w-3.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden focusable=\"false\">\n <rect x=\"9\" y=\"9\" width=\"11\" height=\"11\" rx=\"2\" />\n <path d=\"M5 15V6a2 2 0 0 1 2-2h8\" />\n </svg>\n );\n}\n","// The small line glyphs the data and media primitives draw (play, volume, search, chevrons…): decorative, 24-unit\n// box, `currentColor`, sized by the caller's class. Shared by the entries that need them; never exported on its own —\n// a product draws its own icons with @krizaka/icons.\nimport type * as React from \"react\";\n\ntype GlyphProps = { className?: string };\n\nfunction Glyph({ className = \"h-4 w-4\", fill, children }: GlyphProps & { fill?: boolean; children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n className={className}\n fill={fill ? \"currentColor\" : \"none\"}\n stroke={fill ? \"none\" : \"currentColor\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n focusable=\"false\"\n >\n {children}\n </svg>\n );\n}\n\nexport const PlayGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <path d=\"M8 5.5v13a1 1 0 0 0 1.5.86l10.4-6.5a1 1 0 0 0 0-1.72L9.5 4.64A1 1 0 0 0 8 5.5Z\" />\n </Glyph>\n);\nexport const PauseGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n </Glyph>\n);\nexport const VolumeGlyph = ({ muted, ...p }: GlyphProps & { muted?: boolean }) => (\n <Glyph {...p}>\n <path d=\"M11 5 6 9H3v6h3l5 4V5Z\" />\n {muted ? <path d=\"m22 9-6 6m0-6 6 6\" /> : <path d=\"M15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13\" />}\n </Glyph>\n);\nexport const FullscreenGlyph = ({ exit, ...p }: GlyphProps & { exit?: boolean }) => (\n <Glyph {...p}>\n {exit ? <path d=\"M9 4v5H4m11-5v5h5M9 20v-5H4m11 5v-5h5\" /> : <path d=\"M4 9V4h5m6 0h5v5M4 15v5h5m11-5v5h-5\" />}\n </Glyph>\n);\nexport const CaptionsGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"M10 10.5a2 2 0 1 0 0 3M17 10.5a2 2 0 1 0 0 3\" />\n </Glyph>\n);\nexport const PipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <rect x=\"12\" y=\"12\" width=\"6\" height=\"4\" rx=\"1\" />\n </Glyph>\n);\nexport const SearchGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <path d=\"m20 20-3.5-3.5\" />\n </Glyph>\n);\nexport const CloseGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </Glyph>\n);\nexport const ChevronGlyph = ({ direction = \"down\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" | \"up\" | \"down\" }) => (\n <Glyph {...p}>\n <path d={{ left: \"m15 6-6 6 6 6\", right: \"m9 6 6 6-6 6\", up: \"m6 15 6-6 6 6\", down: \"m6 9 6 6 6-6\" }[direction]} />\n </Glyph>\n);\nexport const CheckGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Glyph>\n);\nexport const PlusGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 5v14M5 12h14\" />\n </Glyph>\n);\nexport const CalendarGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\" />\n <path d=\"M3 10h18M8 3v4M16 3v4\" />\n </Glyph>\n);\nexport const UploadGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 16V4m0 0L7 9m5-5 5 5\" />\n <path d=\"M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\" />\n </Glyph>\n);\nexport const FileGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5Z\" />\n <path d=\"M14 3v5h5\" />\n </Glyph>\n);\nexport const CameraGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 8h3l2-3h6l2 3h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z\" />\n <circle cx=\"12\" cy=\"13.5\" r=\"3.5\" />\n </Glyph>\n);\nexport const FlipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 0 1 14-5.3M20 12a8 8 0 0 1-14 5.3\" />\n <path d=\"M18 3v4h-4M6 21v-4h4\" />\n </Glyph>\n);\nexport const RetryGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 1 0 2.3-5.7L4 8.5\" />\n <path d=\"M4 4v4.5h4.5\" />\n </Glyph>\n);\nexport const SortGlyph = ({ direction, ...p }: GlyphProps & { direction?: \"ascending\" | \"descending\" }) => (\n <Glyph {...p}>\n {direction === \"ascending\" ? <path d=\"m7 14 5-5 5 5\" /> : direction === \"descending\" ? <path d=\"m7 10 5 5 5-5\" /> : <path d=\"m8 9 4-4 4 4M8 15l4 4 4-4\" />}\n </Glyph>\n);\nexport const ArrowGlyph = ({ direction = \"right\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" }) => (\n <Glyph {...p}>\n <path d={direction === \"left\" ? \"M19 12H5m0 0 6-6m-6 6 6 6\" : \"M5 12h14m0 0-6-6m6 6-6 6\"} />\n </Glyph>\n);\nexport const ExternalGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 4h6v6M20 4l-9 9\" />\n <path d=\"M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4\" />\n </Glyph>\n);\nexport const WarningGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 4 2.5 20h19L12 4Z\" />\n <path d=\"M12 10v4M12 17.2v.1\" />\n </Glyph>\n);\nexport const CopyGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"9\" y=\"9\" width=\"11\" height=\"11\" rx=\"2\" />\n <path d=\"M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3\" />\n </Glyph>\n);\n"],"mappings":"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","names":["jsx","jsxs"]}
package/dist/toc.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+
3
+ type TocProps = Omit<React.HTMLAttributes<HTMLElement>, "children"> & {
4
+ /** The navigation's name and visible label: `On this page`. */
5
+ label: string;
6
+ /** The sections, in order: the id of each section's title and its words. */
7
+ items: readonly {
8
+ id: string;
9
+ label: React.ReactNode;
10
+ }[];
11
+ };
12
+ /** The sections of the page, the one being read marked. */
13
+ declare function Toc({ label, items, className, ...props }: TocProps): React.JSX.Element;
14
+ type TocLayoutProps = React.HTMLAttributes<HTMLDivElement> & {
15
+ /** The table of contents (a `Toc`). */
16
+ toc: React.ReactNode;
17
+ /** The page's sections. */
18
+ children: React.ReactNode;
19
+ };
20
+ /** A reading page: the table of contents in a sticky column on the left, the sections beside it (one column on a phone). */
21
+ declare function TocLayout({ toc, children, className, ...props }: TocLayoutProps): React.JSX.Element;
22
+
23
+ export { Toc, TocLayout, type TocLayoutProps, type TocProps };
package/dist/toc.js ADDED
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import {
3
+ cn
4
+ } from "./chunk-5AXLA4LK.js";
5
+
6
+ // src/toc/toc.tsx
7
+ import * as React from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ function Toc({ label, items, className, ...props }) {
10
+ const [active, setActive] = React.useState(items[0]?.id);
11
+ React.useEffect(() => {
12
+ if (typeof IntersectionObserver === "undefined") return;
13
+ const targets = items.map((i) => document.getElementById(i.id)).filter((el) => el !== null);
14
+ const io = new IntersectionObserver(
15
+ (entries) => {
16
+ const visible = entries.filter((e) => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
17
+ if (visible[0]) setActive(visible[0].target.id);
18
+ },
19
+ { rootMargin: "-15% 0px -70% 0px" }
20
+ );
21
+ targets.forEach((t) => io.observe(t));
22
+ return () => io.disconnect();
23
+ }, [items]);
24
+ return /* @__PURE__ */ jsxs("nav", { className: cn("kz-toc", className), "aria-label": label, ...props, children: [
25
+ /* @__PURE__ */ jsx("p", { className: "kz-label", children: label }),
26
+ /* @__PURE__ */ jsx("ol", { children: items.map((i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: `#${i.id}`, "aria-current": active === i.id ? "location" : void 0, onClick: () => setActive(i.id), children: i.label }) }, i.id)) })
27
+ ] });
28
+ }
29
+ function TocLayout({ toc, children, className, ...props }) {
30
+ return /* @__PURE__ */ jsxs("div", { className: cn("kz-toc-layout", className), ...props, children: [
31
+ /* @__PURE__ */ jsx("aside", { className: "kz-toc-aside", children: toc }),
32
+ /* @__PURE__ */ jsx("div", { className: "kz-toc-main", children })
33
+ ] });
34
+ }
35
+ export {
36
+ Toc,
37
+ TocLayout
38
+ };
39
+ //# sourceMappingURL=toc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/toc/toc.tsx"],"sourcesContent":["// Client (one IntersectionObserver). The table of contents of a reading page (blocks.css): sticky beside the content on\n// a wide screen, a row of chips that scrolls sideways on a phone. The section being read is marked (`aria-current`).\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport type TocProps = Omit<React.HTMLAttributes<HTMLElement>, \"children\"> & {\n /** The navigation's name and visible label: `On this page`. */\n label: string;\n /** The sections, in order: the id of each section's title and its words. */\n items: readonly { id: string; label: React.ReactNode }[];\n};\n\n/** The sections of the page, the one being read marked. */\nexport function Toc({ label, items, className, ...props }: TocProps) {\n const [active, setActive] = React.useState(items[0]?.id);\n React.useEffect(() => {\n if (typeof IntersectionObserver === \"undefined\") return;\n const targets = items.map((i) => document.getElementById(i.id)).filter((el): el is HTMLElement => el !== null);\n const io = new IntersectionObserver(\n (entries) => {\n const visible = entries.filter((e) => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);\n if (visible[0]) setActive(visible[0].target.id);\n },\n { rootMargin: \"-15% 0px -70% 0px\" },\n );\n targets.forEach((t) => io.observe(t));\n return () => io.disconnect();\n }, [items]);\n return (\n <nav className={cn(\"kz-toc\", className)} aria-label={label} {...props}>\n <p className=\"kz-label\">{label}</p>\n <ol>\n {items.map((i) => (\n <li key={i.id}>\n <a href={`#${i.id}`} aria-current={active === i.id ? \"location\" : undefined} onClick={() => setActive(i.id)}>\n {i.label}\n </a>\n </li>\n ))}\n </ol>\n </nav>\n );\n}\n\nexport type TocLayoutProps = React.HTMLAttributes<HTMLDivElement> & {\n /** The table of contents (a `Toc`). */\n toc: React.ReactNode;\n /** The page's sections. */\n children: React.ReactNode;\n};\n\n/** A reading page: the table of contents in a sticky column on the left, the sections beside it (one column on a phone). */\nexport function TocLayout({ toc, children, className, ...props }: TocLayoutProps) {\n return (\n <div className={cn(\"kz-toc-layout\", className)} {...props}>\n <aside className=\"kz-toc-aside\">{toc}</aside>\n <div className=\"kz-toc-main\">{children}</div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAEA,YAAY,WAAW;AA4BnB,SACE,KADF;AAhBG,SAAS,IAAI,EAAE,OAAO,OAAO,WAAW,GAAG,MAAM,GAAa;AACnE,QAAM,CAAC,QAAQ,SAAS,IAAU,eAAS,MAAM,CAAC,GAAG,EAAE;AACvD,EAAM,gBAAU,MAAM;AACpB,QAAI,OAAO,yBAAyB,YAAa;AACjD,UAAM,UAAU,MAAM,IAAI,CAAC,MAAM,SAAS,eAAe,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,OAA0B,OAAO,IAAI;AAC7G,UAAM,KAAK,IAAI;AAAA,MACb,CAAC,YAAY;AACX,cAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,mBAAmB,MAAM,EAAE,mBAAmB,GAAG;AAC1H,YAAI,QAAQ,CAAC,EAAG,WAAU,QAAQ,CAAC,EAAE,OAAO,EAAE;AAAA,MAChD;AAAA,MACA,EAAE,YAAY,oBAAoB;AAAA,IACpC;AACA,YAAQ,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;AACpC,WAAO,MAAM,GAAG,WAAW;AAAA,EAC7B,GAAG,CAAC,KAAK,CAAC;AACV,SACE,qBAAC,SAAI,WAAW,GAAG,UAAU,SAAS,GAAG,cAAY,OAAQ,GAAG,OAC9D;AAAA,wBAAC,OAAE,WAAU,YAAY,iBAAM;AAAA,IAC/B,oBAAC,QACE,gBAAM,IAAI,CAAC,MACV,oBAAC,QACC,8BAAC,OAAE,MAAM,IAAI,EAAE,EAAE,IAAI,gBAAc,WAAW,EAAE,KAAK,aAAa,QAAW,SAAS,MAAM,UAAU,EAAE,EAAE,GACvG,YAAE,OACL,KAHO,EAAE,EAIX,CACD,GACH;AAAA,KACF;AAEJ;AAUO,SAAS,UAAU,EAAE,KAAK,UAAU,WAAW,GAAG,MAAM,GAAmB;AAChF,SACE,qBAAC,SAAI,WAAW,GAAG,iBAAiB,SAAS,GAAI,GAAG,OAClD;AAAA,wBAAC,WAAM,WAAU,gBAAgB,eAAI;AAAA,IACrC,oBAAC,SAAI,WAAU,eAAe,UAAS;AAAA,KACzC;AAEJ;","names":[]}
@@ -17,7 +17,7 @@ import {
17
17
  PlayGlyph,
18
18
  RetryGlyph,
19
19
  VolumeGlyph
20
- } from "./chunk-YX6CNVJA.js";
20
+ } from "./chunk-CPA5CF35.js";
21
21
 
22
22
  // src/video-player/video-player.tsx
23
23
  import * as React from "react";