@krizaka/ui 2.1.0 → 2.3.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 (289) hide show
  1. package/README.md +23 -9
  2. package/dist/{button-Cgfkg_3y.d.ts → button-BMAO7dKF.d.ts} +29 -2
  3. package/dist/button.d.ts +32 -5
  4. package/dist/button.js +62 -9
  5. package/dist/button.js.map +1 -1
  6. package/dist/chip-link.d.ts +53 -0
  7. package/dist/chip-link.js +32 -0
  8. package/dist/chip-link.js.map +1 -0
  9. package/dist/chunk-43PTCDTL.js +31 -0
  10. package/dist/chunk-43PTCDTL.js.map +1 -0
  11. package/dist/chunk-6ISW63JI.js +11 -0
  12. package/dist/chunk-6ISW63JI.js.map +1 -0
  13. package/dist/chunk-HAQWKORZ.js +117 -0
  14. package/dist/chunk-HAQWKORZ.js.map +1 -0
  15. package/dist/{chunk-FHYZSO2S.js → chunk-R6SDS7JM.js} +5 -3
  16. package/dist/chunk-R6SDS7JM.js.map +1 -0
  17. package/dist/chunk-RUPNPMP3.js +103 -0
  18. package/dist/chunk-RUPNPMP3.js.map +1 -0
  19. package/dist/chunk-VDR2EP6K.js +49 -0
  20. package/dist/chunk-VDR2EP6K.js.map +1 -0
  21. package/dist/chunk-WEVYKZIF.js +33 -0
  22. package/dist/chunk-WEVYKZIF.js.map +1 -0
  23. package/dist/command.d.ts +7 -7
  24. package/dist/command.js +3 -2
  25. package/dist/command.js.map +1 -1
  26. package/dist/confirm-button.d.ts +1 -1
  27. package/dist/confirm-button.js +2 -1
  28. package/dist/confirm-button.js.map +1 -1
  29. package/dist/{dialog-GQ4Nvuyf.d.ts → dialog-D42QwYb_.d.ts} +11 -1
  30. package/dist/dialog.d.ts +1 -1
  31. package/dist/dialog.js +3 -2
  32. package/dist/dialog.js.map +1 -1
  33. package/dist/glow-card.d.ts +20 -0
  34. package/dist/glow-card.js +30 -0
  35. package/dist/glow-card.js.map +1 -0
  36. package/dist/index.d.ts +2 -20
  37. package/dist/index.js +7 -64
  38. package/dist/index.js.map +1 -1
  39. package/dist/iso.d.ts +400 -0
  40. package/dist/iso.js +363 -0
  41. package/dist/iso.js.map +1 -0
  42. package/dist/loader.d.ts +206 -0
  43. package/dist/loader.js +138 -0
  44. package/dist/loader.js.map +1 -0
  45. package/dist/marquee.d.ts +33 -0
  46. package/dist/marquee.js +52 -0
  47. package/dist/marquee.js.map +1 -0
  48. package/dist/mascots.d.ts +40 -0
  49. package/dist/mascots.js +253 -0
  50. package/dist/mascots.js.map +1 -0
  51. package/dist/meter.d.ts +146 -0
  52. package/dist/meter.js +107 -0
  53. package/dist/meter.js.map +1 -0
  54. package/dist/motion.css +394 -3
  55. package/dist/motion.d.ts +46 -0
  56. package/dist/motion.js +10 -0
  57. package/dist/motion.js.map +1 -0
  58. package/dist/native.d.ts +40 -1
  59. package/dist/native.js +326 -128
  60. package/dist/native.js.map +1 -1
  61. package/dist/nav-bar.d.ts +178 -0
  62. package/dist/nav-bar.js +157 -0
  63. package/dist/nav-bar.js.map +1 -0
  64. package/dist/number-ticker.d.ts +32 -0
  65. package/dist/number-ticker.js +61 -0
  66. package/dist/number-ticker.js.map +1 -0
  67. package/dist/progress.d.ts +56 -1
  68. package/dist/progress.js +72 -25
  69. package/dist/progress.js.map +1 -1
  70. package/dist/skeleton.d.ts +18 -3
  71. package/dist/skeleton.js +9 -1
  72. package/dist/skeleton.js.map +1 -1
  73. package/dist/spinner.d.ts +21 -5
  74. package/dist/spinner.js +13 -12
  75. package/dist/spinner.js.map +1 -1
  76. package/dist/stepper.d.ts +112 -0
  77. package/dist/stepper.js +67 -0
  78. package/dist/stepper.js.map +1 -0
  79. package/dist/tabs.d.ts +1 -1
  80. package/dist/tabs.js +14 -8
  81. package/dist/tabs.js.map +1 -1
  82. package/dist/theme.d.ts +1 -1
  83. package/dist/theme.js +2 -1
  84. package/dist/theme.js.map +1 -1
  85. package/dist/toast.d.ts +39 -4
  86. package/dist/toast.js +81 -7
  87. package/dist/toast.js.map +1 -1
  88. package/package.json +159 -9
  89. package/registry/alert.json +1 -1
  90. package/registry/avatar.json +1 -1
  91. package/registry/badge.json +1 -1
  92. package/registry/button.json +232 -26
  93. package/registry/card.json +1 -1
  94. package/registry/checkbox.json +1 -1
  95. package/registry/chip-link.json +158 -0
  96. package/registry/chip.json +1 -1
  97. package/registry/command.json +1 -1
  98. package/registry/confirm-button.json +91 -7
  99. package/registry/countdown.json +1 -1
  100. package/registry/dialog.json +15 -7
  101. package/registry/dropdown-menu.json +1 -1
  102. package/registry/empty-state.json +1 -1
  103. package/registry/examples/button/error.js +11 -0
  104. package/registry/examples/button/error.tsx +10 -0
  105. package/registry/examples/button/loading.tsx +1 -1
  106. package/registry/examples/button/save-flow.d.ts +4 -0
  107. package/registry/examples/button/save-flow.js +28 -0
  108. package/registry/examples/button/save-flow.tsx +24 -0
  109. package/registry/examples/button/signature.d.ts +4 -0
  110. package/registry/examples/button/signature.js +17 -0
  111. package/registry/examples/button/signature.tsx +19 -0
  112. package/registry/examples/button/upload-progress.d.ts +4 -0
  113. package/registry/examples/button/upload-progress.js +23 -0
  114. package/registry/examples/button/upload-progress.tsx +26 -0
  115. package/registry/examples/chip-link/filters.d.ts +4 -0
  116. package/registry/examples/chip-link/filters.js +12 -0
  117. package/registry/examples/chip-link/filters.tsx +17 -0
  118. package/registry/examples/dialog/left.d.ts +4 -0
  119. package/registry/examples/dialog/left.js +22 -0
  120. package/registry/examples/dialog/left.tsx +32 -0
  121. package/registry/examples/glow-card/link-card.d.ts +4 -0
  122. package/registry/examples/glow-card/link-card.js +14 -0
  123. package/registry/examples/glow-card/link-card.tsx +13 -0
  124. package/registry/examples/glow-card/plans.d.ts +4 -0
  125. package/registry/examples/glow-card/plans.js +25 -0
  126. package/registry/examples/glow-card/plans.tsx +26 -0
  127. package/registry/examples/glow-card/spotlight.d.ts +4 -0
  128. package/registry/examples/glow-card/spotlight.js +14 -0
  129. package/registry/examples/glow-card/spotlight.tsx +15 -0
  130. package/registry/examples/iso/compose.d.ts +4 -0
  131. package/registry/examples/iso/compose.js +22 -0
  132. package/registry/examples/iso/compose.tsx +19 -0
  133. package/registry/examples/iso/orazaka-hero.d.ts +4 -0
  134. package/registry/examples/iso/orazaka-hero.js +26 -0
  135. package/registry/examples/iso/orazaka-hero.tsx +21 -0
  136. package/registry/examples/iso/orochia-hero.d.ts +4 -0
  137. package/registry/examples/iso/orochia-hero.js +29 -0
  138. package/registry/examples/iso/orochia-hero.tsx +23 -0
  139. package/registry/examples/iso/still.d.ts +4 -0
  140. package/registry/examples/iso/still.js +21 -0
  141. package/registry/examples/iso/still.tsx +15 -0
  142. package/registry/examples/loader/endings.d.ts +4 -0
  143. package/registry/examples/loader/endings.js +14 -0
  144. package/registry/examples/loader/endings.tsx +11 -0
  145. package/registry/examples/loader/fetch-flow.d.ts +4 -0
  146. package/registry/examples/loader/fetch-flow.js +24 -0
  147. package/registry/examples/loader/fetch-flow.tsx +24 -0
  148. package/registry/examples/loader/minimal.d.ts +4 -0
  149. package/registry/examples/loader/minimal.js +11 -0
  150. package/registry/examples/loader/minimal.tsx +6 -0
  151. package/registry/examples/loader/overlay.d.ts +4 -0
  152. package/registry/examples/loader/overlay.js +16 -0
  153. package/registry/examples/loader/overlay.tsx +13 -0
  154. package/registry/examples/loader/region-handover.d.ts +4 -0
  155. package/registry/examples/loader/region-handover.js +42 -0
  156. package/registry/examples/loader/region-handover.tsx +29 -0
  157. package/registry/examples/loader/upload-eta.d.ts +4 -0
  158. package/registry/examples/loader/upload-eta.js +11 -0
  159. package/registry/examples/loader/upload-eta.tsx +10 -0
  160. package/registry/examples/marquee/cards.d.ts +4 -0
  161. package/registry/examples/marquee/cards.js +23 -0
  162. package/registry/examples/marquee/cards.tsx +21 -0
  163. package/registry/examples/marquee/logos.d.ts +4 -0
  164. package/registry/examples/marquee/logos.js +12 -0
  165. package/registry/examples/marquee/logos.tsx +17 -0
  166. package/registry/examples/mascots/empty-state.d.ts +4 -0
  167. package/registry/examples/mascots/empty-state.js +24 -0
  168. package/registry/examples/mascots/empty-state.tsx +18 -0
  169. package/registry/examples/mascots/flock.d.ts +4 -0
  170. package/registry/examples/mascots/flock.js +14 -0
  171. package/registry/examples/mascots/flock.tsx +15 -0
  172. package/registry/examples/mascots/long-task.d.ts +4 -0
  173. package/registry/examples/mascots/long-task.js +18 -0
  174. package/registry/examples/mascots/long-task.tsx +15 -0
  175. package/registry/examples/mascots/moods.d.ts +4 -0
  176. package/registry/examples/mascots/moods.js +14 -0
  177. package/registry/examples/mascots/moods.tsx +15 -0
  178. package/registry/examples/mascots/native/default.d.ts +4 -0
  179. package/registry/examples/mascots/native/default.dark.png +0 -0
  180. package/registry/examples/mascots/native/default.js +25 -0
  181. package/registry/examples/mascots/native/default.light.png +0 -0
  182. package/registry/examples/mascots/native/default.tsx +22 -0
  183. package/registry/examples/mascots/own-tone.d.ts +4 -0
  184. package/registry/examples/mascots/own-tone.js +11 -0
  185. package/registry/examples/mascots/own-tone.tsx +12 -0
  186. package/registry/examples/meter/balance.d.ts +4 -0
  187. package/registry/examples/meter/balance.js +14 -0
  188. package/registry/examples/meter/balance.tsx +15 -0
  189. package/registry/examples/meter/quota.d.ts +4 -0
  190. package/registry/examples/meter/quota.js +15 -0
  191. package/registry/examples/meter/quota.tsx +12 -0
  192. package/registry/examples/meter/split.d.ts +4 -0
  193. package/registry/examples/meter/split.js +18 -0
  194. package/registry/examples/meter/split.tsx +18 -0
  195. package/registry/examples/nav-bar/app-bar.d.ts +4 -0
  196. package/registry/examples/nav-bar/app-bar.js +22 -0
  197. package/registry/examples/nav-bar/app-bar.tsx +21 -0
  198. package/registry/examples/nav-bar/menu-open.d.ts +4 -0
  199. package/registry/examples/nav-bar/menu-open.js +26 -0
  200. package/registry/examples/nav-bar/menu-open.tsx +26 -0
  201. package/registry/examples/nav-bar/site.d.ts +4 -0
  202. package/registry/examples/nav-bar/site.js +31 -0
  203. package/registry/examples/nav-bar/site.tsx +36 -0
  204. package/registry/examples/number-ticker/gradient.d.ts +4 -0
  205. package/registry/examples/number-ticker/gradient.js +11 -0
  206. package/registry/examples/number-ticker/gradient.tsx +10 -0
  207. package/registry/examples/number-ticker/live-total.d.ts +4 -0
  208. package/registry/examples/number-ticker/live-total.js +17 -0
  209. package/registry/examples/number-ticker/live-total.tsx +21 -0
  210. package/registry/examples/number-ticker/stats.d.ts +4 -0
  211. package/registry/examples/number-ticker/stats.js +19 -0
  212. package/registry/examples/number-ticker/stats.tsx +23 -0
  213. package/registry/examples/progress/buffer.d.ts +4 -0
  214. package/registry/examples/progress/buffer.js +11 -0
  215. package/registry/examples/progress/buffer.tsx +10 -0
  216. package/registry/examples/progress/statuses.d.ts +4 -0
  217. package/registry/examples/progress/statuses.js +14 -0
  218. package/registry/examples/progress/statuses.tsx +11 -0
  219. package/registry/examples/progress/steps.d.ts +4 -0
  220. package/registry/examples/progress/steps.js +14 -0
  221. package/registry/examples/progress/steps.tsx +13 -0
  222. package/registry/examples/progress/upload.d.ts +4 -0
  223. package/registry/examples/progress/upload.js +11 -0
  224. package/registry/examples/progress/upload.tsx +10 -0
  225. package/registry/examples/skeleton/paragraph.d.ts +4 -0
  226. package/registry/examples/skeleton/paragraph.js +14 -0
  227. package/registry/examples/skeleton/paragraph.tsx +12 -0
  228. package/registry/examples/skeleton/shape-of-content.d.ts +4 -0
  229. package/registry/examples/skeleton/shape-of-content.js +23 -0
  230. package/registry/examples/skeleton/shape-of-content.tsx +26 -0
  231. package/registry/examples/spinner/default.js +5 -2
  232. package/registry/examples/spinner/default.tsx +7 -1
  233. package/registry/examples/spinner/sizes.js +2 -1
  234. package/registry/examples/spinner/sizes.tsx +2 -0
  235. package/registry/examples/spinner/value.d.ts +4 -0
  236. package/registry/examples/spinner/value.js +11 -0
  237. package/registry/examples/spinner/value.tsx +12 -0
  238. package/registry/examples/stepper/checkout.d.ts +4 -0
  239. package/registry/examples/stepper/checkout.js +22 -0
  240. package/registry/examples/stepper/checkout.tsx +17 -0
  241. package/registry/examples/stepper/failed.d.ts +4 -0
  242. package/registry/examples/stepper/failed.js +26 -0
  243. package/registry/examples/stepper/failed.tsx +21 -0
  244. package/registry/examples/stepper/job.d.ts +4 -0
  245. package/registry/examples/stepper/job.js +32 -0
  246. package/registry/examples/stepper/job.tsx +28 -0
  247. package/registry/examples/toast/grouped.d.ts +4 -0
  248. package/registry/examples/toast/grouped.js +21 -0
  249. package/registry/examples/toast/grouped.tsx +23 -0
  250. package/registry/examples/toast/undo.d.ts +4 -0
  251. package/registry/examples/toast/undo.js +29 -0
  252. package/registry/examples/toast/undo.tsx +30 -0
  253. package/registry/examples/toast/upload-progress.d.ts +4 -0
  254. package/registry/examples/toast/upload-progress.js +29 -0
  255. package/registry/examples/toast/upload-progress.tsx +31 -0
  256. package/registry/field.json +1 -1
  257. package/registry/glow-card.json +162 -0
  258. package/registry/index.json +207 -20
  259. package/registry/iso.json +1355 -0
  260. package/registry/kbd.json +1 -1
  261. package/registry/loader.json +399 -0
  262. package/registry/marquee.json +225 -0
  263. package/registry/mascots.json +314 -0
  264. package/registry/meter.json +324 -0
  265. package/registry/nav-bar.json +480 -0
  266. package/registry/number-ticker.json +219 -0
  267. package/registry/page-header.json +1 -1
  268. package/registry/popover.json +1 -1
  269. package/registry/progress.json +116 -11
  270. package/registry/radio-group.json +1 -1
  271. package/registry/section-backdrop.json +1 -1
  272. package/registry/separator.json +1 -1
  273. package/registry/skeleton.json +69 -13
  274. package/registry/slider.json +1 -1
  275. package/registry/slot.json +1 -1
  276. package/registry/spinner.json +91 -27
  277. package/registry/stat.json +1 -1
  278. package/registry/stepper.json +174 -0
  279. package/registry/switch.json +1 -1
  280. package/registry/tabs.json +11 -7
  281. package/registry/theme.json +3 -3
  282. package/registry/toast.json +41 -13
  283. package/registry/tooltip.json +1 -1
  284. package/dist/chunk-FHYZSO2S.js.map +0 -1
  285. package/dist/chunk-PESA2R4U.js +0 -51
  286. package/dist/chunk-PESA2R4U.js.map +0 -1
  287. package/registry/examples/spinner/muted.js +0 -11
  288. package/registry/examples/spinner/muted.tsx +0 -6
  289. /package/registry/examples/{spinner/muted.d.ts → button/error.d.ts} +0 -0
@@ -0,0 +1,117 @@
1
+ "use client";
2
+
3
+ // src/motion/MotionObserver.tsx
4
+ import { useEffect } from "react";
5
+ var SCOPES = ".kz-backdrop, .kz-iso, [data-motion-scope], main > section, main > header, footer";
6
+ var REVEAL = "[data-reveal]:not(.kz-in)";
7
+ var MAGNETIC = "[data-kz-magnetic]";
8
+ var SETTLE_MS = 1200;
9
+ function MotionObserver({ settle = true, pauseOffscreen = true } = {}) {
10
+ useEffect(() => {
11
+ const root = document.documentElement;
12
+ const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
13
+ let settleTimer;
14
+ const ready = () => settleTimer = setTimeout(() => root.setAttribute("data-motion", "ready"), SETTLE_MS);
15
+ if (settle && !reduce && root.getAttribute("data-motion") !== "ready") {
16
+ root.setAttribute("data-motion", "settling");
17
+ if (document.readyState === "complete") ready();
18
+ else window.addEventListener("load", ready, { once: true });
19
+ } else root.setAttribute("data-motion", "ready");
20
+ const revealIo = reduce ? null : new IntersectionObserver(
21
+ (entries) => {
22
+ for (const entry of entries) {
23
+ if (!entry.isIntersecting) continue;
24
+ entry.target.classList.add("kz-in");
25
+ revealIo.unobserve(entry.target);
26
+ }
27
+ },
28
+ { rootMargin: "0px 0px -8% 0px", threshold: 0.12 }
29
+ );
30
+ const scopeIo = pauseOffscreen ? new IntersectionObserver(
31
+ (entries) => {
32
+ for (const entry of entries) entry.target.toggleAttribute("data-offscreen", !entry.isIntersecting);
33
+ },
34
+ { rootMargin: "120px 0px" }
35
+ ) : null;
36
+ const reveal = (el) => revealIo ? revealIo.observe(el) : el.classList.add("kz-in");
37
+ const watch = (scope) => {
38
+ scope.querySelectorAll(REVEAL).forEach(reveal);
39
+ if (scopeIo) scope.querySelectorAll(SCOPES).forEach((el) => scopeIo.observe(el));
40
+ };
41
+ watch(document);
42
+ const mo = new MutationObserver((records) => {
43
+ for (const record of records)
44
+ record.addedNodes.forEach((node) => {
45
+ if (!(node instanceof Element)) return;
46
+ if (node.matches(REVEAL)) reveal(node);
47
+ if (scopeIo && node.matches(SCOPES)) scopeIo.observe(node);
48
+ watch(node);
49
+ });
50
+ });
51
+ mo.observe(document.body, { childList: true, subtree: true });
52
+ return () => {
53
+ clearTimeout(settleTimer);
54
+ window.removeEventListener("load", ready);
55
+ revealIo?.disconnect();
56
+ scopeIo?.disconnect();
57
+ mo.disconnect();
58
+ };
59
+ }, [settle, pauseOffscreen]);
60
+ useEffect(() => {
61
+ const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
62
+ const fine = window.matchMedia("(hover: hover) and (pointer: fine)").matches;
63
+ let magnet = null;
64
+ const release = () => {
65
+ magnet?.style.removeProperty("--kz-mag-x");
66
+ magnet?.style.removeProperty("--kz-mag-y");
67
+ magnet = null;
68
+ };
69
+ const move = (e) => {
70
+ const target = e.target;
71
+ const card = target?.closest?.(".kz-spotlight");
72
+ if (card) {
73
+ const box2 = card.getBoundingClientRect();
74
+ card.style.setProperty("--spot-x", `${e.clientX - box2.left}px`);
75
+ card.style.setProperty("--spot-y", `${e.clientY - box2.top}px`);
76
+ }
77
+ if (reduce || !fine) return;
78
+ const el = target?.closest?.(MAGNETIC);
79
+ if (el !== magnet) release();
80
+ if (!el) return;
81
+ magnet = el;
82
+ const box = el.getBoundingClientRect();
83
+ const pull = (offset, half) => `${(Math.max(-1, Math.min(1, offset / half)) * 6).toFixed(2)}px`;
84
+ el.style.setProperty("--kz-mag-x", pull(e.clientX - box.left - box.width / 2, box.width / 2));
85
+ el.style.setProperty("--kz-mag-y", pull(e.clientY - box.top - box.height / 2, box.height / 2));
86
+ };
87
+ document.addEventListener("pointermove", move, { passive: true });
88
+ document.addEventListener("pointerleave", release);
89
+ return () => {
90
+ document.removeEventListener("pointermove", move);
91
+ document.removeEventListener("pointerleave", release);
92
+ release();
93
+ };
94
+ }, []);
95
+ return null;
96
+ }
97
+
98
+ // src/motion/RotatingWord.tsx
99
+ import { useEffect as useEffect2, useState } from "react";
100
+ import { jsx } from "react/jsx-runtime";
101
+ function RotatingWord({ words, interval = 2600, className }) {
102
+ const [i, setI] = useState(0);
103
+ useEffect2(() => {
104
+ if (words.length < 2 || window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
105
+ const timer = setInterval(() => {
106
+ if (!document.hidden) setI((k) => (k + 1) % words.length);
107
+ }, interval);
108
+ return () => clearInterval(timer);
109
+ }, [words.length, interval]);
110
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "kz-rotating", children: words.map((word, k) => /* @__PURE__ */ jsx("span", { "data-active": k === i, className, children: word }, word)) });
111
+ }
112
+
113
+ export {
114
+ MotionObserver,
115
+ RotatingWord
116
+ };
117
+ //# sourceMappingURL=chunk-HAQWKORZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/motion/MotionObserver.tsx","../src/motion/RotatingWord.tsx"],"sourcesContent":["import { useEffect } from \"react\";\n\n/** What gets `data-offscreen` while out of view: its animations pause (motion.css). */\nconst SCOPES = \".kz-backdrop, .kz-iso, [data-motion-scope], main > section, main > header, footer\";\nconst REVEAL = \"[data-reveal]:not(.kz-in)\";\nconst MAGNETIC = \"[data-kz-magnetic]\";\n/** How long after `load` the first screen's loops wait before they start (LCP first). */\nconst SETTLE_MS = 1200;\n\nexport interface MotionObserverProps {\n /**\n * Hold the loops of the page (`.kz-loop`, the backdrop's drift) still until the page has loaded and settled\n * (`html[data-motion=\"settling\"]` → `\"ready\"`, about 1.2 s after `load`): nothing repaints the first screen while it\n * paints.\n * @default true\n */\n settle?: boolean;\n /**\n * Pause every animation of a scope while it is off screen (`data-offscreen` on `.kz-backdrop`, `.kz-iso`,\n * `[data-motion-scope]` and the page's sections).\n * @default true\n */\n pauseOffscreen?: boolean;\n}\n\n/**\n * The Krizaka motion conductor. Mount it once at the root of the app; it renders nothing and keeps no animation frame\n * running. It reveals every `[data-reveal]` element once as it enters the viewport (including elements added later:\n * client navigation needs nothing more), pauses what is off screen, lets the first screen settle before its loops\n * start, feeds the pointer to `.kz-spotlight` cards (`--spot-x`, `--spot-y`) and to `[data-kz-magnetic]` elements\n * (`Button magnetic`). Under prefers-reduced-motion everything is revealed at once and nothing follows the pointer.\n */\nexport function MotionObserver({ settle = true, pauseOffscreen = true }: MotionObserverProps = {}): null {\n useEffect(() => {\n const root = document.documentElement;\n const reduce = window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\n let settleTimer: ReturnType<typeof setTimeout> | undefined;\n const ready = () => (settleTimer = setTimeout(() => root.setAttribute(\"data-motion\", \"ready\"), SETTLE_MS));\n if (settle && !reduce && root.getAttribute(\"data-motion\") !== \"ready\") {\n root.setAttribute(\"data-motion\", \"settling\");\n if (document.readyState === \"complete\") ready();\n else window.addEventListener(\"load\", ready, { once: true });\n } else root.setAttribute(\"data-motion\", \"ready\");\n\n const revealIo = reduce\n ? null\n : new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n entry.target.classList.add(\"kz-in\");\n revealIo!.unobserve(entry.target);\n }\n },\n { rootMargin: \"0px 0px -8% 0px\", threshold: 0.12 },\n );\n const scopeIo = pauseOffscreen\n ? new IntersectionObserver(\n (entries) => {\n for (const entry of entries) entry.target.toggleAttribute(\"data-offscreen\", !entry.isIntersecting);\n },\n { rootMargin: \"120px 0px\" },\n )\n : null;\n\n const reveal = (el: Element) => (revealIo ? revealIo.observe(el) : el.classList.add(\"kz-in\"));\n const watch = (scope: ParentNode) => {\n scope.querySelectorAll(REVEAL).forEach(reveal);\n if (scopeIo) scope.querySelectorAll(SCOPES).forEach((el) => scopeIo.observe(el));\n };\n watch(document);\n const mo = new MutationObserver((records) => {\n for (const record of records)\n record.addedNodes.forEach((node) => {\n if (!(node instanceof Element)) return;\n if (node.matches(REVEAL)) reveal(node);\n if (scopeIo && node.matches(SCOPES)) scopeIo.observe(node);\n watch(node);\n });\n });\n mo.observe(document.body, { childList: true, subtree: true });\n\n return () => {\n clearTimeout(settleTimer);\n window.removeEventListener(\"load\", ready);\n revealIo?.disconnect();\n scopeIo?.disconnect();\n mo.disconnect();\n };\n }, [settle, pauseOffscreen]);\n\n useEffect(() => {\n const reduce = window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n const fine = window.matchMedia(\"(hover: hover) and (pointer: fine)\").matches;\n let magnet: HTMLElement | null = null;\n const release = () => {\n magnet?.style.removeProperty(\"--kz-mag-x\");\n magnet?.style.removeProperty(\"--kz-mag-y\");\n magnet = null;\n };\n const move = (e: PointerEvent) => {\n const target = e.target as Element | null;\n const card = target?.closest?.(\".kz-spotlight\") as HTMLElement | null;\n if (card) {\n const box = card.getBoundingClientRect();\n card.style.setProperty(\"--spot-x\", `${e.clientX - box.left}px`);\n card.style.setProperty(\"--spot-y\", `${e.clientY - box.top}px`);\n }\n if (reduce || !fine) return;\n const el = target?.closest?.(MAGNETIC) as HTMLElement | null;\n if (el !== magnet) release();\n if (!el) return;\n magnet = el;\n const box = el.getBoundingClientRect();\n // A lean of at most ~6 px, a fraction of the pointer's offset from the centre.\n const pull = (offset: number, half: number) => `${(Math.max(-1, Math.min(1, offset / half)) * 6).toFixed(2)}px`;\n el.style.setProperty(\"--kz-mag-x\", pull(e.clientX - box.left - box.width / 2, box.width / 2));\n el.style.setProperty(\"--kz-mag-y\", pull(e.clientY - box.top - box.height / 2, box.height / 2));\n };\n document.addEventListener(\"pointermove\", move, { passive: true });\n document.addEventListener(\"pointerleave\", release);\n return () => {\n document.removeEventListener(\"pointermove\", move);\n document.removeEventListener(\"pointerleave\", release);\n release();\n };\n }, []);\n\n return null;\n}\n","import { useEffect, useState } from \"react\";\n\nexport interface RotatingWordProps {\n /** The alternatives, passed translated; the first one is what the server renders. */\n words: readonly string[];\n /**\n * Milliseconds each word stays.\n * @default 2600\n */\n interval?: number;\n /** Classes for every word (a colour, gradient text). */\n className?: string;\n}\n\n/**\n * A word that rolls through alternatives — the Krizaka headline signature. Every word shares one grid cell from the\n * first paint, so the line keeps the width of the longest one (no layout shift); the current one rolls in. The server\n * render shows the first word; it stays put under prefers-reduced-motion and while the tab is hidden. Decorative\n * (`aria-hidden`): give the heading a stable accessible label.\n */\nexport function RotatingWord({ words, interval = 2600, className }: RotatingWordProps) {\n const [i, setI] = useState(0);\n useEffect(() => {\n if (words.length < 2 || window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n const timer = setInterval(() => {\n if (!document.hidden) setI((k) => (k + 1) % words.length);\n }, interval);\n return () => clearInterval(timer);\n }, [words.length, interval]);\n return (\n <span aria-hidden className=\"kz-rotating\">\n {words.map((word, k) => (\n <span key={word} data-active={k === i} className={className}>\n {word}\n </span>\n ))}\n </span>\n );\n}\n"],"mappings":"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","names":["box","useEffect"]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  IconButton
4
- } from "./chunk-PESA2R4U.js";
4
+ } from "./chunk-RUPNPMP3.js";
5
5
 
6
6
  // src/dialog/dialog.tsx
7
7
  import { Dialog as DialogPrimitive } from "radix-ui";
@@ -25,7 +25,9 @@ var dialog = tv({
25
25
  bottom: {
26
26
  content: "inset-x-0 bottom-0 max-h-[92dvh] rounded-t-[1.75rem] sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:w-full sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-[1.75rem]"
27
27
  },
28
- right: { content: "inset-y-0 right-0 h-full w-full max-w-md rounded-none border-y-0 border-r-0" }
28
+ right: { content: "inset-y-0 right-0 h-full w-full max-w-md rounded-none border-y-0 border-r-0" },
29
+ /* A navigation drawer: full height, from the left, clear of the notch. */
30
+ left: { content: "inset-y-0 left-0 h-full w-full max-w-md rounded-none border-y-0 border-l-0 pl-[env(safe-area-inset-left)]" }
29
31
  },
30
32
  size: { sm: { content: "sm:max-w-sm" }, md: { content: "sm:max-w-md" }, lg: { content: "sm:max-w-2xl" } }
31
33
  },
@@ -118,4 +120,4 @@ export {
118
120
  Dialog,
119
121
  Sheet
120
122
  };
121
- //# sourceMappingURL=chunk-FHYZSO2S.js.map
123
+ //# sourceMappingURL=chunk-R6SDS7JM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dialog/dialog.tsx"],"sourcesContent":["// Client (a portal). Radix does the focus trap, the scroll lock, Escape, the outside click, aria-modal, the\n// aria-labelledby / aria-describedby wiring and the focus return: this file only holds the shape.\nimport { Dialog as DialogPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { IconButton } from \"../button/button\";\n\nexport const dialog = tv({\n slots: {\n overlay: \"kz-overlay fixed inset-0 z-50 bg-overlay backdrop-blur-xs\",\n content:\n \"kz-dialog fixed z-50 flex flex-col overflow-hidden border border-border-default bg-surface-1 text-fg shadow-lg focus:outline-hidden\",\n close: \"absolute right-3 top-3 h-9 w-9\",\n header: \"flex flex-col gap-1 px-5 pb-2 pr-14 pt-5\",\n title: \"text-base font-bold text-fg\",\n description: \"text-sm text-fg-secondary\",\n body: \"min-h-0 flex-1 overflow-y-auto px-5 pb-5\",\n footer:\n \"flex flex-wrap items-center justify-end gap-2 border-t border-border-subtle px-5 py-4 pb-[max(1rem,env(safe-area-inset-bottom))]\",\n },\n variants: {\n placement: {\n center: { content: \"left-1/2 top-1/2 max-h-[85dvh] w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl\" },\n /* A sheet: anchored at the bottom on a phone, centred from `sm` up. */\n bottom: {\n content:\n \"inset-x-0 bottom-0 max-h-[92dvh] rounded-t-[1.75rem] sm:bottom-auto sm:left-1/2 sm:top-1/2 sm:w-full \" +\n \"sm:-translate-x-1/2 sm:-translate-y-1/2 sm:rounded-[1.75rem]\",\n },\n right: { content: \"inset-y-0 right-0 h-full w-full max-w-md rounded-none border-y-0 border-r-0\" },\n /* A navigation drawer: full height, from the left, clear of the notch. */\n left: { content: \"inset-y-0 left-0 h-full w-full max-w-md rounded-none border-y-0 border-l-0 pl-[env(safe-area-inset-left)]\" },\n },\n size: { sm: { content: \"sm:max-w-sm\" }, md: { content: \"sm:max-w-md\" }, lg: { content: \"sm:max-w-2xl\" } },\n },\n defaultVariants: { placement: \"center\", size: \"md\" },\n});\nconst s = dialog();\n\nexport type DialogVariants = VariantProps<typeof dialog>;\n\nfunction CloseIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n );\n}\n\ntype CloseButtonProps =\n | {\n /** The accessible name of the close button — passed translated. */\n closeLabel: string;\n /** Leaves the close button out (the content brings its own way out, or none: see `dismissible`). */\n hideClose?: false;\n }\n | { closeLabel?: string; hideClose: true };\n\nexport type DialogContentProps = React.ComponentProps<typeof DialogPrimitive.Content> &\n DialogVariants &\n CloseButtonProps & {\n /**\n * center · bottom (a sheet on a phone, centred from `sm` up) · right (a side panel, full height) · left (a\n * navigation drawer, full height).\n * @default \"center\"\n */\n placement?: DialogVariants[\"placement\"];\n /**\n * sm · md · lg: the width of the dialog.\n * @default \"md\"\n */\n size?: DialogVariants[\"size\"];\n /**\n * `false`: Escape and a click outside do not close it (a gate the user must answer: age, terms). It still closes\n * through `open` / `onOpenChange` and any `Dialog.Close` inside. Default `true`.\n */\n dismissible?: boolean;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n };\n\nconst prevent = (event: Event) => event.preventDefault();\n\n/** The dialog itself, portalled over a dimmed overlay, with a close button. Give it a `Dialog.Title`. */\nexport function DialogContent({\n placement,\n size,\n closeLabel,\n hideClose,\n dismissible = true,\n container,\n className,\n children,\n onEscapeKeyDown,\n onPointerDownOutside,\n onInteractOutside,\n ...props\n}: DialogContentProps) {\n const v = dialog({ placement, size });\n return (\n <DialogPrimitive.Portal container={container}>\n <DialogPrimitive.Overlay className={v.overlay()} />\n <DialogPrimitive.Content\n data-placement={placement ?? \"center\"}\n data-dismissible={dismissible ? undefined : \"false\"}\n className={v.content({ className })}\n onEscapeKeyDown={dismissible ? onEscapeKeyDown : chain(onEscapeKeyDown, prevent)}\n onPointerDownOutside={dismissible ? onPointerDownOutside : chain(onPointerDownOutside, prevent)}\n onInteractOutside={dismissible ? onInteractOutside : chain(onInteractOutside, prevent)}\n {...props}\n >\n {children}\n {!hideClose && (\n <DialogPrimitive.Close asChild>\n <IconButton label={closeLabel as string} variant=\"ghost\" shape=\"pill\" className={v.close()}>\n <CloseIcon />\n </IconButton>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n}\n\nfunction chain<E extends Event>(handler: ((event: E) => void) | undefined, then: (event: E) => void) {\n return (event: E) => {\n handler?.(event);\n then(event);\n };\n}\n\nexport function DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.header({ className })} {...props} />;\n}\n\nexport function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return <DialogPrimitive.Title className={s.title({ className })} {...props} />;\n}\n\nexport function DialogDescription({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return <DialogPrimitive.Description className={s.description({ className })} {...props} />;\n}\n\nexport function DialogBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport function DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.footer({ className })} {...props} />;\n}\n\n/** `Dialog.Root/Trigger/Content/Header/Title/Description/Body/Footer/Close`. `open`/`defaultOpen` + `onOpenChange`. */\nexport const Dialog = {\n Root: DialogPrimitive.Root,\n Trigger: DialogPrimitive.Trigger,\n Close: DialogPrimitive.Close,\n Content: DialogContent,\n Header: DialogHeader,\n Title: DialogTitle,\n Description: DialogDescription,\n Body: DialogBody,\n Footer: DialogFooter,\n};\n\n/** `Omit` that keeps the close-button union (`closeLabel` required unless `hideClose`). */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\nexport type SheetProps = DistributiveOmit<DialogContentProps, \"placement\">;\n\n/** A sheet is a dialog anchored at the bottom (centred from `sm` up): `Dialog.Content placement=\"bottom\"`. */\nexport function Sheet(props: SheetProps) {\n return <DialogContent placement=\"bottom\" {...props} />;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ import {
3
+ LoaderGlyph
4
+ } from "./chunk-WEVYKZIF.js";
5
+
6
+ // src/button/button.tsx
7
+ import { Slot } from "radix-ui";
8
+ import { tv } from "tailwind-variants";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ var buttonVariants = tv({
11
+ base: "inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98] [&[data-loading]]:opacity-100",
12
+ variants: {
13
+ variant: {
14
+ primary: "bg-accent text-on-accent shadow-sm hover:bg-accent-hover",
15
+ // The brand's signature: accent → accent-2 (on-accent reads on both stops, tested in @krizaka/tokens).
16
+ gradient: "bg-linear-to-r from-accent to-accent-2 text-on-accent shadow-sm hover:brightness-110",
17
+ secondary: "border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3",
18
+ outline: "border border-border-default bg-transparent text-fg hover:border-accent hover:text-fg-accent",
19
+ ghost: "text-fg-secondary hover:bg-surface-2 hover:text-fg",
20
+ // The border and the tint carry the danger; the label stays the primary text role, legible on the tint at rest
21
+ // and hovered over every surface (`text-fg-danger` is for text set directly on a surface).
22
+ danger: "border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20"
23
+ },
24
+ size: { sm: "h-8 px-3 text-xs", md: "h-10 px-4 text-sm", lg: "h-12 px-6 text-sm", icon: "h-10 w-10" },
25
+ // `cut`: the Krizaka chamfer — 45° corners (CSS corner-shape, where supported; rounded elsewhere). The border, the
26
+ // focus ring and the hover follow the cut, unlike a clip-path.
27
+ shape: { rounded: "rounded-lg", pill: "rounded-full", cut: "rounded-[10px] [corner-shape:bevel]" }
28
+ },
29
+ defaultVariants: { variant: "secondary", size: "md", shape: "rounded" }
30
+ });
31
+ var STATUS_TEXT = { success: "text-fg-success", error: "text-fg-danger" };
32
+ function Button({
33
+ asChild,
34
+ loading,
35
+ progress,
36
+ status,
37
+ announce,
38
+ indicator = true,
39
+ shimmer,
40
+ magnetic,
41
+ variant,
42
+ size,
43
+ shape,
44
+ className,
45
+ disabled,
46
+ children,
47
+ ...props
48
+ }) {
49
+ const Comp = asChild ? Slot.Root : "button";
50
+ const known = loading && typeof progress === "number" && Number.isFinite(progress);
51
+ const ratio = known ? Math.min(1, Math.max(0, progress)) : 0;
52
+ const glyph = indicator && !asChild && (loading || status) ? status ?? "loading" : null;
53
+ const filled = variant === "primary" || variant === "gradient";
54
+ const button = /* @__PURE__ */ jsx(
55
+ Comp,
56
+ {
57
+ type: asChild ? void 0 : "button",
58
+ "aria-busy": loading || void 0,
59
+ "data-loading": loading ? "" : void 0,
60
+ "data-variant": variant ?? "secondary",
61
+ "data-kz-status": status ?? void 0,
62
+ "data-kz-magnetic": magnetic ? "" : void 0,
63
+ disabled: asChild ? void 0 : disabled || loading,
64
+ "aria-disabled": asChild && (disabled || loading) ? true : void 0,
65
+ className: buttonVariants({
66
+ variant,
67
+ size,
68
+ shape,
69
+ className: [known && "relative isolate overflow-hidden", shimmer && "kz-sheen", className].filter(Boolean).join(" ") || void 0
70
+ }),
71
+ ...props,
72
+ children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
73
+ known && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute inset-y-0 left-0 -z-10 bg-current opacity-15 transition-[width] duration-500", style: { width: `${ratio * 100}%` } }),
74
+ glyph && /* @__PURE__ */ jsx(
75
+ "span",
76
+ {
77
+ "aria-hidden": true,
78
+ "data-slot": "indicator",
79
+ className: "-my-1 grid grid-cols-[1fr] transition-[grid-template-columns,margin,opacity] duration-300 starting:-mr-2 starting:grid-cols-[0fr] starting:opacity-0",
80
+ children: /* @__PURE__ */ jsx("span", { className: "overflow-hidden", children: /* @__PURE__ */ jsx(LoaderGlyph, { state: glyph, value: known ? ratio : null, className: ["h-4 w-4", glyph !== "loading" && !filled && STATUS_TEXT[glyph]].filter(Boolean).join(" ") }) })
81
+ }
82
+ ),
83
+ children
84
+ ] })
85
+ }
86
+ );
87
+ if (announce === void 0 || asChild) return button;
88
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
89
+ button,
90
+ /* @__PURE__ */ jsx("span", { role: "status", className: "sr-only", children: announce })
91
+ ] });
92
+ }
93
+ function IconButton({ label, size = "icon", children, ...props }) {
94
+ const swap = props.indicator !== false && !props.asChild && (props.loading || props.status);
95
+ return /* @__PURE__ */ jsx(Button, { "aria-label": label, title: label, size, ...props, children: swap ? null : children });
96
+ }
97
+
98
+ export {
99
+ buttonVariants,
100
+ Button,
101
+ IconButton
102
+ };
103
+ //# sourceMappingURL=chunk-RUPNPMP3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/button/button.tsx"],"sourcesContent":["// Server-safe: no hook, no context. `buttonVariants` styles a <Link> or a Server Component without the component.\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { LoaderGlyph } from \"../spinner/glyph\";\n\nexport const buttonVariants = tv({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98] \" +\n // Busy is not unavailable: a loading button keeps its colour (it is disabled only so it is not pressed twice).\n \"[&[data-loading]]:opacity-100\",\n variants: {\n variant: {\n primary: \"bg-accent text-on-accent shadow-sm hover:bg-accent-hover\",\n // The brand's signature: accent → accent-2 (on-accent reads on both stops, tested in @krizaka/tokens).\n gradient: \"bg-linear-to-r from-accent to-accent-2 text-on-accent shadow-sm hover:brightness-110\",\n secondary: \"border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3\",\n outline: \"border border-border-default bg-transparent text-fg hover:border-accent hover:text-fg-accent\",\n ghost: \"text-fg-secondary hover:bg-surface-2 hover:text-fg\",\n // The border and the tint carry the danger; the label stays the primary text role, legible on the tint at rest\n // and hovered over every surface (`text-fg-danger` is for text set directly on a surface).\n danger: \"border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20\",\n },\n size: { sm: \"h-8 px-3 text-xs\", md: \"h-10 px-4 text-sm\", lg: \"h-12 px-6 text-sm\", icon: \"h-10 w-10\" },\n // `cut`: the Krizaka chamfer — 45° corners (CSS corner-shape, where supported; rounded elsewhere). The border, the\n // focus ring and the hover follow the cut, unlike a clip-path.\n shape: { rounded: \"rounded-lg\", pill: \"rounded-full\", cut: \"rounded-[10px] [corner-shape:bevel]\" },\n },\n defaultVariants: { variant: \"secondary\", size: \"md\", shape: \"rounded\" },\n});\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n ButtonVariants & {\n /**\n * The look: `primary` (the accent), `gradient` (accent → accent-2), `secondary` (a raised surface), `outline`,\n * `ghost`, `danger`.\n * @default \"secondary\"\n */\n variant?: ButtonVariants[\"variant\"];\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"md\"\n */\n size?: ButtonVariants[\"size\"];\n /**\n * rounded · pill · cut (45° corners, the Krizaka chamfer).\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */\n asChild?: boolean;\n /**\n * Disables and signals the wait (aria-busy, data-loading) and shows the Krizaka loader glyph before the label; the\n * button keeps its colour.\n */\n loading?: boolean;\n /**\n * Between 0 and 1, while `loading`: the glyph's trace and a light fill across the button grow to the value (an\n * upload, an export).\n */\n progress?: number | null;\n /**\n * How the action ended: `success` draws a check, `error` a cross (and the button shakes its head once); a ring of\n * the status colour opens around it. Clear it to return to rest.\n */\n status?: \"success\" | \"error\" | null;\n /** A message announced politely by assistive technology when it changes (“Saved”, “Upload failed”) — passed translated. */\n announce?: string;\n /**\n * Shows the glyph while `loading` / with a `status`. `false`: you draw your own.\n * @default true\n */\n indicator?: boolean;\n /** A sheen of light crosses the button on hover — for the one action a page is about. */\n shimmer?: boolean;\n /** The button leans a few pixels toward a fine pointer (driven by `MotionObserver`; never under reduced motion or on touch). */\n magnetic?: boolean;\n };\n\nconst STATUS_TEXT = { success: \"text-fg-success\", error: \"text-fg-danger\" } as const;\n\nexport function Button({\n asChild,\n loading,\n progress,\n status,\n announce,\n indicator = true,\n shimmer,\n magnetic,\n variant,\n size,\n shape,\n className,\n disabled,\n children,\n ...props\n}: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n const known = loading && typeof progress === \"number\" && Number.isFinite(progress);\n const ratio = known ? Math.min(1, Math.max(0, progress)) : 0;\n const glyph = indicator && !asChild && (loading || status) ? (status ?? \"loading\") : null;\n // On a filled variant the glyph stays in the label's colour; on the others it takes the status colour.\n const filled = variant === \"primary\" || variant === \"gradient\";\n const button = (\n <Comp\n type={asChild ? undefined : \"button\"}\n aria-busy={loading || undefined}\n data-loading={loading ? \"\" : undefined}\n data-variant={variant ?? \"secondary\"}\n data-kz-status={status ?? undefined}\n data-kz-magnetic={magnetic ? \"\" : undefined}\n disabled={asChild ? undefined : disabled || loading}\n aria-disabled={asChild && (disabled || loading) ? true : undefined}\n className={buttonVariants({\n variant,\n size,\n shape,\n className: [known && \"relative isolate overflow-hidden\", shimmer && \"kz-sheen\", className].filter(Boolean).join(\" \") || undefined,\n })}\n {...props}\n >\n {asChild ? (\n children\n ) : (\n <>\n {known && (\n <span aria-hidden className=\"absolute inset-y-0 left-0 -z-10 bg-current opacity-15 transition-[width] duration-500\" style={{ width: `${ratio * 100}%` }} />\n )}\n {glyph && (\n <span\n aria-hidden\n data-slot=\"indicator\"\n className=\"-my-1 grid grid-cols-[1fr] transition-[grid-template-columns,margin,opacity] duration-300 starting:-mr-2 starting:grid-cols-[0fr] starting:opacity-0\"\n >\n <span className=\"overflow-hidden\">\n <LoaderGlyph state={glyph} value={known ? ratio : null} className={[\"h-4 w-4\", glyph !== \"loading\" && !filled && STATUS_TEXT[glyph]].filter(Boolean).join(\" \")} />\n </span>\n </span>\n )}\n {children}\n </>\n )}\n </Comp>\n );\n if (announce === undefined || asChild) return button;\n return (\n <>\n {button}\n <span role=\"status\" className=\"sr-only\">\n {announce}\n </span>\n </>\n );\n}\n\nexport type IconButtonProps = Omit<ButtonProps, \"size\"> & {\n /** The accessible name (and tooltip) of the button — required, passed translated. */\n label: string;\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"icon\"\n */\n size?: ButtonProps[\"size\"];\n};\n\n/** An icon-only button: `label` is required, it is its accessible name. Loading or with a status, the glyph takes the icon's place. */\nexport function IconButton({ label, size = \"icon\", children, ...props }: IconButtonProps) {\n const swap = props.indicator !== false && !props.asChild && (props.loading || props.status);\n return (\n <Button aria-label={label} title={label} size={size} {...props}>\n {swap ? null : children}\n </Button>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ // src/sliding-indicator.ts
4
+ import * as React from "react";
5
+ var useIsoLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
6
+ function useSlidingIndicator({ item, active, follow = false }) {
7
+ const ref = React.useRef(null);
8
+ const place = React.useCallback((target) => {
9
+ const list = ref.current;
10
+ if (!list) return;
11
+ if (!(target instanceof HTMLElement) || !list.contains(target)) {
12
+ list.removeAttribute("data-indicator");
13
+ return;
14
+ }
15
+ const a = target.getBoundingClientRect();
16
+ const b = list.getBoundingClientRect();
17
+ list.style.setProperty("--kz-ind-x", `${a.left - b.left + list.scrollLeft}px`);
18
+ list.style.setProperty("--kz-ind-y", `${a.top - b.top + list.scrollTop}px`);
19
+ list.style.setProperty("--kz-ind-w", `${a.width}px`);
20
+ list.style.setProperty("--kz-ind-h", `${a.height}px`);
21
+ list.setAttribute("data-indicator", "on");
22
+ }, []);
23
+ const rest = React.useCallback(() => place(ref.current?.querySelector(active) ?? null), [place, active]);
24
+ useIsoLayoutEffect(() => {
25
+ const list = ref.current;
26
+ if (!list) return;
27
+ rest();
28
+ const resize = new ResizeObserver(rest);
29
+ resize.observe(list);
30
+ const changes = new MutationObserver(rest);
31
+ changes.observe(list, { subtree: true, attributes: true, attributeFilter: ["data-state", "aria-current", "data-active"] });
32
+ return () => {
33
+ resize.disconnect();
34
+ changes.disconnect();
35
+ };
36
+ }, [rest]);
37
+ const handlers = follow ? {
38
+ onPointerOver: (e) => place(e.target.closest(item)),
39
+ onPointerLeave: rest,
40
+ onFocus: (e) => place(e.target.closest(item)),
41
+ onBlur: rest
42
+ } : {};
43
+ return { ref, handlers };
44
+ }
45
+
46
+ export {
47
+ useSlidingIndicator
48
+ };
49
+ //# sourceMappingURL=chunk-VDR2EP6K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sliding-indicator.ts"],"sourcesContent":["// The shared sliding indicator (NavBar, Tabs): one element that glides from item to item instead of each item lighting\n// up on its own. It writes the target's box as CSS variables on the list (`--kz-ind-x/y/w/h`) and `data-indicator=\"on\"`\n// — no re-render, no animation frame: the glide is a CSS transition (none under reduced motion). Before hydration the\n// items keep their own active style, so nothing flashes.\nimport * as React from \"react\";\n\nconst useIsoLayoutEffect = typeof window === \"undefined\" ? React.useEffect : React.useLayoutEffect;\n\nexport function useSlidingIndicator<T extends HTMLElement>({ item, active, follow = false }: { item: string; active: string; follow?: boolean }) {\n const ref = React.useRef<T>(null);\n const place = React.useCallback((target: Element | null) => {\n const list = ref.current;\n if (!list) return;\n if (!(target instanceof HTMLElement) || !list.contains(target)) {\n list.removeAttribute(\"data-indicator\");\n return;\n }\n const a = target.getBoundingClientRect();\n const b = list.getBoundingClientRect();\n list.style.setProperty(\"--kz-ind-x\", `${a.left - b.left + list.scrollLeft}px`);\n list.style.setProperty(\"--kz-ind-y\", `${a.top - b.top + list.scrollTop}px`);\n list.style.setProperty(\"--kz-ind-w\", `${a.width}px`);\n list.style.setProperty(\"--kz-ind-h\", `${a.height}px`);\n list.setAttribute(\"data-indicator\", \"on\");\n }, []);\n const rest = React.useCallback(() => place(ref.current?.querySelector(active) ?? null), [place, active]);\n\n useIsoLayoutEffect(() => {\n const list = ref.current;\n if (!list) return;\n rest();\n const resize = new ResizeObserver(rest);\n resize.observe(list);\n const changes = new MutationObserver(rest);\n changes.observe(list, { subtree: true, attributes: true, attributeFilter: [\"data-state\", \"aria-current\", \"data-active\"] });\n return () => {\n resize.disconnect();\n changes.disconnect();\n };\n }, [rest]);\n\n const handlers = follow\n ? {\n onPointerOver: (e: React.PointerEvent) => place((e.target as Element).closest(item)),\n onPointerLeave: rest,\n onFocus: (e: React.FocusEvent) => place((e.target as Element).closest(item)),\n onBlur: rest,\n }\n : {};\n return { ref, handlers };\n}\n"],"mappings":";;;AAIA,YAAY,WAAW;AAEvB,IAAM,qBAAqB,OAAO,WAAW,cAAoB,kBAAkB;AAE5E,SAAS,oBAA2C,EAAE,MAAM,QAAQ,SAAS,MAAM,GAAuD;AAC/I,QAAM,MAAY,aAAU,IAAI;AAChC,QAAM,QAAc,kBAAY,CAAC,WAA2B;AAC1D,UAAM,OAAO,IAAI;AACjB,QAAI,CAAC,KAAM;AACX,QAAI,EAAE,kBAAkB,gBAAgB,CAAC,KAAK,SAAS,MAAM,GAAG;AAC9D,WAAK,gBAAgB,gBAAgB;AACrC;AAAA,IACF;AACA,UAAM,IAAI,OAAO,sBAAsB;AACvC,UAAM,IAAI,KAAK,sBAAsB;AACrC,SAAK,MAAM,YAAY,cAAc,GAAG,EAAE,OAAO,EAAE,OAAO,KAAK,UAAU,IAAI;AAC7E,SAAK,MAAM,YAAY,cAAc,GAAG,EAAE,MAAM,EAAE,MAAM,KAAK,SAAS,IAAI;AAC1E,SAAK,MAAM,YAAY,cAAc,GAAG,EAAE,KAAK,IAAI;AACnD,SAAK,MAAM,YAAY,cAAc,GAAG,EAAE,MAAM,IAAI;AACpD,SAAK,aAAa,kBAAkB,IAAI;AAAA,EAC1C,GAAG,CAAC,CAAC;AACL,QAAM,OAAa,kBAAY,MAAM,MAAM,IAAI,SAAS,cAAc,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,MAAM,CAAC;AAEvG,qBAAmB,MAAM;AACvB,UAAM,OAAO,IAAI;AACjB,QAAI,CAAC,KAAM;AACX,SAAK;AACL,UAAM,SAAS,IAAI,eAAe,IAAI;AACtC,WAAO,QAAQ,IAAI;AACnB,UAAM,UAAU,IAAI,iBAAiB,IAAI;AACzC,YAAQ,QAAQ,MAAM,EAAE,SAAS,MAAM,YAAY,MAAM,iBAAiB,CAAC,cAAc,gBAAgB,aAAa,EAAE,CAAC;AACzH,WAAO,MAAM;AACX,aAAO,WAAW;AAClB,cAAQ,WAAW;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,WAAW,SACb;AAAA,IACE,eAAe,CAAC,MAA0B,MAAO,EAAE,OAAmB,QAAQ,IAAI,CAAC;AAAA,IACnF,gBAAgB;AAAA,IAChB,SAAS,CAAC,MAAwB,MAAO,EAAE,OAAmB,QAAQ,IAAI,CAAC;AAAA,IAC3E,QAAQ;AAAA,EACV,IACA,CAAC;AACL,SAAO,EAAE,KAAK,SAAS;AACzB;","names":[]}
@@ -0,0 +1,33 @@
1
+ "use client";
2
+
3
+ // src/spinner/glyph.tsx
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ var HEX = "M12 3 19.79 7.5 19.79 16.5 12 21 4.21 16.5 4.21 7.5Z";
6
+ function LoaderGlyph({ state = "loading", value, ...props }) {
7
+ const known = typeof value === "number" && Number.isFinite(value);
8
+ const fill = state !== "loading" ? 100 : known ? Math.round(Math.min(1, Math.max(0, value)) * 100) : null;
9
+ return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, "data-state": state, "data-progress": fill === null ? void 0 : fill, ...props, children: [
10
+ /* @__PURE__ */ jsx("path", { d: HEX, stroke: "currentColor", strokeOpacity: "0.22", strokeWidth: "2.2", strokeLinejoin: "round" }),
11
+ /* @__PURE__ */ jsx(
12
+ "path",
13
+ {
14
+ d: HEX,
15
+ pathLength: 100,
16
+ stroke: "currentColor",
17
+ strokeWidth: "2.2",
18
+ strokeLinejoin: "round",
19
+ strokeLinecap: "round",
20
+ className: "kz-loader-trace",
21
+ strokeDasharray: fill === null ? void 0 : `${fill} ${100 - fill}`
22
+ }
23
+ ),
24
+ state === "loading" && /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "2.6", fill: "currentColor", className: "kz-loader-node" }),
25
+ state === "success" && /* @__PURE__ */ jsx("path", { d: "M8.3 12.3l2.6 2.6 4.9-5.3", pathLength: 20, stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", className: "kz-loader-mark" }),
26
+ state === "error" && /* @__PURE__ */ jsx("path", { d: "M9.4 9.4l5.2 5.2M14.6 9.4l-5.2 5.2", pathLength: 20, stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", className: "kz-loader-mark" })
27
+ ] });
28
+ }
29
+
30
+ export {
31
+ LoaderGlyph
32
+ };
33
+ //# sourceMappingURL=chunk-WEVYKZIF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spinner/glyph.tsx"],"sourcesContent":["// The Krizaka loader glyph, server-safe: a hexagon (the marks' shape) traced by a segment of light around a node that\n// breathes; determinate, it fills to its value; done, the trace closes and a check (or a cross) draws itself. Animated by\n// motion.css (`kz-loader-*`); still under prefers-reduced-motion — a segment at rest and the node lit, never blank.\nimport type * as React from \"react\";\n\n/** The hexagon, pointy top, radius 9 around (12, 12). */\nconst HEX = \"M12 3 19.79 7.5 19.79 16.5 12 21 4.21 16.5 4.21 7.5Z\";\n\n/** What the glyph shows: a wait (with an optional value), or how it ended. */\nexport type LoaderGlyphState = \"loading\" | \"success\" | \"error\";\n\nexport interface LoaderGlyphProps extends Omit<React.ComponentProps<\"svg\">, \"children\"> {\n /** loading · success · error. */\n state?: LoaderGlyphState;\n /** Between 0 and 1: a determinate wait, the trace grows to it. Absent: indeterminate. */\n value?: number | null;\n}\n\n/** The glyph alone (decorative): the Spinner, the Loader and the Button's `loading` draw it. */\nexport function LoaderGlyph({ state = \"loading\", value, ...props }: LoaderGlyphProps) {\n const known = typeof value === \"number\" && Number.isFinite(value);\n const fill = state !== \"loading\" ? 100 : known ? Math.round(Math.min(1, Math.max(0, value)) * 100) : null;\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden data-state={state} data-progress={fill === null ? undefined : fill} {...props}>\n <path d={HEX} stroke=\"currentColor\" strokeOpacity=\"0.22\" strokeWidth=\"2.2\" strokeLinejoin=\"round\" />\n <path\n d={HEX}\n pathLength={100}\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n className=\"kz-loader-trace\"\n strokeDasharray={fill === null ? undefined : `${fill} ${100 - fill}`}\n />\n {state === \"loading\" && <circle cx=\"12\" cy=\"12\" r=\"2.6\" fill=\"currentColor\" className=\"kz-loader-node\" />}\n {state === \"success\" && <path d=\"M8.3 12.3l2.6 2.6 4.9-5.3\" pathLength={20} stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"kz-loader-mark\" />}\n {state === \"error\" && <path d=\"M9.4 9.4l5.2 5.2M14.6 9.4l-5.2 5.2\" pathLength={20} stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" className=\"kz-loader-mark\" />}\n </svg>\n );\n}\n"],"mappings":";;;AAuBI,SACE,KADF;AAjBJ,IAAM,MAAM;AAaL,SAAS,YAAY,EAAE,QAAQ,WAAW,OAAO,GAAG,MAAM,GAAqB;AACpF,QAAM,QAAQ,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAChE,QAAM,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI;AACrG,SACE,qBAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,eAAW,MAAC,cAAY,OAAO,iBAAe,SAAS,OAAO,SAAY,MAAO,GAAG,OACvH;AAAA,wBAAC,UAAK,GAAG,KAAK,QAAO,gBAAe,eAAc,QAAO,aAAY,OAAM,gBAAe,SAAQ;AAAA,IAClG;AAAA,MAAC;AAAA;AAAA,QACC,GAAG;AAAA,QACH,YAAY;AAAA,QACZ,QAAO;AAAA,QACP,aAAY;AAAA,QACZ,gBAAe;AAAA,QACf,eAAc;AAAA,QACd,WAAU;AAAA,QACV,iBAAiB,SAAS,OAAO,SAAY,GAAG,IAAI,IAAI,MAAM,IAAI;AAAA;AAAA,IACpE;AAAA,IACC,UAAU,aAAa,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe,WAAU,kBAAiB;AAAA,IACtG,UAAU,aAAa,oBAAC,UAAK,GAAE,6BAA4B,YAAY,IAAI,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,WAAU,kBAAiB;AAAA,IAC3L,UAAU,WAAW,oBAAC,UAAK,GAAE,sCAAqC,YAAY,IAAI,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,WAAU,kBAAiB;AAAA,KAC9K;AAEJ;","names":[]}
package/dist/command.d.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  import * as tailwind_variants from 'tailwind-variants';
2
2
  import { Command as Command$1 } from 'cmdk';
3
3
  import * as React from 'react';
4
- import { D as DialogContentProps } from './dialog-GQ4Nvuyf.js';
4
+ import { D as DialogContentProps } from './dialog-D42QwYb_.js';
5
5
  import 'radix-ui';
6
6
 
7
7
  declare const command: tailwind_variants.TVReturnType<{
8
8
  [key: string]: {
9
9
  [key: string]: tailwind_variants.ClassValue | {
10
- icon?: tailwind_variants.ClassValue;
11
- input?: tailwind_variants.ClassValue;
12
10
  loading?: tailwind_variants.ClassValue;
11
+ input?: tailwind_variants.ClassValue;
13
12
  group?: tailwind_variants.ClassValue;
14
13
  list?: tailwind_variants.ClassValue;
15
14
  separator?: tailwind_variants.ClassValue;
15
+ icon?: tailwind_variants.ClassValue;
16
16
  root?: tailwind_variants.ClassValue;
17
17
  inputWrap?: tailwind_variants.ClassValue;
18
18
  empty?: tailwind_variants.ClassValue;
@@ -23,12 +23,12 @@ declare const command: tailwind_variants.TVReturnType<{
23
23
  } | {
24
24
  [x: string]: {
25
25
  [x: string]: tailwind_variants.ClassValue | {
26
- icon?: tailwind_variants.ClassValue;
27
- input?: tailwind_variants.ClassValue;
28
26
  loading?: tailwind_variants.ClassValue;
27
+ input?: tailwind_variants.ClassValue;
29
28
  group?: tailwind_variants.ClassValue;
30
29
  list?: tailwind_variants.ClassValue;
31
30
  separator?: tailwind_variants.ClassValue;
31
+ icon?: tailwind_variants.ClassValue;
32
32
  root?: tailwind_variants.ClassValue;
33
33
  inputWrap?: tailwind_variants.ClassValue;
34
34
  empty?: tailwind_variants.ClassValue;
@@ -51,12 +51,12 @@ declare const command: tailwind_variants.TVReturnType<{
51
51
  }, undefined, {
52
52
  [key: string]: {
53
53
  [key: string]: tailwind_variants.ClassValue | {
54
- icon?: tailwind_variants.ClassValue;
55
- input?: tailwind_variants.ClassValue;
56
54
  loading?: tailwind_variants.ClassValue;
55
+ input?: tailwind_variants.ClassValue;
57
56
  group?: tailwind_variants.ClassValue;
58
57
  list?: tailwind_variants.ClassValue;
59
58
  separator?: tailwind_variants.ClassValue;
59
+ icon?: tailwind_variants.ClassValue;
60
60
  root?: tailwind_variants.ClassValue;
61
61
  inputWrap?: tailwind_variants.ClassValue;
62
62
  empty?: tailwind_variants.ClassValue;
package/dist/command.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
  import {
3
3
  DialogContent
4
- } from "./chunk-FHYZSO2S.js";
5
- import "./chunk-PESA2R4U.js";
4
+ } from "./chunk-R6SDS7JM.js";
5
+ import "./chunk-RUPNPMP3.js";
6
+ import "./chunk-WEVYKZIF.js";
6
7
  import {
7
8
  cn
8
9
  } from "./chunk-5AXLA4LK.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/command/command.tsx"],"sourcesContent":["// Client. A command palette on cmdk: the combobox / listbox roles, the active option (aria-activedescendant), the\n// arrows, Home / End, Enter, and the filtering (turn it off with `shouldFilter={false}` when the server searches).\n// `CommandDialog` puts it in the platform's Dialog. Words arrive as props.\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { Dialog as DialogPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { DialogContent, type DialogContentProps } from \"../dialog/dialog\";\n\nexport const command = tv({\n slots: {\n root: \"flex h-full w-full flex-col overflow-hidden bg-surface-1 text-fg\",\n inputWrap: \"flex items-center gap-3 border-b border-border-default px-4\",\n icon: \"h-5 w-5 shrink-0 text-fg-secondary\",\n input:\n \"h-13 w-full min-w-0 flex-1 bg-transparent text-sm text-fg outline-hidden placeholder:text-fg-muted disabled:cursor-not-allowed disabled:opacity-50 sm:text-base\",\n list: \"max-h-[min(60dvh,26rem)] scroll-py-2 overflow-y-auto overscroll-contain p-2 [&:not(:has([cmdk-item]))]:p-0\",\n empty: \"px-3 py-8 text-center text-sm text-fg-secondary\",\n loading: \"px-3 py-6 text-center text-sm text-fg-secondary\",\n group:\n \"[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:pb-1.5 [&_[cmdk-group-heading]]:pt-3 [&_[cmdk-group-heading]]:text-xs \" +\n \"[&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wider [&_[cmdk-group-heading]]:text-fg-secondary\",\n item:\n \"relative flex cursor-pointer select-none items-center gap-3 rounded-lg px-3 py-2.5 text-sm text-fg outline-hidden transition-colors \" +\n \"before:absolute before:inset-y-2 before:left-0 before:w-0.5 before:rounded-full before:bg-transparent \" +\n \"data-[selected=true]:bg-surface-2 data-[selected=true]:before:bg-accent data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-40\",\n separator: \"-mx-2 my-1 h-px bg-border-subtle\",\n shortcut: \"ml-auto text-xs tracking-widest text-fg-secondary\",\n },\n});\nconst s = command();\n\nfunction SearchIcon({ className }: { className?: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <path d=\"m20 20-3.5-3.5\" />\n </svg>\n );\n}\n\nexport type CommandRootProps = React.ComponentProps<typeof CommandPrimitive> & {\n /** The accessible name of the palette — passed translated (\"Search\", \"Commands\"). */\n label: string;\n};\n\n/** The palette: `value` / `onValueChange` (the active item), `shouldFilter`, `filter`, `loop`. */\nexport function CommandRoot({ className, ...props }: CommandRootProps) {\n return <CommandPrimitive className={s.root({ className })} {...props} />;\n}\n\nexport type CommandInputProps = Omit<React.ComponentProps<typeof CommandPrimitive.Input>, \"placeholder\"> & {\n /** What to type — passed translated. The input is named by the palette's `label`. */\n placeholder: string;\n /** After the input, inside the bar: a spinner, a clear button. */\n trailing?: React.ReactNode;\n};\n\n/** The search field (`value` / `onValueChange` for the query), with a magnifier. */\nexport function CommandInput({ className, placeholder, trailing, ...props }: CommandInputProps) {\n return (\n <div className={s.inputWrap()} cmdk-input-wrapper=\"\">\n <SearchIcon className={s.icon()} />\n <CommandPrimitive.Input placeholder={placeholder} className={s.input({ className })} {...props} />\n {trailing}\n </div>\n );\n}\n\n// Set inside `Command.List`: a listbox may only hold options and groups (axe `aria-required-children`), so the empty\n// message must live beside it, not in it.\nconst InsideList = React.createContext(false);\n\nexport type CommandListProps = React.ComponentProps<typeof CommandPrimitive.List> & {\n /** The accessible name of the list of results — passed translated (\"Suggestions\", \"Results\"). */\n label: string;\n /**\n * Shown when nothing matches — passed translated. Rendered after the listbox, never inside it: an empty listbox is\n * valid, a listbox holding text is not.\n */\n emptyLabel?: React.ReactNode;\n};\n\nexport function CommandList({ className, emptyLabel, children, ...props }: CommandListProps) {\n return (\n <>\n <CommandPrimitive.List className={s.list({ className })} {...props}>\n <InsideList.Provider value>{children}</InsideList.Provider>\n </CommandPrimitive.List>\n {emptyLabel === undefined ? null : <CommandEmpty emptyLabel={emptyLabel} />}\n </>\n );\n}\n\nexport type CommandEmptyProps = Omit<React.ComponentProps<typeof CommandPrimitive.Empty>, \"children\"> & {\n /** Shown when nothing matches — passed translated. */\n emptyLabel: React.ReactNode;\n};\n\n/**\n * Shown by cmdk only when no item matches. Place it beside `Command.List` (or pass `emptyLabel` to the list), never\n * inside it: inside, it is rendered as before but warns in development — the listbox then holds text, which axe\n * refuses (`aria-required-children`).\n */\nexport function CommandEmpty({ className, emptyLabel, ...props }: CommandEmptyProps) {\n const inside = React.useContext(InsideList);\n React.useEffect(() => {\n if (inside && typeof process !== \"undefined\" && process.env.NODE_ENV !== \"production\") {\n console.warn(\"@krizaka/ui/command: <Command.Empty> inside <Command.List> breaks the listbox (axe aria-required-children). Pass `emptyLabel` to <Command.List> instead.\");\n }\n }, [inside]);\n return (\n <CommandPrimitive.Empty className={s.empty({ className })} {...props}>\n {emptyLabel}\n </CommandPrimitive.Empty>\n );\n}\n\n/** While results load (`label` is announced). */\nexport function CommandLoading({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Loading>) {\n return <CommandPrimitive.Loading className={s.loading({ className })} {...props} />;\n}\n\n/** A group of items under a `heading`. */\nexport function CommandGroup({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Group>) {\n return <CommandPrimitive.Group className={s.group({ className })} {...props} />;\n}\n\n/** An option: `onSelect` on Enter or click, `value` and `keywords` for the filter, `disabled`. */\nexport function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {\n return <CommandPrimitive.Item className={s.item({ className })} {...props} />;\n}\n\n/** A line between groups. Decorative (`role=\"none\"`): cmdk's own separator is a role a listbox may not hold (axe). */\nexport function CommandSeparator({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div role=\"none\" className={s.separator({ className })} {...props} />;\n}\n\n/** A keyboard hint at the end of an item. */\nexport function CommandShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return <span className={s.shortcut({ className })} {...props} />;\n}\n\n/** `Command.Root/Input/List/Empty/Loading/Group/Item/Separator/Shortcut`. */\nexport const Command = {\n Root: CommandRoot,\n Input: CommandInput,\n List: CommandList,\n Empty: CommandEmpty,\n Loading: CommandLoading,\n Group: CommandGroup,\n Item: CommandItem,\n Separator: CommandSeparator,\n Shortcut: CommandShortcut,\n};\n\nexport type CommandDialogProps = Omit<CommandRootProps, \"title\"> & {\n /** Open or closed (controlled), with `onOpenChange`. */\n open?: boolean;\n /** Open at first, uncontrolled. */\n defaultOpen?: boolean;\n /** Called when it opens or closes (Escape, a click outside, a shortcut of the product). */\n onOpenChange?: (open: boolean) => void;\n /** Under the palette, inside the dialog: shortcuts, a \"see all results\" link. */\n footer?: React.ReactNode;\n /** Passed to `Dialog.Content`: `size`, `container`, `className` of the dialog. */\n contentProps?: Omit<Extract<DialogContentProps, { hideClose: true }>, \"hideClose\" | \"children\" | \"placement\">;\n};\n\n/**\n * The palette in a dialog (Radix: focus trap, Escape, focus return). The dialog is named by `label`; it has no close\n * button — Escape and a click outside close it — and the input takes the focus when it opens.\n */\nexport function CommandDialog({ open, defaultOpen, onOpenChange, footer, contentProps, label, className, children, ...props }: CommandDialogProps) {\n const { className: contentClassName, ...content } = contentProps ?? {};\n return (\n <DialogPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <DialogContent\n hideClose\n size=\"lg\"\n aria-describedby={undefined}\n className={cn(\"top-[12dvh] translate-y-0 sm:top-[14dvh]\", contentClassName)}\n {...content}\n >\n <DialogPrimitive.Title className=\"sr-only\">{label}</DialogPrimitive.Title>\n <CommandRoot label={label} className={className} {...props}>\n {children}\n </CommandRoot>\n {footer}\n </DialogContent>\n </DialogPrimitive.Root>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/command/command.tsx"],"sourcesContent":["// Client. A command palette on cmdk: the combobox / listbox roles, the active option (aria-activedescendant), the\n// arrows, Home / End, Enter, and the filtering (turn it off with `shouldFilter={false}` when the server searches).\n// `CommandDialog` puts it in the platform's Dialog. Words arrive as props.\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { Dialog as DialogPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { DialogContent, type DialogContentProps } from \"../dialog/dialog\";\n\nexport const command = tv({\n slots: {\n root: \"flex h-full w-full flex-col overflow-hidden bg-surface-1 text-fg\",\n inputWrap: \"flex items-center gap-3 border-b border-border-default px-4\",\n icon: \"h-5 w-5 shrink-0 text-fg-secondary\",\n input:\n \"h-13 w-full min-w-0 flex-1 bg-transparent text-sm text-fg outline-hidden placeholder:text-fg-muted disabled:cursor-not-allowed disabled:opacity-50 sm:text-base\",\n list: \"max-h-[min(60dvh,26rem)] scroll-py-2 overflow-y-auto overscroll-contain p-2 [&:not(:has([cmdk-item]))]:p-0\",\n empty: \"px-3 py-8 text-center text-sm text-fg-secondary\",\n loading: \"px-3 py-6 text-center text-sm text-fg-secondary\",\n group:\n \"[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:pb-1.5 [&_[cmdk-group-heading]]:pt-3 [&_[cmdk-group-heading]]:text-xs \" +\n \"[&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wider [&_[cmdk-group-heading]]:text-fg-secondary\",\n item:\n \"relative flex cursor-pointer select-none items-center gap-3 rounded-lg px-3 py-2.5 text-sm text-fg outline-hidden transition-colors \" +\n \"before:absolute before:inset-y-2 before:left-0 before:w-0.5 before:rounded-full before:bg-transparent \" +\n \"data-[selected=true]:bg-surface-2 data-[selected=true]:before:bg-accent data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-40\",\n separator: \"-mx-2 my-1 h-px bg-border-subtle\",\n shortcut: \"ml-auto text-xs tracking-widest text-fg-secondary\",\n },\n});\nconst s = command();\n\nfunction SearchIcon({ className }: { className?: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <path d=\"m20 20-3.5-3.5\" />\n </svg>\n );\n}\n\nexport type CommandRootProps = React.ComponentProps<typeof CommandPrimitive> & {\n /** The accessible name of the palette — passed translated (\"Search\", \"Commands\"). */\n label: string;\n};\n\n/** The palette: `value` / `onValueChange` (the active item), `shouldFilter`, `filter`, `loop`. */\nexport function CommandRoot({ className, ...props }: CommandRootProps) {\n return <CommandPrimitive className={s.root({ className })} {...props} />;\n}\n\nexport type CommandInputProps = Omit<React.ComponentProps<typeof CommandPrimitive.Input>, \"placeholder\"> & {\n /** What to type — passed translated. The input is named by the palette's `label`. */\n placeholder: string;\n /** After the input, inside the bar: a spinner, a clear button. */\n trailing?: React.ReactNode;\n};\n\n/** The search field (`value` / `onValueChange` for the query), with a magnifier. */\nexport function CommandInput({ className, placeholder, trailing, ...props }: CommandInputProps) {\n return (\n <div className={s.inputWrap()} cmdk-input-wrapper=\"\">\n <SearchIcon className={s.icon()} />\n <CommandPrimitive.Input placeholder={placeholder} className={s.input({ className })} {...props} />\n {trailing}\n </div>\n );\n}\n\n// Set inside `Command.List`: a listbox may only hold options and groups (axe `aria-required-children`), so the empty\n// message must live beside it, not in it.\nconst InsideList = React.createContext(false);\n\nexport type CommandListProps = React.ComponentProps<typeof CommandPrimitive.List> & {\n /** The accessible name of the list of results — passed translated (\"Suggestions\", \"Results\"). */\n label: string;\n /**\n * Shown when nothing matches — passed translated. Rendered after the listbox, never inside it: an empty listbox is\n * valid, a listbox holding text is not.\n */\n emptyLabel?: React.ReactNode;\n};\n\nexport function CommandList({ className, emptyLabel, children, ...props }: CommandListProps) {\n return (\n <>\n <CommandPrimitive.List className={s.list({ className })} {...props}>\n <InsideList.Provider value>{children}</InsideList.Provider>\n </CommandPrimitive.List>\n {emptyLabel === undefined ? null : <CommandEmpty emptyLabel={emptyLabel} />}\n </>\n );\n}\n\nexport type CommandEmptyProps = Omit<React.ComponentProps<typeof CommandPrimitive.Empty>, \"children\"> & {\n /** Shown when nothing matches — passed translated. */\n emptyLabel: React.ReactNode;\n};\n\n/**\n * Shown by cmdk only when no item matches. Place it beside `Command.List` (or pass `emptyLabel` to the list), never\n * inside it: inside, it is rendered as before but warns in development — the listbox then holds text, which axe\n * refuses (`aria-required-children`).\n */\nexport function CommandEmpty({ className, emptyLabel, ...props }: CommandEmptyProps) {\n const inside = React.useContext(InsideList);\n React.useEffect(() => {\n if (inside && typeof process !== \"undefined\" && process.env.NODE_ENV !== \"production\") {\n console.warn(\"@krizaka/ui/command: <Command.Empty> inside <Command.List> breaks the listbox (axe aria-required-children). Pass `emptyLabel` to <Command.List> instead.\");\n }\n }, [inside]);\n return (\n <CommandPrimitive.Empty className={s.empty({ className })} {...props}>\n {emptyLabel}\n </CommandPrimitive.Empty>\n );\n}\n\n/** While results load (`label` is announced). */\nexport function CommandLoading({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Loading>) {\n return <CommandPrimitive.Loading className={s.loading({ className })} {...props} />;\n}\n\n/** A group of items under a `heading`. */\nexport function CommandGroup({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Group>) {\n return <CommandPrimitive.Group className={s.group({ className })} {...props} />;\n}\n\n/** An option: `onSelect` on Enter or click, `value` and `keywords` for the filter, `disabled`. */\nexport function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {\n return <CommandPrimitive.Item className={s.item({ className })} {...props} />;\n}\n\n/** A line between groups. Decorative (`role=\"none\"`): cmdk's own separator is a role a listbox may not hold (axe). */\nexport function CommandSeparator({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div role=\"none\" className={s.separator({ className })} {...props} />;\n}\n\n/** A keyboard hint at the end of an item. */\nexport function CommandShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return <span className={s.shortcut({ className })} {...props} />;\n}\n\n/** `Command.Root/Input/List/Empty/Loading/Group/Item/Separator/Shortcut`. */\nexport const Command = {\n Root: CommandRoot,\n Input: CommandInput,\n List: CommandList,\n Empty: CommandEmpty,\n Loading: CommandLoading,\n Group: CommandGroup,\n Item: CommandItem,\n Separator: CommandSeparator,\n Shortcut: CommandShortcut,\n};\n\nexport type CommandDialogProps = Omit<CommandRootProps, \"title\"> & {\n /** Open or closed (controlled), with `onOpenChange`. */\n open?: boolean;\n /** Open at first, uncontrolled. */\n defaultOpen?: boolean;\n /** Called when it opens or closes (Escape, a click outside, a shortcut of the product). */\n onOpenChange?: (open: boolean) => void;\n /** Under the palette, inside the dialog: shortcuts, a \"see all results\" link. */\n footer?: React.ReactNode;\n /** Passed to `Dialog.Content`: `size`, `container`, `className` of the dialog. */\n contentProps?: Omit<Extract<DialogContentProps, { hideClose: true }>, \"hideClose\" | \"children\" | \"placement\">;\n};\n\n/**\n * The palette in a dialog (Radix: focus trap, Escape, focus return). The dialog is named by `label`; it has no close\n * button — Escape and a click outside close it — and the input takes the focus when it opens.\n */\nexport function CommandDialog({ open, defaultOpen, onOpenChange, footer, contentProps, label, className, children, ...props }: CommandDialogProps) {\n const { className: contentClassName, ...content } = contentProps ?? {};\n return (\n <DialogPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <DialogContent\n hideClose\n size=\"lg\"\n aria-describedby={undefined}\n className={cn(\"top-[12dvh] translate-y-0 sm:top-[14dvh]\", contentClassName)}\n {...content}\n >\n <DialogPrimitive.Title className=\"sr-only\">{label}</DialogPrimitive.Title>\n <CommandRoot label={label} className={className} {...props}>\n {children}\n </CommandRoot>\n {footer}\n </DialogContent>\n </DialogPrimitive.Root>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { B as ButtonProps } from './button-Cgfkg_3y.js';
2
+ import { B as ButtonProps } from './button-BMAO7dKF.js';
3
3
  import 'tailwind-variants';
4
4
 
5
5
  declare const confirmArmed = "border border-danger bg-danger/20 text-fg hover:border-danger hover:bg-danger/30";
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import {
3
3
  Button
4
- } from "./chunk-PESA2R4U.js";
4
+ } from "./chunk-RUPNPMP3.js";
5
+ import "./chunk-WEVYKZIF.js";
5
6
  import {
6
7
  cn
7
8
  } from "./chunk-5AXLA4LK.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/confirm-button/confirm-button.tsx"],"sourcesContent":["// Client (a state). A destructive action confirmed by a second press, never `window.confirm`: the first press arms it\n// and says what will happen (`confirmLabel`, announced politely), the second runs `onConfirm`. It disarms by itself\n// after `timeoutMs`, on Escape, and when the focus leaves. The danger is the border and the tint; the words stay a\n// text role (contrast AA in both themes).\nimport { VisuallyHidden } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { Button, type ButtonProps } from \"../button/button\";\nimport { cn } from \"../cn\";\n\nexport const confirmArmed = \"border border-danger bg-danger/20 text-fg hover:border-danger hover:bg-danger/30\";\n\nexport type ConfirmButtonProps = Omit<ButtonProps, \"onClick\" | \"asChild\"> & {\n /** What the second press does, in words — shown and announced once armed (\"Delete for good?\"). Passed translated. */\n confirmLabel: string;\n /** The accessible name while idle, for an icon-only button (the confirm label names it once armed). */\n label?: string;\n /** Runs on the second press. */\n onConfirm: () => void;\n /** Disarms after this many milliseconds (4000 by default). */\n timeoutMs?: number;\n /** What it shows once armed (default: its children, then `confirmLabel`). */\n armedContent?: React.ReactNode;\n /** Notified when it arms and disarms. */\n onArmedChange?: (armed: boolean) => void;\n};\n\n/** A two-step button: press to arm, press again within `timeoutMs` to confirm. State: `data-armed`. */\nexport function ConfirmButton({\n confirmLabel,\n label,\n onConfirm,\n timeoutMs = 4000,\n onArmedChange,\n armedContent,\n variant = \"ghost\",\n className,\n children,\n onBlur,\n onKeyDown,\n ...props\n}: ConfirmButtonProps) {\n const [armed, setArmedState] = React.useState(false);\n const armedRef = React.useRef(false);\n const onArmedChangeRef = React.useRef(onArmedChange);\n React.useEffect(() => {\n onArmedChangeRef.current = onArmedChange;\n }, [onArmedChange]);\n const setArmed = React.useCallback((next: boolean) => {\n if (armedRef.current === next) return;\n armedRef.current = next;\n setArmedState(next);\n onArmedChangeRef.current?.(next);\n }, []);\n React.useEffect(() => {\n if (!armed) return;\n const timer = window.setTimeout(() => setArmed(false), timeoutMs);\n return () => window.clearTimeout(timer);\n }, [armed, timeoutMs, setArmed]);\n const name = armed ? confirmLabel : label;\n return (\n <>\n <Button\n variant={variant}\n aria-label={name}\n title={name}\n data-armed={armed ? \"\" : undefined}\n className={cn(armed && confirmArmed, className)}\n onClick={() => {\n if (!armed) return setArmed(true);\n setArmed(false);\n onConfirm();\n }}\n onBlur={(event) => {\n onBlur?.(event);\n setArmed(false);\n }}\n onKeyDown={(event) => {\n onKeyDown?.(event);\n if (armed && event.key === \"Escape\") {\n event.stopPropagation();\n setArmed(false);\n }\n }}\n {...props}\n >\n {armed\n ? (armedContent ?? (\n <>\n {children}\n <span>{confirmLabel}</span>\n </>\n ))\n : children}\n </Button>\n <VisuallyHidden.Root aria-live=\"polite\">{armed ? confirmLabel : \"\"}</VisuallyHidden.Root>\n </>\n );\n}\n"],"mappings":";;;;;;;;;AAIA,SAAS,sBAAsB;AAC/B,YAAY,WAAW;AAmFT,mBAEE,KAFF;AA9EP,IAAM,eAAe;AAkBrB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,QAAM,CAAC,OAAO,aAAa,IAAU,eAAS,KAAK;AACnD,QAAM,WAAiB,aAAO,KAAK;AACnC,QAAM,mBAAyB,aAAO,aAAa;AACnD,EAAM,gBAAU,MAAM;AACpB,qBAAiB,UAAU;AAAA,EAC7B,GAAG,CAAC,aAAa,CAAC;AAClB,QAAM,WAAiB,kBAAY,CAAC,SAAkB;AACpD,QAAI,SAAS,YAAY,KAAM;AAC/B,aAAS,UAAU;AACnB,kBAAc,IAAI;AAClB,qBAAiB,UAAU,IAAI;AAAA,EACjC,GAAG,CAAC,CAAC;AACL,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ,OAAO,WAAW,MAAM,SAAS,KAAK,GAAG,SAAS;AAChE,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,OAAO,WAAW,QAAQ,CAAC;AAC/B,QAAM,OAAO,QAAQ,eAAe;AACpC,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,cAAY;AAAA,QACZ,OAAO;AAAA,QACP,cAAY,QAAQ,KAAK;AAAA,QACzB,WAAW,GAAG,SAAS,cAAc,SAAS;AAAA,QAC9C,SAAS,MAAM;AACb,cAAI,CAAC,MAAO,QAAO,SAAS,IAAI;AAChC,mBAAS,KAAK;AACd,oBAAU;AAAA,QACZ;AAAA,QACA,QAAQ,CAAC,UAAU;AACjB,mBAAS,KAAK;AACd,mBAAS,KAAK;AAAA,QAChB;AAAA,QACA,WAAW,CAAC,UAAU;AACpB,sBAAY,KAAK;AACjB,cAAI,SAAS,MAAM,QAAQ,UAAU;AACnC,kBAAM,gBAAgB;AACtB,qBAAS,KAAK;AAAA,UAChB;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEH,kBACI,gBACC,iCACG;AAAA;AAAA,UACD,oBAAC,UAAM,wBAAa;AAAA,WACtB,IAEF;AAAA;AAAA,IACN;AAAA,IACA,oBAAC,eAAe,MAAf,EAAoB,aAAU,UAAU,kBAAQ,eAAe,IAAG;AAAA,KACrE;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/confirm-button/confirm-button.tsx"],"sourcesContent":["// Client (a state). A destructive action confirmed by a second press, never `window.confirm`: the first press arms it\n// and says what will happen (`confirmLabel`, announced politely), the second runs `onConfirm`. It disarms by itself\n// after `timeoutMs`, on Escape, and when the focus leaves. The danger is the border and the tint; the words stay a\n// text role (contrast AA in both themes).\nimport { VisuallyHidden } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { Button, type ButtonProps } from \"../button/button\";\nimport { cn } from \"../cn\";\n\nexport const confirmArmed = \"border border-danger bg-danger/20 text-fg hover:border-danger hover:bg-danger/30\";\n\nexport type ConfirmButtonProps = Omit<ButtonProps, \"onClick\" | \"asChild\"> & {\n /** What the second press does, in words — shown and announced once armed (\"Delete for good?\"). Passed translated. */\n confirmLabel: string;\n /** The accessible name while idle, for an icon-only button (the confirm label names it once armed). */\n label?: string;\n /** Runs on the second press. */\n onConfirm: () => void;\n /** Disarms after this many milliseconds (4000 by default). */\n timeoutMs?: number;\n /** What it shows once armed (default: its children, then `confirmLabel`). */\n armedContent?: React.ReactNode;\n /** Notified when it arms and disarms. */\n onArmedChange?: (armed: boolean) => void;\n};\n\n/** A two-step button: press to arm, press again within `timeoutMs` to confirm. State: `data-armed`. */\nexport function ConfirmButton({\n confirmLabel,\n label,\n onConfirm,\n timeoutMs = 4000,\n onArmedChange,\n armedContent,\n variant = \"ghost\",\n className,\n children,\n onBlur,\n onKeyDown,\n ...props\n}: ConfirmButtonProps) {\n const [armed, setArmedState] = React.useState(false);\n const armedRef = React.useRef(false);\n const onArmedChangeRef = React.useRef(onArmedChange);\n React.useEffect(() => {\n onArmedChangeRef.current = onArmedChange;\n }, [onArmedChange]);\n const setArmed = React.useCallback((next: boolean) => {\n if (armedRef.current === next) return;\n armedRef.current = next;\n setArmedState(next);\n onArmedChangeRef.current?.(next);\n }, []);\n React.useEffect(() => {\n if (!armed) return;\n const timer = window.setTimeout(() => setArmed(false), timeoutMs);\n return () => window.clearTimeout(timer);\n }, [armed, timeoutMs, setArmed]);\n const name = armed ? confirmLabel : label;\n return (\n <>\n <Button\n variant={variant}\n aria-label={name}\n title={name}\n data-armed={armed ? \"\" : undefined}\n className={cn(armed && confirmArmed, className)}\n onClick={() => {\n if (!armed) return setArmed(true);\n setArmed(false);\n onConfirm();\n }}\n onBlur={(event) => {\n onBlur?.(event);\n setArmed(false);\n }}\n onKeyDown={(event) => {\n onKeyDown?.(event);\n if (armed && event.key === \"Escape\") {\n event.stopPropagation();\n setArmed(false);\n }\n }}\n {...props}\n >\n {armed\n ? (armedContent ?? (\n <>\n {children}\n <span>{confirmLabel}</span>\n </>\n ))\n : children}\n </Button>\n <VisuallyHidden.Root aria-live=\"polite\">{armed ? confirmLabel : \"\"}</VisuallyHidden.Root>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;AAIA,SAAS,sBAAsB;AAC/B,YAAY,WAAW;AAmFT,mBAEE,KAFF;AA9EP,IAAM,eAAe;AAkBrB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,QAAM,CAAC,OAAO,aAAa,IAAU,eAAS,KAAK;AACnD,QAAM,WAAiB,aAAO,KAAK;AACnC,QAAM,mBAAyB,aAAO,aAAa;AACnD,EAAM,gBAAU,MAAM;AACpB,qBAAiB,UAAU;AAAA,EAC7B,GAAG,CAAC,aAAa,CAAC;AAClB,QAAM,WAAiB,kBAAY,CAAC,SAAkB;AACpD,QAAI,SAAS,YAAY,KAAM;AAC/B,aAAS,UAAU;AACnB,kBAAc,IAAI;AAClB,qBAAiB,UAAU,IAAI;AAAA,EACjC,GAAG,CAAC,CAAC;AACL,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ,OAAO,WAAW,MAAM,SAAS,KAAK,GAAG,SAAS;AAChE,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,OAAO,WAAW,QAAQ,CAAC;AAC/B,QAAM,OAAO,QAAQ,eAAe;AACpC,SACE,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,cAAY;AAAA,QACZ,OAAO;AAAA,QACP,cAAY,QAAQ,KAAK;AAAA,QACzB,WAAW,GAAG,SAAS,cAAc,SAAS;AAAA,QAC9C,SAAS,MAAM;AACb,cAAI,CAAC,MAAO,QAAO,SAAS,IAAI;AAChC,mBAAS,KAAK;AACd,oBAAU;AAAA,QACZ;AAAA,QACA,QAAQ,CAAC,UAAU;AACjB,mBAAS,KAAK;AACd,mBAAS,KAAK;AAAA,QAChB;AAAA,QACA,WAAW,CAAC,UAAU;AACpB,sBAAY,KAAK;AACjB,cAAI,SAAS,MAAM,QAAQ,UAAU;AACnC,kBAAM,gBAAgB;AACtB,qBAAS,KAAK;AAAA,UAChB;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEH,kBACI,gBACC,iCACG;AAAA;AAAA,UACD,oBAAC,UAAM,wBAAa;AAAA,WACtB,IAEF;AAAA;AAAA,IACN;AAAA,IACA,oBAAC,eAAe,MAAf,EAAoB,aAAU,UAAU,kBAAQ,eAAe,IAAG;AAAA,KACrE;AAEJ;","names":[]}