@krizaka/ui 3.21.0 → 3.23.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 (494) hide show
  1. package/README.md +5 -0
  2. package/dist/achievement.js +1 -1
  3. package/dist/action-bar.js +4 -4
  4. package/dist/app-header.d.ts +79 -0
  5. package/dist/app-header.js +32 -0
  6. package/dist/app-header.js.map +1 -0
  7. package/dist/app-shell.d.ts +20 -2
  8. package/dist/app-shell.js +35 -20
  9. package/dist/app-shell.js.map +1 -1
  10. package/dist/argument-card.d.ts +4 -1
  11. package/dist/argument-card.js +8 -5
  12. package/dist/argument-card.js.map +1 -1
  13. package/dist/audio-player.d.ts +3 -2
  14. package/dist/audio-player.js +14 -10
  15. package/dist/audio-player.js.map +1 -1
  16. package/dist/blocks.css +28 -0
  17. package/dist/button.js +2 -1
  18. package/dist/captcha.d.ts +81 -0
  19. package/dist/captcha.js +162 -0
  20. package/dist/captcha.js.map +1 -0
  21. package/dist/card-grid.d.ts +10 -1
  22. package/dist/card-grid.js +3 -2
  23. package/dist/card-grid.js.map +1 -1
  24. package/dist/card.js +3 -3
  25. package/dist/changelog-page.d.ts +57 -3
  26. package/dist/changelog-page.js +117 -1
  27. package/dist/changelog-page.js.map +1 -1
  28. package/dist/choice-grid.js +1 -1
  29. package/dist/{chunk-5MH64NIL.js → chunk-2L67YTNV.js} +2 -2
  30. package/dist/{chunk-3IN6TOPM.js → chunk-6ZYRUOTA.js} +6 -3
  31. package/dist/chunk-6ZYRUOTA.js.map +1 -0
  32. package/dist/chunk-APNIVNIX.js +54 -0
  33. package/dist/chunk-APNIVNIX.js.map +1 -0
  34. package/dist/{chunk-FKBHWS4N.js → chunk-CEJDH6SA.js} +2 -2
  35. package/dist/{chunk-OWC2LZD2.js → chunk-CHOJUCVE.js} +6 -3
  36. package/dist/chunk-CHOJUCVE.js.map +1 -0
  37. package/dist/{chunk-3BC4XQ6C.js → chunk-DZU6RMYD.js} +6 -3
  38. package/dist/chunk-DZU6RMYD.js.map +1 -0
  39. package/dist/chunk-F7FVPPBB.js +1080 -0
  40. package/dist/chunk-F7FVPPBB.js.map +1 -0
  41. package/dist/{chunk-5Z7FWCV2.js → chunk-HBZPJ3EP.js} +2 -2
  42. package/dist/{chunk-C2BRIFJG.js → chunk-HJFRHYCI.js} +2 -2
  43. package/dist/{chunk-ZNMFG62E.js → chunk-KH3JOEPY.js} +3 -2
  44. package/dist/chunk-KH3JOEPY.js.map +1 -0
  45. package/dist/{chunk-BTMFZ66D.js → chunk-KM6VAKIE.js} +2 -2
  46. package/dist/{chunk-DGQMDJXK.js → chunk-LZNZLCOE.js} +2 -2
  47. package/dist/chunk-MQPC3P4T.js +126 -0
  48. package/dist/chunk-MQPC3P4T.js.map +1 -0
  49. package/dist/{chunk-2FRWNSRO.js → chunk-NSLXEDIS.js} +3 -2
  50. package/dist/chunk-NSLXEDIS.js.map +1 -0
  51. package/dist/{chunk-3GODX3D6.js → chunk-QDXV544C.js} +2 -2
  52. package/dist/chunk-QDXV544C.js.map +1 -0
  53. package/dist/{chunk-4LOMIQVX.js → chunk-W675RFOA.js} +3 -2
  54. package/dist/chunk-W675RFOA.js.map +1 -0
  55. package/dist/{chunk-G3ETON2A.js → chunk-WU4VLSEA.js} +3 -2
  56. package/dist/chunk-WU4VLSEA.js.map +1 -0
  57. package/dist/{chunk-IZ7MV6HM.js → chunk-XVFQZ3ZG.js} +3 -2
  58. package/dist/chunk-XVFQZ3ZG.js.map +1 -0
  59. package/dist/{chunk-LIPK4UCS.js → chunk-YCIBJ6OQ.js} +140 -209
  60. package/dist/chunk-YCIBJ6OQ.js.map +1 -0
  61. package/dist/cn.js +1 -1
  62. package/dist/code-block.js +2 -2
  63. package/dist/code-block.js.map +1 -1
  64. package/dist/command.js +3 -3
  65. package/dist/comparison-table.d.ts +44 -0
  66. package/dist/comparison-table.js +84 -0
  67. package/dist/comparison-table.js.map +1 -0
  68. package/dist/confirm-button.js +2 -2
  69. package/dist/continue-prompt.js +3 -3
  70. package/dist/continue-prompt.js.map +1 -1
  71. package/dist/cta-panel.js +1 -1
  72. package/dist/data-table.js +19 -1066
  73. package/dist/data-table.js.map +1 -1
  74. package/dist/date-picker.js +4 -4
  75. package/dist/decision-list.js +1 -1
  76. package/dist/dialog.js +3 -2
  77. package/dist/dialog.js.map +1 -1
  78. package/dist/docs-nav.d.ts +36 -0
  79. package/dist/docs-nav.js +44 -0
  80. package/dist/docs-nav.js.map +1 -0
  81. package/dist/dropdown-menu.js +1 -1
  82. package/dist/error-page.js +1 -1
  83. package/dist/field.js +1 -1
  84. package/dist/filter-bar.js +2 -2
  85. package/dist/force-update-screen.js +2 -1
  86. package/dist/force-update-screen.js.map +1 -1
  87. package/dist/gallery-page.js +1 -1
  88. package/dist/genui.d.ts +221 -0
  89. package/dist/genui.js +533 -0
  90. package/dist/genui.js.map +1 -0
  91. package/dist/glow-card.js +1 -1
  92. package/dist/goal-gauge.js +1 -1
  93. package/dist/how-it-works-page.js +1 -1
  94. package/dist/image-cropper.js +3 -3
  95. package/dist/index.d.ts +17 -24
  96. package/dist/index.js +4 -4
  97. package/dist/landscape.js +1 -1
  98. package/dist/link-card.d.ts +9 -2
  99. package/dist/link-card.js +5 -44
  100. package/dist/link-card.js.map +1 -1
  101. package/dist/longform-page.js +1 -1
  102. package/dist/maintenance-screen.js +2 -1
  103. package/dist/maintenance-screen.js.map +1 -1
  104. package/dist/map.js +3 -3
  105. package/dist/map.js.map +1 -1
  106. package/dist/markdown.js +2 -1
  107. package/dist/markdown.js.map +1 -1
  108. package/dist/marketing-layout.js +1 -1
  109. package/dist/marketing-layout.js.map +1 -1
  110. package/dist/marquee.js +1 -1
  111. package/dist/mascot-quote.js +1 -1
  112. package/dist/match-dialog.js +2 -1
  113. package/dist/match-dialog.js.map +1 -1
  114. package/dist/media-grid.d.ts +26 -4
  115. package/dist/media-grid.js +122 -163
  116. package/dist/media-grid.js.map +1 -1
  117. package/dist/meta-row.d.ts +54 -0
  118. package/dist/meta-row.js +35 -0
  119. package/dist/meta-row.js.map +1 -0
  120. package/dist/native/map.js +3 -3
  121. package/dist/native/map.js.map +1 -1
  122. package/dist/native.d.ts +42 -16
  123. package/dist/native.js +591 -537
  124. package/dist/native.js.map +1 -1
  125. package/dist/nav-bar.js +3 -3
  126. package/dist/page-hero.js +5 -5
  127. package/dist/page.js +2 -2
  128. package/dist/popover.js +1 -1
  129. package/dist/pricing-page.js +1 -1
  130. package/dist/product-page.js +1 -1
  131. package/dist/profile-card.js +1 -1
  132. package/dist/promise-card.js +1 -1
  133. package/dist/radio-group.js +2 -2
  134. package/dist/rail-nav.d.ts +149 -0
  135. package/dist/rail-nav.js +177 -0
  136. package/dist/rail-nav.js.map +1 -0
  137. package/dist/scroll-stage.js +1 -1
  138. package/dist/settings-layout.d.ts +75 -62
  139. package/dist/settings-layout.js +39 -6
  140. package/dist/settings-layout.js.map +1 -1
  141. package/dist/showcase.js +1 -1
  142. package/dist/site-footer.d.ts +48 -67
  143. package/dist/site-footer.js +36 -12
  144. package/dist/site-footer.js.map +1 -1
  145. package/dist/skip-link.js +1 -1
  146. package/dist/slider.js +2 -2
  147. package/dist/stage-banner.js +1 -1
  148. package/dist/step-showcase.d.ts +62 -0
  149. package/dist/step-showcase.js +227 -0
  150. package/dist/step-showcase.js.map +1 -0
  151. package/dist/tabs.js +1 -1
  152. package/dist/tabs.js.map +1 -1
  153. package/dist/terminal-replay.js +1 -1
  154. package/dist/theme.js +2 -1
  155. package/dist/theme.js.map +1 -1
  156. package/dist/toast.js +1 -1
  157. package/dist/toc.js +1 -1
  158. package/dist/tooltip.js +1 -1
  159. package/dist/update-prompt.js +2 -1
  160. package/dist/update-prompt.js.map +1 -1
  161. package/dist/vertical-video.js +2 -2
  162. package/dist/video-player.js +3 -3
  163. package/dist/waveform.d.ts +93 -0
  164. package/dist/waveform.js +95 -0
  165. package/dist/waveform.js.map +1 -0
  166. package/package.json +138 -10
  167. package/registry/achievement.json +1 -1
  168. package/registry/action-bar.json +1 -1
  169. package/registry/activity-feed.json +1 -1
  170. package/registry/alert.json +1 -1
  171. package/registry/app-header.json +202 -0
  172. package/registry/app-shell.json +33 -9
  173. package/registry/argument-card.json +37 -5
  174. package/registry/audio-player.json +5 -3
  175. package/registry/auth-layout.json +1 -1
  176. package/registry/avatar.json +1 -1
  177. package/registry/badge.json +1 -1
  178. package/registry/button.json +3 -2
  179. package/registry/captcha.json +300 -0
  180. package/registry/card-grid.json +27 -3
  181. package/registry/card.json +1 -1
  182. package/registry/catalogue-page.json +1 -1
  183. package/registry/changelog-page.json +11 -7
  184. package/registry/chat.json +1 -1
  185. package/registry/checkbox.json +1 -1
  186. package/registry/chip-link.json +1 -1
  187. package/registry/chip.json +1 -1
  188. package/registry/choice-grid.json +1 -1
  189. package/registry/cn.json +1 -1
  190. package/registry/code-block.json +1 -1
  191. package/registry/combobox.json +1 -1
  192. package/registry/command.json +1 -1
  193. package/registry/comparison-table.json +207 -0
  194. package/registry/component-page.json +1 -1
  195. package/registry/confirm-button.json +1 -1
  196. package/registry/contact-page.json +1 -1
  197. package/registry/continue-prompt.json +1 -1
  198. package/registry/countdown.json +1 -1
  199. package/registry/cta-panel.json +1 -1
  200. package/registry/dashboard-layout.json +1 -1
  201. package/registry/data-table.json +1 -1
  202. package/registry/date-picker.json +1 -1
  203. package/registry/decision-list.json +1 -1
  204. package/registry/description-list.json +1 -1
  205. package/registry/detail-layout.json +1 -1
  206. package/registry/dialog.json +1 -1
  207. package/registry/docs-article-page.json +1 -1
  208. package/registry/docs-hub-page.json +1 -1
  209. package/registry/docs-layout.json +1 -1
  210. package/registry/docs-nav.json +177 -0
  211. package/registry/document-viewer.json +1 -1
  212. package/registry/dropdown-menu.json +1 -1
  213. package/registry/empty-state.json +1 -1
  214. package/registry/error-page.json +1 -1
  215. package/registry/examples/activity-feed/native/notifications.light.png +0 -0
  216. package/registry/examples/app-header/basic.d.ts +4 -0
  217. package/registry/examples/app-header/basic.js +23 -0
  218. package/registry/examples/app-header/basic.tsx +17 -0
  219. package/registry/examples/app-shell/desktop.d.ts +4 -0
  220. package/registry/examples/app-shell/desktop.js +41 -0
  221. package/registry/examples/app-shell/desktop.tsx +37 -0
  222. package/registry/examples/argument-card/hover-light.d.ts +4 -0
  223. package/registry/examples/argument-card/hover-light.js +17 -0
  224. package/registry/examples/argument-card/hover-light.tsx +19 -0
  225. package/registry/examples/argument-card/hover-quiet.d.ts +4 -0
  226. package/registry/examples/argument-card/hover-quiet.js +17 -0
  227. package/registry/examples/argument-card/hover-quiet.tsx +19 -0
  228. package/registry/examples/avatar/native/group.light.png +0 -0
  229. package/registry/examples/avatar/native/presence.light.png +0 -0
  230. package/registry/examples/avatar/native/sizes.light.png +0 -0
  231. package/registry/examples/badge/native/tones.light.png +0 -0
  232. package/registry/examples/button/native/ghost.light.png +0 -0
  233. package/registry/examples/captcha/disclosure.d.ts +4 -0
  234. package/registry/examples/captcha/disclosure.js +14 -0
  235. package/registry/examples/captcha/disclosure.tsx +11 -0
  236. package/registry/examples/captcha/form.d.ts +4 -0
  237. package/registry/examples/captcha/form.js +18 -0
  238. package/registry/examples/captcha/form.tsx +17 -0
  239. package/registry/examples/card/native/body.light.png +0 -0
  240. package/registry/examples/card/native/default.light.png +0 -0
  241. package/registry/examples/card/native/elevated.light.png +0 -0
  242. package/registry/examples/card/native/pressable.light.png +0 -0
  243. package/registry/examples/card-grid/hover-quiet.d.ts +4 -0
  244. package/registry/examples/card-grid/hover-quiet.js +18 -0
  245. package/registry/examples/card-grid/hover-quiet.tsx +20 -0
  246. package/registry/examples/changelog-page/releases.js +1 -1
  247. package/registry/examples/changelog-page/releases.tsx +1 -1
  248. package/registry/examples/chat/native/conversation.light.png +0 -0
  249. package/registry/examples/chat/native/inbox.light.png +0 -0
  250. package/registry/examples/chip/native/multiple.light.png +0 -0
  251. package/registry/examples/chip/native/removable.light.png +0 -0
  252. package/registry/examples/chip/native/single.light.png +0 -0
  253. package/registry/examples/chip/native/toggle.light.png +0 -0
  254. package/registry/examples/combobox/native/multiple.light.png +0 -0
  255. package/registry/examples/combobox/native/search.light.png +0 -0
  256. package/registry/examples/comparison-table/versus.d.ts +4 -0
  257. package/registry/examples/comparison-table/versus.js +28 -0
  258. package/registry/examples/comparison-table/versus.tsx +20 -0
  259. package/registry/examples/countdown/native/days.light.png +0 -0
  260. package/registry/examples/countdown/native/hours.light.png +0 -0
  261. package/registry/examples/countdown/native/sizes.light.png +0 -0
  262. package/registry/examples/countdown/native/urgent.light.png +0 -0
  263. package/registry/examples/countdown/native/with-label.light.png +0 -0
  264. package/registry/examples/date-picker/native/birth-date-wheel.light.png +0 -0
  265. package/registry/examples/date-picker/native/birth-date.light.png +0 -0
  266. package/registry/examples/date-picker/native/calendar.dark.png +0 -0
  267. package/registry/examples/date-picker/native/calendar.light.png +0 -0
  268. package/registry/examples/date-picker/native/day-strip.dark.png +0 -0
  269. package/registry/examples/date-picker/native/day-strip.light.png +0 -0
  270. package/registry/examples/date-picker/native/time-slots.dark.png +0 -0
  271. package/registry/examples/date-picker/native/time-slots.light.png +0 -0
  272. package/registry/examples/date-picker/native/time-wheel.light.png +0 -0
  273. package/registry/examples/description-list/native/job-details.light.png +0 -0
  274. package/registry/examples/dialog/native/sheet.dark.png +0 -0
  275. package/registry/examples/dialog/native/sheet.light.png +0 -0
  276. package/registry/examples/docs-nav/groups.d.ts +4 -0
  277. package/registry/examples/docs-nav/groups.js +21 -0
  278. package/registry/examples/docs-nav/groups.tsx +15 -0
  279. package/registry/examples/empty-state/native/default.light.png +0 -0
  280. package/registry/examples/field/native/default.light.png +0 -0
  281. package/registry/examples/field/native/select.light.png +0 -0
  282. package/registry/examples/force-update-screen/native/default.light.png +0 -0
  283. package/registry/examples/form/native/amount.light.png +0 -0
  284. package/registry/examples/form/native/audience.light.png +0 -0
  285. package/registry/examples/form/native/profile.light.png +0 -0
  286. package/registry/examples/form/native/settings.light.png +0 -0
  287. package/registry/examples/form/native/sign-up.light.png +0 -0
  288. package/registry/examples/form/native/upload.dark.png +0 -0
  289. package/registry/examples/form/native/upload.light.png +0 -0
  290. package/registry/examples/genui/streaming.d.ts +4 -0
  291. package/registry/examples/genui/streaming.js +18 -0
  292. package/registry/examples/genui/streaming.tsx +14 -0
  293. package/registry/examples/genui/table.d.ts +4 -0
  294. package/registry/examples/genui/table.js +19 -0
  295. package/registry/examples/genui/table.tsx +14 -0
  296. package/registry/examples/goal-gauge/native/default.light.png +0 -0
  297. package/registry/examples/header/native/large-title.light.png +0 -0
  298. package/registry/examples/link-card/hover-light.d.ts +4 -0
  299. package/registry/examples/link-card/hover-light.js +18 -0
  300. package/registry/examples/link-card/hover-light.tsx +20 -0
  301. package/registry/examples/link-card/hover-quiet.d.ts +4 -0
  302. package/registry/examples/link-card/hover-quiet.js +18 -0
  303. package/registry/examples/link-card/hover-quiet.tsx +20 -0
  304. package/registry/examples/loader/native/job-wait.light.png +0 -0
  305. package/registry/examples/maintenance-screen/native/default.light.png +0 -0
  306. package/registry/examples/map/native/places.light.png +0 -0
  307. package/registry/examples/markdown/native/basic.light.png +0 -0
  308. package/registry/examples/mascot-state/native/default.light.png +0 -0
  309. package/registry/examples/media-picker/native/story.light.png +0 -0
  310. package/registry/examples/meta-row/native/video.d.ts +4 -0
  311. package/registry/examples/meta-row/native/video.dark.png +0 -0
  312. package/registry/examples/meta-row/native/video.js +11 -0
  313. package/registry/examples/meta-row/native/video.light.png +0 -0
  314. package/registry/examples/meta-row/native/video.tsx +5 -0
  315. package/registry/examples/meta-row/status.d.ts +4 -0
  316. package/registry/examples/meta-row/status.js +12 -0
  317. package/registry/examples/meta-row/status.tsx +7 -0
  318. package/registry/examples/meta-row/video.d.ts +4 -0
  319. package/registry/examples/meta-row/video.js +12 -0
  320. package/registry/examples/meta-row/video.tsx +7 -0
  321. package/registry/examples/meter/native/credits.light.png +0 -0
  322. package/registry/examples/meter/native/split-ring.light.png +0 -0
  323. package/registry/examples/number-ticker/native/balance.light.png +0 -0
  324. package/registry/examples/onboarding/native/first-launch.light.png +0 -0
  325. package/registry/examples/otp-input/native/verify.light.png +0 -0
  326. package/registry/examples/pagination/native/cursor.light.png +0 -0
  327. package/registry/examples/pagination/native/pages.light.png +0 -0
  328. package/registry/examples/permission-prompt/native/blocked.light.png +0 -0
  329. package/registry/examples/permission-prompt/native/camera.light.png +0 -0
  330. package/registry/examples/profile-card/native/default.light.png +0 -0
  331. package/registry/examples/radio-group/native/buttons.light.png +0 -0
  332. package/registry/examples/radio-group/native/cards.light.png +0 -0
  333. package/registry/examples/radio-group/native/list.light.png +0 -0
  334. package/registry/examples/radio-group/native/segmented.light.png +0 -0
  335. package/registry/examples/rail-nav/expandable.d.ts +4 -0
  336. package/registry/examples/rail-nav/expandable.js +34 -0
  337. package/registry/examples/rail-nav/expandable.tsx +28 -0
  338. package/registry/examples/rail-nav/studio.d.ts +4 -0
  339. package/registry/examples/rail-nav/studio.js +43 -0
  340. package/registry/examples/rail-nav/studio.tsx +38 -0
  341. package/registry/examples/screen/native/app-shell.light.png +0 -0
  342. package/registry/examples/screen/native/auth.light.png +0 -0
  343. package/registry/examples/screen/native/map.light.png +0 -0
  344. package/registry/examples/screen/native/notifications.light.png +0 -0
  345. package/registry/examples/screen/native/profile.light.png +0 -0
  346. package/registry/examples/segmented/native/default.light.png +0 -0
  347. package/registry/examples/segmented/native/small.light.png +0 -0
  348. package/registry/examples/settings-layout/flat.d.ts +4 -0
  349. package/registry/examples/settings-layout/flat.js +26 -0
  350. package/registry/examples/settings-layout/flat.tsx +30 -0
  351. package/registry/examples/showcase/native/slides.light.png +0 -0
  352. package/registry/examples/site-footer/app.d.ts +4 -0
  353. package/registry/examples/site-footer/app.js +25 -0
  354. package/registry/examples/site-footer/app.tsx +22 -0
  355. package/registry/examples/site-footer/docs.d.ts +4 -0
  356. package/registry/examples/site-footer/docs.js +31 -0
  357. package/registry/examples/site-footer/docs.tsx +24 -0
  358. package/registry/examples/slider/native/default.light.png +0 -0
  359. package/registry/examples/slider/native/stepped.light.png +0 -0
  360. package/registry/examples/step-progress/native/sign-up.light.png +0 -0
  361. package/registry/examples/step-showcase/desktop.d.ts +4 -0
  362. package/registry/examples/step-showcase/desktop.js +24 -0
  363. package/registry/examples/step-showcase/desktop.tsx +19 -0
  364. package/registry/examples/step-showcase/phone.d.ts +4 -0
  365. package/registry/examples/step-showcase/phone.js +24 -0
  366. package/registry/examples/step-showcase/phone.tsx +19 -0
  367. package/registry/examples/stepper/native/run.light.png +0 -0
  368. package/registry/examples/swipeable-row/native/conversation.light.png +0 -0
  369. package/registry/examples/switch/native/settings.light.png +0 -0
  370. package/registry/examples/tab-bar/native/main-sections.light.png +0 -0
  371. package/registry/examples/tabs/native/sections.light.png +0 -0
  372. package/registry/examples/tabs/native/segmented.light.png +0 -0
  373. package/registry/examples/tag-selector/native/interests.light.png +0 -0
  374. package/registry/examples/toast/native/tones.light.png +0 -0
  375. package/registry/examples/txt/native/tones.dark.png +0 -0
  376. package/registry/examples/txt/native/tones.light.png +0 -0
  377. package/registry/examples/update-prompt/native/default.light.png +0 -0
  378. package/registry/examples/waveform/card.d.ts +4 -0
  379. package/registry/examples/waveform/card.js +18 -0
  380. package/registry/examples/waveform/card.tsx +16 -0
  381. package/registry/examples/waveform/native/card.d.ts +4 -0
  382. package/registry/examples/waveform/native/card.dark.png +0 -0
  383. package/registry/examples/waveform/native/card.js +19 -0
  384. package/registry/examples/waveform/native/card.light.png +0 -0
  385. package/registry/examples/waveform/native/card.tsx +19 -0
  386. package/registry/examples/waveform/sizes.d.ts +4 -0
  387. package/registry/examples/waveform/sizes.js +16 -0
  388. package/registry/examples/waveform/sizes.tsx +14 -0
  389. package/registry/field.json +1 -1
  390. package/registry/file-upload.json +1 -1
  391. package/registry/filter-bar.json +1 -1
  392. package/registry/force-update-screen.json +1 -1
  393. package/registry/form.json +1 -1
  394. package/registry/gallery-page.json +1 -1
  395. package/registry/genui.json +409 -0
  396. package/registry/glow-card.json +1 -1
  397. package/registry/goal-gauge.json +1 -1
  398. package/registry/how-it-works-page.json +1 -1
  399. package/registry/image-cropper.json +1 -1
  400. package/registry/index.json +323 -14
  401. package/registry/iso.json +1 -1
  402. package/registry/kanban.json +1 -1
  403. package/registry/kbd.json +1 -1
  404. package/registry/landing-page.json +1 -1
  405. package/registry/landscape.json +1 -1
  406. package/registry/legal-page.json +1 -1
  407. package/registry/link-card.json +38 -6
  408. package/registry/list.json +1 -1
  409. package/registry/loader.json +1 -1
  410. package/registry/longform-page.json +1 -1
  411. package/registry/maintenance-screen.json +1 -1
  412. package/registry/map.json +2 -2
  413. package/registry/markdown.json +1 -1
  414. package/registry/marketing-layout.json +1 -1
  415. package/registry/marquee.json +1 -1
  416. package/registry/mascot-quote.json +1 -1
  417. package/registry/mascot-state.json +1 -1
  418. package/registry/mascots.json +1 -1
  419. package/registry/match-dialog.json +1 -1
  420. package/registry/media-capture.json +1 -1
  421. package/registry/media-grid.json +92 -6
  422. package/registry/meta-row.json +215 -0
  423. package/registry/meter.json +1 -1
  424. package/registry/nav-bar.json +13 -13
  425. package/registry/number-ticker.json +1 -1
  426. package/registry/page-header.json +1 -1
  427. package/registry/page-hero.json +1 -1
  428. package/registry/page.json +1 -1
  429. package/registry/pagination.json +1 -1
  430. package/registry/photo-grid.json +1 -1
  431. package/registry/pointer-light.json +1 -1
  432. package/registry/popover.json +1 -1
  433. package/registry/pricing-page.json +1 -1
  434. package/registry/product-page.json +1 -1
  435. package/registry/profile-card.json +1 -1
  436. package/registry/progress.json +1 -1
  437. package/registry/promise-card.json +1 -1
  438. package/registry/radio-group.json +1 -1
  439. package/registry/rail-nav.json +493 -0
  440. package/registry/recipes.json +1 -1
  441. package/registry/scroll-stage.json +1 -1
  442. package/registry/search-field.json +1 -1
  443. package/registry/section-backdrop.json +1 -1
  444. package/registry/separator.json +1 -1
  445. package/registry/settings-layout.json +104 -9
  446. package/registry/showcase.json +1 -1
  447. package/registry/site-footer.json +49 -17
  448. package/registry/sites.json +1 -1
  449. package/registry/skeleton.json +1 -1
  450. package/registry/skip-link.json +2 -2
  451. package/registry/slider.json +1 -1
  452. package/registry/slot.json +1 -1
  453. package/registry/spinner.json +1 -1
  454. package/registry/split-view.json +1 -1
  455. package/registry/stage-banner.json +1 -1
  456. package/registry/stat.json +1 -1
  457. package/registry/status-page.json +1 -1
  458. package/registry/step-progress.json +1 -1
  459. package/registry/step-showcase.json +296 -0
  460. package/registry/stepper.json +1 -1
  461. package/registry/swipe-deck.json +1 -1
  462. package/registry/switch.json +1 -1
  463. package/registry/tabs.json +2 -2
  464. package/registry/tag-input.json +1 -1
  465. package/registry/tag-selector.json +1 -1
  466. package/registry/terminal-replay.json +1 -1
  467. package/registry/theme.json +1 -1
  468. package/registry/toast.json +1 -1
  469. package/registry/toc.json +1 -1
  470. package/registry/tooltip.json +1 -1
  471. package/registry/tree-view.json +1 -1
  472. package/registry/update-prompt.json +1 -1
  473. package/registry/verified-badge.json +1 -1
  474. package/registry/vertical-video.json +1 -1
  475. package/registry/video-player.json +1 -1
  476. package/registry/video-trimmer.json +1 -1
  477. package/registry/virtual.json +1 -1
  478. package/registry/waveform.json +296 -0
  479. package/dist/chunk-2FRWNSRO.js.map +0 -1
  480. package/dist/chunk-3BC4XQ6C.js.map +0 -1
  481. package/dist/chunk-3GODX3D6.js.map +0 -1
  482. package/dist/chunk-3IN6TOPM.js.map +0 -1
  483. package/dist/chunk-4LOMIQVX.js.map +0 -1
  484. package/dist/chunk-G3ETON2A.js.map +0 -1
  485. package/dist/chunk-IZ7MV6HM.js.map +0 -1
  486. package/dist/chunk-LIPK4UCS.js.map +0 -1
  487. package/dist/chunk-OWC2LZD2.js.map +0 -1
  488. package/dist/chunk-ZNMFG62E.js.map +0 -1
  489. /package/dist/{chunk-5MH64NIL.js.map → chunk-2L67YTNV.js.map} +0 -0
  490. /package/dist/{chunk-FKBHWS4N.js.map → chunk-CEJDH6SA.js.map} +0 -0
  491. /package/dist/{chunk-5Z7FWCV2.js.map → chunk-HBZPJ3EP.js.map} +0 -0
  492. /package/dist/{chunk-C2BRIFJG.js.map → chunk-HJFRHYCI.js.map} +0 -0
  493. /package/dist/{chunk-BTMFZ66D.js.map → chunk-KM6VAKIE.js.map} +0 -0
  494. /package/dist/{chunk-DGQMDJXK.js.map → chunk-LZNZLCOE.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/site-footer/site-footer.tsx"],"sourcesContent":["// Client (the marks hold an id). The footer shared by every site of the Krizaka family: the site's own columns, then the\n// family in columns from `@krizaka/ui/sites` (the same groups as the bar's switcher), then the signature line — “A\n// Krizaka product” by the kind of the current site — the version and the place.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { FamilyMark } from \"../family-mark\";\nimport { KrizakaLogo } from \"../marks/KrizakaLogo\";\nimport { type FamilyLabels, familyLabels, siteById, type SiteId, sitesByGroup } from \"../sites/sites\";\n\nexport const siteFooter = tv({\n slots: {\n root: \"w-full border-t border-border-subtle bg-surface-0 text-fg\",\n inner: \"mx-auto grid w-full max-w-(--kz-page-max,72rem) grid-cols-[minmax(0,1fr)] gap-10 px-(--kz-page-gutter,16px) py-12\",\n top: \"grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]\",\n site: \"grid content-start gap-3\",\n siteName: \"inline-flex items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg\",\n siteText: \"max-w-xs text-sm leading-relaxed text-fg-secondary\",\n own: \"grid grid-cols-2 gap-8 sm:grid-cols-3\",\n family: \"grid grid-cols-2 gap-8 border-t border-border-subtle pt-8 md:grid-cols-4\",\n column: \"grid min-w-0 content-start gap-3\",\n title: \"text-[11px] font-semibold uppercase tracking-wider text-fg-secondary\",\n list: \"grid min-w-0 gap-2\",\n link:\n \"inline-flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 rounded-md text-sm [overflow-wrap:anywhere] text-fg-secondary no-underline transition-colors hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg aria-[current=true]:text-fg aria-[current=true]:font-semibold\",\n mark: \"flex h-4 w-4 shrink-0 items-center justify-center text-fg\",\n tag: \"rounded-full bg-surface-3 px-1.5 py-px text-[10px] font-semibold uppercase tracking-wider text-fg-secondary\",\n bottom: \"flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-border-subtle pt-6 text-xs text-fg-secondary\",\n signature:\n \"inline-flex items-center gap-2 rounded-md font-medium text-fg no-underline hover:text-fg-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n version:\n \"rounded-full border border-border-subtle bg-surface-2 px-2 py-0.5 font-mono text-[11px] text-fg-secondary\",\n legal: \"flex flex-wrap items-center gap-x-4 gap-y-2 sm:ml-auto\",\n },\n});\nconst s = siteFooter();\n\nexport type SiteFooterProps = Omit<React.ComponentProps<\"footer\">, \"children\"> & {\n /** The site this footer belongs to (`@krizaka/ui/sites`): its mark and line, its signature, marked in the family. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** The site's own columns (`SiteFooter.Column`), before the family. */\n children?: React.ReactNode;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /**\n * Shows the family in columns (the Krizaka sites: www, ui., java.). A product is independent once deployed: pass\n * `family={false}` and the footer holds only its own columns, the legal links, the version and one publisher line —\n * “A Krizaka product”, linking to www.krizaka.com.\n * @default true\n */\n family?: boolean;\n /** The end of the signature line: legal links, a language switch (`SiteFooter.Link`s or any inline content). */\n legal?: React.ReactNode;\n};\n\n/** The footer of a Krizaka site: its own columns, the family in columns, the signature, the version, Montréal. */\nexport function SiteFooter({\n current,\n labels = familyLabels.en,\n children,\n version,\n env,\n legal,\n family = true,\n className,\n ...props\n}: SiteFooterProps) {\n const id = React.useId();\n const site = siteById(current);\n const krizaka = siteById(\"krizaka\");\n const tag = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean).join(\" · \");\n return (\n <footer className={s.root({ className })} {...props}>\n <div className={s.inner()}>\n <div className={s.top()}>\n <div className={s.site()}>\n <a href={site.url} className={s.siteName()}>\n <FamilyMark mark={site.mark} size={24} />\n {site.name}\n </a>\n <p className={s.siteText()}>{labels.descriptions[site.id]}</p>\n </div>\n {children && <div className={s.own()}>{children}</div>}\n </div>\n {family && (\n <nav aria-label={labels.family} className={s.family()}>\n {sitesByGroup().map(({ group, sites }) => (\n <div key={group} className={s.column()}>\n <p id={`${id}-${group}`} className={s.title()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className={s.list()}>\n {sites.map((item) => (\n <li key={item.id}>\n <a href={item.url} aria-current={item.id === current ? \"true\" : undefined} className={s.link()}>\n <span className={s.mark()}>\n <FamilyMark mark={item.mark} size={16} />\n </span>\n {item.name}\n {item.status !== \"released\" && <span className={s.tag()}>{labels.status[item.status]}</span>}\n {item.id === current && <span className=\"sr-only\">({labels.current})</span>}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </nav>\n )}\n <div className={s.bottom()}>\n <a href={krizaka.url} className={s.signature()}>\n <KrizakaLogo size={18} animated={false} />\n {labels.signature[site.kind]}\n </a>\n {tag && (\n <span className={s.version()}>\n <span className=\"sr-only\">{labels.version} </span>\n {tag}\n </span>\n )}\n <span>{labels.place}</span>\n {legal && <div className={s.legal()}>{legal}</div>}\n </div>\n </div>\n </footer>\n );\n}\n\nexport type SiteFooterColumnProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The column's heading (“Docs”) — passed translated. */\n title: string;\n /** Its links (`SiteFooter.Link`). */\n children: React.ReactNode;\n};\n\n/** One of the site's own columns: a heading and its links. */\nexport function SiteFooterColumn({ title, children, className, ...props }: SiteFooterColumnProps) {\n const id = React.useId();\n return (\n <div className={s.column({ className })} {...props}>\n <p id={id} className={s.title()}>\n {title}\n </p>\n <ul aria-labelledby={id} className={s.list()}>\n {React.Children.map(children, (child) => (child ? <li>{child}</li> : null))}\n </ul>\n </div>\n );\n}\n\nexport type SiteFooterLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page: `aria-current=\"page\"`. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the footer. */\nexport function SiteFooterLink({ active, asChild, className, ...props }: SiteFooterLinkProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.link({ className })} {...props} />;\n}\n\nSiteFooter.Column = SiteFooterColumn;\nSiteFooter.Link = SiteFooterLink;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/site-footer/site-footer.tsx"],"sourcesContent":["// Client (the marks hold an id). The footer shared by every site of the Krizaka family: the site's own columns, then the\n// family in columns from `@krizaka/ui/sites` (the same groups as the bar's switcher), then the signature line — “A\n// Krizaka product” by the kind of the current site — the version and the place.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { FamilyMark } from \"../family-mark\";\nimport { KrizakaLogo } from \"../marks/KrizakaLogo\";\nimport { type FamilyLabels, familyLabels, siteById, type SiteId, sitesByGroup } from \"../sites/sites\";\n\nexport const siteFooter = tv({\n slots: {\n root: \"w-full border-t border-border-subtle bg-surface-0 text-fg\",\n inner:\n \"mx-auto grid w-full max-w-[calc(var(--kz-page-max,72rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] grid-cols-[minmax(0,1fr)] gap-10 px-[var(--kz-page-gutter,clamp(16px,3.2vw,32px))] py-12\",\n top: \"grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]\",\n site: \"grid content-start gap-3\",\n siteName: \"inline-flex items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg\",\n siteText: \"max-w-xs text-sm leading-relaxed text-fg-secondary\",\n own: \"grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-8\",\n family: \"grid grid-cols-2 gap-8 border-t border-border-subtle pt-8 md:grid-cols-4\",\n column: \"grid min-w-0 content-start gap-3\",\n title: \"text-[11px] font-semibold uppercase tracking-wider text-fg-secondary\",\n list: \"grid min-w-0 gap-2\",\n link:\n \"inline-flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 rounded-md text-sm [overflow-wrap:anywhere] text-fg-secondary no-underline transition-colors hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg aria-[current=true]:text-fg aria-[current=true]:font-semibold\",\n mark: \"flex h-4 w-4 shrink-0 items-center justify-center text-fg\",\n tag: \"rounded-full bg-surface-3 px-1.5 py-px text-[10px] font-semibold uppercase tracking-wider text-fg-secondary\",\n bottom: \"flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-border-subtle pt-6 text-xs text-fg-secondary\",\n signature:\n \"inline-flex items-center gap-2 rounded-md font-medium text-fg no-underline hover:text-fg-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n version:\n \"rounded-full border border-border-subtle bg-surface-2 px-2 py-0.5 font-mono text-[11px] text-fg-secondary\",\n legal: \"flex flex-wrap items-center gap-x-4 gap-y-2 sm:ml-auto\",\n },\n variants: {\n // `site`: the full footer. `docs`: no site block, the columns in one row, on the documentation's width. `app`: one\n // slim line inside a signed-in product — signature, version, legal links.\n variant: {\n site: {},\n docs: {\n inner: \"max-w-[calc(var(--kz-page-max-docs,88rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] gap-6 py-8\",\n top: \"lg:grid-cols-[minmax(0,1fr)]\",\n own: \"sm:grid-cols-4\",\n },\n app: {\n root: \"bg-transparent\",\n inner: \"gap-0 py-3\",\n bottom: \"border-t-0 pt-0\",\n },\n },\n },\n defaultVariants: { variant: \"site\" },\n});\n\nexport type SiteFooterProps = Omit<React.ComponentProps<\"footer\">, \"children\"> & {\n /** The site this footer belongs to (`@krizaka/ui/sites`): its mark and line, its signature, marked in the family. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** The site's own columns (`SiteFooter.Column`), before the family. */\n children?: React.ReactNode;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /**\n * Shows the family in columns (the Krizaka sites: www, ui., java.). A product is independent once deployed: pass\n * `family={false}` and the footer holds only its own columns, the legal links, the version and one publisher line —\n * “A Krizaka product”, linking to www.krizaka.com.\n * @default true\n */\n family?: boolean;\n /** The end of the signature line: legal links, a language switch (`SiteFooter.Link`s or any inline content). */\n legal?: React.ReactNode;\n /**\n * `site` — the full footer of a marketing or company site. `docs` — a compact one for documentation pages (no site\n * block, the columns in a row, the documentation's width; never the family). `app` — one slim line inside a signed-in\n * product: the publisher line, the version and the legal links (no columns, no family); render it once, in the\n * layout, and not at all where the app shell has a sidebar that holds them.\n * @default \"site\"\n */\n variant?: \"site\" | \"docs\" | \"app\";\n};\n\n/** The footer of a Krizaka site: its own columns, the family in columns, the signature, the version, Montréal. */\nexport function SiteFooter({\n current,\n labels = familyLabels.en,\n children,\n version,\n env,\n legal,\n family: familyProp = true,\n variant = \"site\",\n className,\n ...props\n}: SiteFooterProps) {\n const id = React.useId();\n const s = siteFooter({ variant });\n const family = variant === \"site\" && familyProp;\n const slim = variant === \"app\";\n const site = siteById(current);\n const krizaka = siteById(\"krizaka\");\n const tag = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean).join(\" · \");\n return (\n <footer className={s.root({ className })} {...props}>\n <div className={s.inner()}>\n {!slim && (\n <div className={s.top()}>\n {variant === \"site\" && (\n <div className={s.site()}>\n <a href={site.url} className={s.siteName()}>\n <FamilyMark mark={site.mark} size={24} />\n {site.name}\n </a>\n <p className={s.siteText()}>{labels.descriptions[site.id]}</p>\n </div>\n )}\n {React.Children.toArray(children).length > 0 && <div className={s.own()}>{children}</div>}\n </div>\n )}\n {family && (\n <nav aria-label={labels.family} className={s.family()}>\n {sitesByGroup().map(({ group, sites }) => (\n <div key={group} className={s.column()}>\n <p id={`${id}-${group}`} className={s.title()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className={s.list()}>\n {sites.map((item) => (\n <li key={item.id}>\n <a href={item.url} aria-current={item.id === current ? \"true\" : undefined} className={s.link()}>\n <span className={s.mark()}>\n <FamilyMark mark={item.mark} size={16} />\n </span>\n {item.name}\n {item.status !== \"released\" && <span className={s.tag()}>{labels.status[item.status]}</span>}\n {item.id === current && <span className=\"sr-only\">({labels.current})</span>}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </nav>\n )}\n <div className={s.bottom()}>\n <a href={krizaka.url} className={s.signature()}>\n <KrizakaLogo size={18} animated={false} />\n {labels.signature[site.kind]}\n </a>\n {tag && (\n <span className={s.version()}>\n <span className=\"sr-only\">{labels.version} </span>\n {tag}\n </span>\n )}\n {!slim && <span>{labels.place}</span>}\n {legal && <div className={s.legal()}>{legal}</div>}\n </div>\n </div>\n </footer>\n );\n}\n\nexport type SiteFooterColumnProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The column's heading (“Docs”) — passed translated. */\n title: string;\n /** Its links (`SiteFooter.Link`). */\n children: React.ReactNode;\n};\n\n/** One of the site's own columns: a heading and its links. */\nexport function SiteFooterColumn({ title, children, className, ...props }: SiteFooterColumnProps) {\n const id = React.useId();\n // A group with no link is not a column: only a heading over nothing.\n if (React.Children.toArray(children).length === 0) return null;\n const s = siteFooter();\n return (\n <div className={s.column({ className })} {...props}>\n <p id={id} className={s.title()}>\n {title}\n </p>\n <ul aria-labelledby={id} className={s.list()}>\n {React.Children.toArray(children).map((child, i) => <li key={i}>{child}</li>)}\n </ul>\n </div>\n );\n}\n\nexport type SiteFooterLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page: `aria-current=\"page\"`. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the footer. */\nexport function SiteFooterLink({ active, asChild, className, ...props }: SiteFooterLinkProps) {\n const s = siteFooter();\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.link({ className })} {...props} />;\n}\n\nSiteFooter.Column = SiteFooterColumn;\nSiteFooter.Link = SiteFooterLink;\n"],"mappings":";;;;;;;;;;;;AAGA,SAAS,YAAY;AACrB,YAAY,WAAW;AACvB,SAAS,UAAU;AAgHH,SACE,KADF;AA1GT,IAAM,aAAa,GAAG;AAAA,EAC3B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,OACE;AAAA,IACF,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,IACV,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MACE;AAAA,IAEF,MAAM;AAAA,IACN,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,WACE;AAAA,IACF,SACE;AAAA,IACF,OAAO;AAAA,EACT;AAAA,EACA,UAAU;AAAA;AAAA;AAAA,IAGR,SAAS;AAAA,MACP,MAAM,CAAC;AAAA,MACP,MAAM;AAAA,QACJ,OAAO;AAAA,QACP,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,SAAS,OAAO;AACrC,CAAC;AAoCM,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,SAAS,aAAa;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ,aAAa;AAAA,EACrB,UAAU;AAAA,EACV;AAAA,EACA,GAAG;AACL,GAAoB;AAClB,QAAM,KAAW,YAAM;AACvB,QAAM,IAAI,WAAW,EAAE,QAAQ,CAAC;AAChC,QAAM,SAAS,YAAY,UAAU;AACrC,QAAM,OAAO,YAAY;AACzB,QAAM,OAAO,SAAS,OAAO;AAC7B,QAAM,UAAU,SAAS,SAAS;AAClC,QAAM,MAAM,CAAC,KAAK,WAAW,IAAI,QAAQ,QAAQ,MAAM,EAAE,CAAC,EAAE,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AACxF,SACE,oBAAC,YAAO,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC5C,+BAAC,SAAI,WAAW,EAAE,MAAM,GACrB;AAAA,KAAC,QACA,qBAAC,SAAI,WAAW,EAAE,IAAI,GACnB;AAAA,kBAAY,UACX,qBAAC,SAAI,WAAW,EAAE,KAAK,GACrB;AAAA,6BAAC,OAAE,MAAM,KAAK,KAAK,WAAW,EAAE,SAAS,GACvC;AAAA,8BAAC,cAAW,MAAM,KAAK,MAAM,MAAM,IAAI;AAAA,UACtC,KAAK;AAAA,WACR;AAAA,QACA,oBAAC,OAAE,WAAW,EAAE,SAAS,GAAI,iBAAO,aAAa,KAAK,EAAE,GAAE;AAAA,SAC5D;AAAA,MAEK,eAAS,QAAQ,QAAQ,EAAE,SAAS,KAAK,oBAAC,SAAI,WAAW,EAAE,IAAI,GAAI,UAAS;AAAA,OACrF;AAAA,IAED,UACC,oBAAC,SAAI,cAAY,OAAO,QAAQ,WAAW,EAAE,OAAO,GACjD,uBAAa,EAAE,IAAI,CAAC,EAAE,OAAO,MAAM,MAClC,qBAAC,SAAgB,WAAW,EAAE,OAAO,GACnC;AAAA,0BAAC,OAAE,IAAI,GAAG,EAAE,IAAI,KAAK,IAAI,WAAW,EAAE,MAAM,GACzC,iBAAO,OAAO,KAAK,GACtB;AAAA,MACA,oBAAC,QAAG,mBAAiB,GAAG,EAAE,IAAI,KAAK,IAAI,WAAW,EAAE,KAAK,GACtD,gBAAM,IAAI,CAAC,SACV,oBAAC,QACC,+BAAC,OAAE,MAAM,KAAK,KAAK,gBAAc,KAAK,OAAO,UAAU,SAAS,QAAW,WAAW,EAAE,KAAK,GAC3F;AAAA,4BAAC,UAAK,WAAW,EAAE,KAAK,GACtB,8BAAC,cAAW,MAAM,KAAK,MAAM,MAAM,IAAI,GACzC;AAAA,QACC,KAAK;AAAA,QACL,KAAK,WAAW,cAAc,oBAAC,UAAK,WAAW,EAAE,IAAI,GAAI,iBAAO,OAAO,KAAK,MAAM,GAAE;AAAA,QACpF,KAAK,OAAO,WAAW,qBAAC,UAAK,WAAU,WAAU;AAAA;AAAA,UAAE,OAAO;AAAA,UAAQ;AAAA,WAAC;AAAA,SACtE,KARO,KAAK,EASd,CACD,GACH;AAAA,SAjBQ,KAkBV,CACD,GACH;AAAA,IAEF,qBAAC,SAAI,WAAW,EAAE,OAAO,GACvB;AAAA,2BAAC,OAAE,MAAM,QAAQ,KAAK,WAAW,EAAE,UAAU,GAC3C;AAAA,4BAAC,eAAY,MAAM,IAAI,UAAU,OAAO;AAAA,QACvC,OAAO,UAAU,KAAK,IAAI;AAAA,SAC7B;AAAA,MACC,OACC,qBAAC,UAAK,WAAW,EAAE,QAAQ,GACzB;AAAA,6BAAC,UAAK,WAAU,WAAW;AAAA,iBAAO;AAAA,UAAQ;AAAA,WAAC;AAAA,QAC1C;AAAA,SACH;AAAA,MAED,CAAC,QAAQ,oBAAC,UAAM,iBAAO,OAAM;AAAA,MAC7B,SAAS,oBAAC,SAAI,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,OAC9C;AAAA,KACF,GACF;AAEJ;AAUO,SAAS,iBAAiB,EAAE,OAAO,UAAU,WAAW,GAAG,MAAM,GAA0B;AAChG,QAAM,KAAW,YAAM;AAEvB,MAAU,eAAS,QAAQ,QAAQ,EAAE,WAAW,EAAG,QAAO;AAC1D,QAAM,IAAI,WAAW;AACrB,SACE,qBAAC,SAAI,WAAW,EAAE,OAAO,EAAE,UAAU,CAAC,GAAI,GAAG,OAC3C;AAAA,wBAAC,OAAE,IAAQ,WAAW,EAAE,MAAM,GAC3B,iBACH;AAAA,IACA,oBAAC,QAAG,mBAAiB,IAAI,WAAW,EAAE,KAAK,GACxC,UAAM,eAAS,QAAQ,QAAQ,EAAE,IAAI,CAAC,OAAO,MAAM,oBAAC,QAAY,mBAAJ,CAAU,CAAK,GAC9E;AAAA,KACF;AAEJ;AAUO,SAAS,eAAe,EAAE,QAAQ,SAAS,WAAW,GAAG,MAAM,GAAwB;AAC5F,QAAM,IAAI,WAAW;AACrB,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SAAO,oBAAC,QAAK,gBAAc,SAAS,SAAS,QAAW,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AACvG;AAEA,WAAW,SAAS;AACpB,WAAW,OAAO;","names":[]}
package/dist/skip-link.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  SkipLink,
4
4
  skipLink
5
- } from "./chunk-3GODX3D6.js";
5
+ } from "./chunk-QDXV544C.js";
6
6
  export {
7
7
  SkipLink,
8
8
  skipLink
package/dist/slider.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import {
3
3
  tv
4
- } from "./chunk-C2BRIFJG.js";
5
- import "./chunk-2FRWNSRO.js";
4
+ } from "./chunk-HJFRHYCI.js";
5
+ import "./chunk-NSLXEDIS.js";
6
6
 
7
7
  // src/slider/slider.tsx
8
8
  import { Slider as SliderPrimitive } from "radix-ui";
@@ -2,7 +2,7 @@ import {
2
2
  brandClass,
3
3
  cn,
4
4
  storyVariantClass
5
- } from "./chunk-IZ7MV6HM.js";
5
+ } from "./chunk-XVFQZ3ZG.js";
6
6
 
7
7
  // src/stage-banner/stage-banner.tsx
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -0,0 +1,62 @@
1
+ import * as React from 'react';
2
+
3
+ type DeviceKind = "phone" | "browser" | "desktop";
4
+ interface DeviceFrameProps extends React.ComponentProps<"div"> {
5
+ /** The device: a phone, a browser window or a macOS window. */
6
+ kind: DeviceKind;
7
+ /** The browser's address or the window's title (“dev.orazaka.com”, “Orazaka”). */
8
+ title?: string;
9
+ }
10
+ /** A phone, a browser window or a macOS window around a screen of content. */
11
+ declare function DeviceFrame({ kind, title, className, children, ...props }: DeviceFrameProps): React.JSX.Element;
12
+
13
+ interface ShowcaseStep {
14
+ /** A stable key. */
15
+ id: string;
16
+ /** The step's name (“Make an image”), passed translated. */
17
+ title: string;
18
+ /** One line under it. */
19
+ description: string;
20
+ /** The still shown first, and the only picture under reduced motion. */
21
+ poster: string;
22
+ /** What the poster shows, for assistive technology. */
23
+ alt: string;
24
+ /** The recording: WebM and / or MP4. Without one, the poster stays `duration` ms. */
25
+ video?: {
26
+ webm?: string;
27
+ mp4?: string;
28
+ };
29
+ /** Milliseconds a step without a video stays. @default 6000 */
30
+ duration?: number;
31
+ }
32
+ interface StepShowcaseLabels {
33
+ /** The button's name while paused. */
34
+ play: string;
35
+ /** The button's name while it plays. */
36
+ pause: string;
37
+ /** A step's position in words: `(2, 4) => "Step 2 of 4"`. */
38
+ step: (n: number, total: number) => string;
39
+ }
40
+ declare const stepShowcaseLabels: StepShowcaseLabels;
41
+ interface StepShowcaseProps extends Omit<React.ComponentProps<"section">, "children"> {
42
+ /** The sequence's accessible name (“Orazaka in your pocket”), passed translated. */
43
+ label: string;
44
+ /** The steps, in the order of the journey. */
45
+ steps: readonly ShowcaseStep[];
46
+ /** The device the recordings were made on. */
47
+ device: DeviceKind;
48
+ /** The browser's address or the window's title. */
49
+ deviceTitle?: string;
50
+ /** Moves on by itself (never under reduced motion). @default true */
51
+ autoplay?: boolean;
52
+ /** The controls' words, translated. */
53
+ labels?: StepShowcaseLabels;
54
+ /** The step shown first. @default 0 */
55
+ defaultIndex?: number;
56
+ /** Called when the step changes — `user` is true when the visitor asked for it. */
57
+ onIndexChange?: (index: number, user: boolean) => void;
58
+ }
59
+ /** One device frame, its steps beside it, playing each recording then the next — a product's guided tour. */
60
+ declare function StepShowcase({ label, steps, device, deviceTitle, autoplay, labels, defaultIndex, onIndexChange, className, ...props }: StepShowcaseProps): React.JSX.Element;
61
+
62
+ export { DeviceFrame, type DeviceFrameProps, type DeviceKind, type ShowcaseStep, StepShowcase, type StepShowcaseLabels, type StepShowcaseProps, stepShowcaseLabels };
@@ -0,0 +1,227 @@
1
+ "use client";
2
+ import {
3
+ cn
4
+ } from "./chunk-NSLXEDIS.js";
5
+
6
+ // src/step-showcase/device-frame.tsx
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ var screen = {
9
+ phone: "aspect-[9/19.5]",
10
+ browser: "aspect-[16/10]",
11
+ desktop: "aspect-[16/10]"
12
+ };
13
+ function DeviceFrame({ kind, title, className, children, ...props }) {
14
+ if (kind === "phone") {
15
+ return /* @__PURE__ */ jsx("div", { "data-device": "phone", className: cn("relative mx-auto w-full max-w-[18rem] rounded-[2.4rem] border border-border-strong bg-surface-3 p-2 shadow-2xl", className), ...props, children: /* @__PURE__ */ jsxs("div", { className: cn("relative overflow-hidden rounded-[1.9rem] bg-surface-0", screen.phone), children: [
16
+ children,
17
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute left-1/2 top-2 h-5 w-20 -translate-x-1/2 rounded-full bg-surface-3" })
18
+ ] }) });
19
+ }
20
+ return /* @__PURE__ */ jsxs("div", { "data-device": kind, className: cn("relative w-full overflow-hidden rounded-xl border border-border-default bg-surface-1 shadow-2xl", className), ...props, children: [
21
+ /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-1.5 border-b border-border-subtle bg-surface-2 px-3", children: [
22
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-2.5 w-2.5 rounded-full bg-danger/80" }),
23
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-2.5 w-2.5 rounded-full bg-warning/80" }),
24
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-2.5 w-2.5 rounded-full bg-success/80" }),
25
+ title && (kind === "browser" ? /* @__PURE__ */ jsx("span", { className: "mx-auto max-w-[60%] truncate rounded-md bg-surface-1 px-3 py-0.5 font-mono text-[11px] text-fg-secondary", children: title }) : /* @__PURE__ */ jsx("span", { className: "mx-auto truncate text-xs font-semibold text-fg-secondary", children: title }))
26
+ ] }),
27
+ /* @__PURE__ */ jsx("div", { className: cn("relative overflow-hidden bg-surface-0", screen[kind]), children })
28
+ ] });
29
+ }
30
+
31
+ // src/step-showcase/step-showcase.tsx
32
+ import * as React from "react";
33
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
34
+ var FILL_CSS = ".kz-step-fill{transform-origin:left;animation:kz-step-fill var(--kz-step-ms,6000ms) linear forwards}@keyframes kz-step-fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}";
35
+ var REDUCED = "(prefers-reduced-motion: reduce)";
36
+ var noop = () => () => void 0;
37
+ var readReduced = () => Boolean(typeof window !== "undefined" && window.matchMedia?.(REDUCED).matches);
38
+ var subscribeReduced = (notify) => {
39
+ const q = window.matchMedia?.(REDUCED);
40
+ q?.addEventListener?.("change", notify);
41
+ return () => q?.removeEventListener?.("change", notify);
42
+ };
43
+ var stepShowcaseLabels = {
44
+ play: "Play the steps",
45
+ pause: "Pause the steps",
46
+ step: (n, total) => `Step ${n} of ${total}`
47
+ };
48
+ function StepShowcase({ label, steps, device, deviceTitle, autoplay = true, labels = stepShowcaseLabels, defaultIndex = 0, onIndexChange, className, ...props }) {
49
+ const total = steps.length;
50
+ const id = React.useId();
51
+ const root = React.useRef(null);
52
+ const video = React.useRef(null);
53
+ const bar = React.useRef(null);
54
+ const swipe = React.useRef(null);
55
+ const [index, setIndex] = React.useState(defaultIndex);
56
+ const [paused, setPaused] = React.useState(false);
57
+ const [hold, setHold] = React.useState({ hover: false, focus: false });
58
+ const [inView, setInView] = React.useState(false);
59
+ const [seen, setSeen] = React.useState(false);
60
+ const reduced = React.useSyncExternalStore(subscribeReduced, readReduced, () => false);
61
+ const mounted = React.useSyncExternalStore(noop, () => true, () => false);
62
+ const current = steps[Math.min(index, total - 1)];
63
+ const auto = autoplay && !reduced && mounted;
64
+ const running = auto && !paused && !hold.hover && !hold.focus && inView;
65
+ React.useEffect(() => {
66
+ const host = root.current;
67
+ if (!host || typeof IntersectionObserver === "undefined") return;
68
+ const io = new IntersectionObserver((e) => {
69
+ const visible = e.some((x) => x.isIntersecting);
70
+ setInView(visible);
71
+ if (visible) setSeen(true);
72
+ }, { threshold: 0.35 });
73
+ io.observe(host);
74
+ return () => io.disconnect();
75
+ }, []);
76
+ const go = React.useCallback(
77
+ (to, user) => {
78
+ const next = (to + total) % total;
79
+ setIndex(next);
80
+ if (bar.current) bar.current.style.transform = "scaleX(0)";
81
+ onIndexChange?.(next, user);
82
+ },
83
+ [total, onIndexChange]
84
+ );
85
+ React.useEffect(() => {
86
+ const v = video.current;
87
+ if (!v) return;
88
+ if (running) v.play()?.catch?.(() => void 0);
89
+ else v.pause();
90
+ }, [running, index, seen]);
91
+ const playable = Boolean(current?.video) && seen && !reduced;
92
+ const onTime = (e) => {
93
+ const v = e.currentTarget;
94
+ if (bar.current && v.duration) bar.current.style.transform = `scaleX(${v.currentTime / v.duration})`;
95
+ };
96
+ return /* @__PURE__ */ jsxs2(
97
+ "section",
98
+ {
99
+ ref: root,
100
+ "aria-roledescription": "carousel",
101
+ "aria-label": label,
102
+ className: cn("grid items-center gap-6 md:grid-cols-[minmax(0,20rem)_minmax(0,1fr)] md:gap-10", className),
103
+ onPointerEnter: () => setHold((h) => ({ ...h, hover: true })),
104
+ onPointerLeave: () => setHold((h) => ({ ...h, hover: false })),
105
+ onFocus: () => setHold((h) => ({ ...h, focus: true })),
106
+ onBlur: (e) => {
107
+ if (!e.currentTarget.contains(e.relatedTarget)) setHold((h) => ({ ...h, focus: false }));
108
+ },
109
+ ...props,
110
+ children: [
111
+ /* @__PURE__ */ jsx2("style", { href: "kz-step-showcase", precedence: "medium", children: FILL_CSS }),
112
+ /* @__PURE__ */ jsxs2("div", { className: "order-2 grid gap-3 md:order-1", children: [
113
+ /* @__PURE__ */ jsx2("div", { role: "tablist", "aria-orientation": "vertical", "aria-label": label, className: "flex justify-center gap-2 md:grid md:gap-1", children: steps.map((s, i) => {
114
+ const active = i === index;
115
+ return /* @__PURE__ */ jsxs2(
116
+ "button",
117
+ {
118
+ type: "button",
119
+ role: "tab",
120
+ id: `${id}-tab-${i}`,
121
+ "aria-selected": active,
122
+ "aria-controls": `${id}-panel`,
123
+ tabIndex: active ? 0 : -1,
124
+ onClick: () => go(i, true),
125
+ onKeyDown: (e) => {
126
+ if (e.key === "ArrowDown" || e.key === "ArrowRight") go(i + 1, true);
127
+ else if (e.key === "ArrowUp" || e.key === "ArrowLeft") go(i - 1, true);
128
+ else return;
129
+ e.preventDefault();
130
+ },
131
+ className: cn(
132
+ "group relative rounded-xl text-left outline-hidden transition-colors focus-visible:ring-2 focus-visible:ring-ring",
133
+ "max-md:h-2.5 max-md:w-2.5 max-md:rounded-full max-md:bg-border-strong max-md:aria-selected:w-6 max-md:aria-selected:bg-accent",
134
+ "md:overflow-hidden md:p-4 md:hover:bg-surface-2 md:aria-selected:bg-surface-2"
135
+ ),
136
+ children: [
137
+ /* @__PURE__ */ jsxs2("span", { className: "max-md:sr-only", children: [
138
+ /* @__PURE__ */ jsxs2("span", { className: "flex items-baseline gap-3", children: [
139
+ /* @__PURE__ */ jsx2("span", { className: cn("font-mono text-xs", active ? "text-fg-accent" : "text-fg-secondary"), children: String(i + 1).padStart(2, "0") }),
140
+ /* @__PURE__ */ jsx2("span", { className: cn("text-sm font-semibold", active ? "text-fg" : "text-fg-secondary"), children: s.title })
141
+ ] }),
142
+ /* @__PURE__ */ jsx2("span", { className: "mt-1 block pl-8 text-xs leading-relaxed text-fg-secondary", children: s.description })
143
+ ] }),
144
+ active && auto && /* @__PURE__ */ jsx2("span", { "aria-hidden": true, className: "absolute inset-x-4 bottom-0 hidden h-0.5 overflow-hidden rounded-full bg-border-subtle md:block", children: /* @__PURE__ */ jsx2(
145
+ "span",
146
+ {
147
+ ref: bar,
148
+ "data-fill": true,
149
+ className: cn("block h-full bg-accent", !playable && "kz-step-fill"),
150
+ style: { transform: playable ? "scaleX(0)" : void 0, animationPlayState: running ? "running" : "paused", ["--kz-step-ms"]: `${s.duration ?? 6e3}ms` },
151
+ onAnimationEnd: () => go(index + 1, false)
152
+ },
153
+ `${s.id}-${playable}`
154
+ ) })
155
+ ]
156
+ },
157
+ s.id
158
+ );
159
+ }) }),
160
+ /* @__PURE__ */ jsxs2("p", { "aria-hidden": true, className: "text-center text-sm md:hidden", children: [
161
+ /* @__PURE__ */ jsx2("span", { className: "font-semibold text-fg", children: current?.title }),
162
+ " ",
163
+ /* @__PURE__ */ jsx2("span", { className: "text-fg-secondary", children: current?.description })
164
+ ] }),
165
+ auto && /* @__PURE__ */ jsxs2("button", { type: "button", onClick: () => setPaused((p) => !p), "aria-pressed": paused, className: "mx-auto inline-flex h-8 items-center gap-2 rounded-full border border-border-subtle px-3 text-xs font-medium text-fg-secondary hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring md:mx-0 md:w-fit", children: [
166
+ /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 24 24", className: "h-3.5 w-3.5", fill: "currentColor", "aria-hidden": true, children: paused ? /* @__PURE__ */ jsx2("path", { d: "M8 5v14l11-7z" }) : /* @__PURE__ */ jsx2("path", { d: "M7 5h4v14H7zM13 5h4v14h-4z" }) }),
167
+ paused ? labels.play : labels.pause
168
+ ] })
169
+ ] }),
170
+ /* @__PURE__ */ jsxs2(
171
+ "div",
172
+ {
173
+ id: `${id}-panel`,
174
+ role: "tabpanel",
175
+ "aria-roledescription": "slide",
176
+ "aria-labelledby": `${id}-tab-${index}`,
177
+ className: "order-1 touch-pan-y md:order-2",
178
+ onPointerDown: (e) => {
179
+ swipe.current = e.clientX;
180
+ },
181
+ onPointerUp: (e) => {
182
+ if (swipe.current === null) return;
183
+ const dx = e.clientX - swipe.current;
184
+ swipe.current = null;
185
+ if (Math.abs(dx) > 40) go(index + (dx < 0 ? 1 : -1), true);
186
+ },
187
+ children: [
188
+ /* @__PURE__ */ jsx2(DeviceFrame, { kind: device, title: deviceTitle, children: steps.map((s, i) => {
189
+ const active = i === index;
190
+ return /* @__PURE__ */ jsxs2("div", { "data-step": s.id, "aria-hidden": !active, className: cn("absolute inset-0 transition-opacity duration-500 motion-reduce:transition-none", active ? "opacity-100" : "opacity-0"), children: [
191
+ /* @__PURE__ */ jsx2("img", { src: s.poster, alt: active ? s.alt : "", loading: i === 0 ? "eager" : "lazy", decoding: "async", className: "h-full w-full object-cover" }),
192
+ active && playable && s.video && /* @__PURE__ */ jsxs2(
193
+ "video",
194
+ {
195
+ ref: video,
196
+ muted: true,
197
+ playsInline: true,
198
+ preload: "metadata",
199
+ poster: s.poster,
200
+ "aria-hidden": true,
201
+ tabIndex: -1,
202
+ onTimeUpdate: onTime,
203
+ onEnded: () => go(index + 1, false),
204
+ className: "absolute inset-0 h-full w-full object-cover",
205
+ children: [
206
+ s.video.webm && /* @__PURE__ */ jsx2("source", { src: s.video.webm, type: "video/webm" }),
207
+ s.video.mp4 && /* @__PURE__ */ jsx2("source", { src: s.video.mp4, type: "video/mp4" })
208
+ ]
209
+ },
210
+ s.id
211
+ )
212
+ ] }, s.id);
213
+ }) }),
214
+ /* @__PURE__ */ jsx2("span", { className: "sr-only", "aria-live": "off", children: labels.step(index + 1, total) })
215
+ ]
216
+ }
217
+ )
218
+ ]
219
+ }
220
+ );
221
+ }
222
+ export {
223
+ DeviceFrame,
224
+ StepShowcase,
225
+ stepShowcaseLabels
226
+ };
227
+ //# sourceMappingURL=step-showcase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/step-showcase/device-frame.tsx","../src/step-showcase/step-showcase.tsx"],"sourcesContent":["// Server-safe. The frame a product's recording plays in: a phone, a browser window or a macOS window — drawn with the\n// tokens (no image), so it follows dark and light. The content fills the screen area (`object-cover` media).\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport type DeviceKind = \"phone\" | \"browser\" | \"desktop\";\n\nexport interface DeviceFrameProps extends React.ComponentProps<\"div\"> {\n /** The device: a phone, a browser window or a macOS window. */\n kind: DeviceKind;\n /** The browser's address or the window's title (“dev.orazaka.com”, “Orazaka”). */\n title?: string;\n}\n\nconst screen: Record<DeviceKind, string> = {\n phone: \"aspect-[9/19.5]\",\n browser: \"aspect-[16/10]\",\n desktop: \"aspect-[16/10]\",\n};\n\n/** A phone, a browser window or a macOS window around a screen of content. */\nexport function DeviceFrame({ kind, title, className, children, ...props }: DeviceFrameProps) {\n if (kind === \"phone\") {\n return (\n <div data-device=\"phone\" className={cn(\"relative mx-auto w-full max-w-[18rem] rounded-[2.4rem] border border-border-strong bg-surface-3 p-2 shadow-2xl\", className)} {...props}>\n <div className={cn(\"relative overflow-hidden rounded-[1.9rem] bg-surface-0\", screen.phone)}>\n {children}\n <span aria-hidden className=\"absolute left-1/2 top-2 h-5 w-20 -translate-x-1/2 rounded-full bg-surface-3\" />\n </div>\n </div>\n );\n }\n return (\n <div data-device={kind} className={cn(\"relative w-full overflow-hidden rounded-xl border border-border-default bg-surface-1 shadow-2xl\", className)} {...props}>\n <div className=\"flex h-8 items-center gap-1.5 border-b border-border-subtle bg-surface-2 px-3\">\n <span aria-hidden className=\"h-2.5 w-2.5 rounded-full bg-danger/80\" />\n <span aria-hidden className=\"h-2.5 w-2.5 rounded-full bg-warning/80\" />\n <span aria-hidden className=\"h-2.5 w-2.5 rounded-full bg-success/80\" />\n {title &&\n (kind === \"browser\" ? (\n <span className=\"mx-auto max-w-[60%] truncate rounded-md bg-surface-1 px-3 py-0.5 font-mono text-[11px] text-fg-secondary\">{title}</span>\n ) : (\n <span className=\"mx-auto truncate text-xs font-semibold text-fg-secondary\">{title}</span>\n ))}\n </div>\n <div className={cn(\"relative overflow-hidden bg-surface-0\", screen[kind])}>{children}</div>\n </div>\n );\n}\n","// Client (timers through the video, observers, swipe). A guided sequence in one device frame: the steps listed beside\n// it (a vertical tab list: number · title · one line, a bar filling under the current one), the frame playing the\n// step's recording muted, then moving on to the next; the recordings crossfade. It plays only while in view, holds on\n// hover and focus, keeps a visible play / pause button, and never shows a video's native controls. Recordings load\n// lazily (posters first, the current step's video once the block has been seen). Reduced motion: posters, manual steps.\n// Below `md` the list becomes dots under the frame, the frame swipes, the current step's words show under it.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { DeviceFrame, type DeviceKind } from \"./device-frame\";\n\nconst FILL_CSS = \".kz-step-fill{transform-origin:left;animation:kz-step-fill var(--kz-step-ms,6000ms) linear forwards}@keyframes kz-step-fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}\";\nconst REDUCED = \"(prefers-reduced-motion: reduce)\";\nconst noop = () => () => undefined;\nconst readReduced = () => Boolean(typeof window !== \"undefined\" && window.matchMedia?.(REDUCED).matches);\nconst subscribeReduced = (notify: () => void) => {\n const q = window.matchMedia?.(REDUCED);\n q?.addEventListener?.(\"change\", notify);\n return () => q?.removeEventListener?.(\"change\", notify);\n};\n\nexport interface ShowcaseStep {\n /** A stable key. */\n id: string;\n /** The step's name (“Make an image”), passed translated. */\n title: string;\n /** One line under it. */\n description: string;\n /** The still shown first, and the only picture under reduced motion. */\n poster: string;\n /** What the poster shows, for assistive technology. */\n alt: string;\n /** The recording: WebM and / or MP4. Without one, the poster stays `duration` ms. */\n video?: { webm?: string; mp4?: string };\n /** Milliseconds a step without a video stays. @default 6000 */\n duration?: number;\n}\n\nexport interface StepShowcaseLabels {\n /** The button's name while paused. */\n play: string;\n /** The button's name while it plays. */\n pause: string;\n /** A step's position in words: `(2, 4) => \"Step 2 of 4\"`. */\n step: (n: number, total: number) => string;\n}\n\nexport const stepShowcaseLabels: StepShowcaseLabels = {\n play: \"Play the steps\",\n pause: \"Pause the steps\",\n step: (n, total) => `Step ${n} of ${total}`,\n};\n\nexport interface StepShowcaseProps extends Omit<React.ComponentProps<\"section\">, \"children\"> {\n /** The sequence's accessible name (“Orazaka in your pocket”), passed translated. */\n label: string;\n /** The steps, in the order of the journey. */\n steps: readonly ShowcaseStep[];\n /** The device the recordings were made on. */\n device: DeviceKind;\n /** The browser's address or the window's title. */\n deviceTitle?: string;\n /** Moves on by itself (never under reduced motion). @default true */\n autoplay?: boolean;\n /** The controls' words, translated. */\n labels?: StepShowcaseLabels;\n /** The step shown first. @default 0 */\n defaultIndex?: number;\n /** Called when the step changes — `user` is true when the visitor asked for it. */\n onIndexChange?: (index: number, user: boolean) => void;\n}\n\n/** One device frame, its steps beside it, playing each recording then the next — a product's guided tour. */\nexport function StepShowcase({ label, steps, device, deviceTitle, autoplay = true, labels = stepShowcaseLabels, defaultIndex = 0, onIndexChange, className, ...props }: StepShowcaseProps) {\n const total = steps.length;\n const id = React.useId();\n const root = React.useRef<HTMLElement>(null);\n const video = React.useRef<HTMLVideoElement>(null);\n const bar = React.useRef<HTMLSpanElement>(null);\n const swipe = React.useRef<number | null>(null);\n const [index, setIndex] = React.useState(defaultIndex);\n const [paused, setPaused] = React.useState(false);\n const [hold, setHold] = React.useState({ hover: false, focus: false });\n const [inView, setInView] = React.useState(false);\n const [seen, setSeen] = React.useState(false);\n const reduced = React.useSyncExternalStore(subscribeReduced, readReduced, () => false);\n const mounted = React.useSyncExternalStore(noop, () => true, () => false);\n const current = steps[Math.min(index, total - 1)];\n const auto = autoplay && !reduced && mounted;\n const running = auto && !paused && !hold.hover && !hold.focus && inView;\n\n React.useEffect(() => {\n const host = root.current;\n if (!host || typeof IntersectionObserver === \"undefined\") return;\n const io = new IntersectionObserver((e) => {\n const visible = e.some((x) => x.isIntersecting);\n setInView(visible);\n if (visible) setSeen(true);\n }, { threshold: 0.35 });\n io.observe(host);\n return () => io.disconnect();\n }, []);\n\n const go = React.useCallback(\n (to: number, user: boolean) => {\n const next = (to + total) % total;\n setIndex(next);\n if (bar.current) bar.current.style.transform = \"scaleX(0)\";\n onIndexChange?.(next, user);\n },\n [total, onIndexChange],\n );\n\n // The recording runs only while the sequence does; its time is the bar.\n React.useEffect(() => {\n const v = video.current;\n if (!v) return;\n if (running) v.play()?.catch?.(() => undefined);\n else v.pause();\n }, [running, index, seen]);\n\n const playable = Boolean(current?.video) && seen && !reduced;\n const onTime = (e: React.SyntheticEvent<HTMLVideoElement>) => {\n const v = e.currentTarget;\n if (bar.current && v.duration) bar.current.style.transform = `scaleX(${v.currentTime / v.duration})`;\n };\n\n return (\n <section\n ref={root}\n aria-roledescription=\"carousel\"\n aria-label={label}\n className={cn(\"grid items-center gap-6 md:grid-cols-[minmax(0,20rem)_minmax(0,1fr)] md:gap-10\", className)}\n onPointerEnter={() => setHold((h) => ({ ...h, hover: true }))}\n onPointerLeave={() => setHold((h) => ({ ...h, hover: false }))}\n onFocus={() => setHold((h) => ({ ...h, focus: true }))}\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) setHold((h) => ({ ...h, focus: false }));\n }}\n {...props}\n >\n <style href=\"kz-step-showcase\" precedence=\"medium\">{FILL_CSS}</style>\n <div className=\"order-2 grid gap-3 md:order-1\">\n <div role=\"tablist\" aria-orientation=\"vertical\" aria-label={label} className=\"flex justify-center gap-2 md:grid md:gap-1\">\n {steps.map((s, i) => {\n const active = i === index;\n return (\n <button\n key={s.id}\n type=\"button\"\n role=\"tab\"\n id={`${id}-tab-${i}`}\n aria-selected={active}\n aria-controls={`${id}-panel`}\n tabIndex={active ? 0 : -1}\n onClick={() => go(i, true)}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") go(i + 1, true);\n else if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") go(i - 1, true);\n else return;\n e.preventDefault();\n }}\n className={cn(\n \"group relative rounded-xl text-left outline-hidden transition-colors focus-visible:ring-2 focus-visible:ring-ring\",\n \"max-md:h-2.5 max-md:w-2.5 max-md:rounded-full max-md:bg-border-strong max-md:aria-selected:w-6 max-md:aria-selected:bg-accent\",\n \"md:overflow-hidden md:p-4 md:hover:bg-surface-2 md:aria-selected:bg-surface-2\",\n )}\n >\n <span className=\"max-md:sr-only\">\n <span className=\"flex items-baseline gap-3\">\n <span className={cn(\"font-mono text-xs\", active ? \"text-fg-accent\" : \"text-fg-secondary\")}>{String(i + 1).padStart(2, \"0\")}</span>\n <span className={cn(\"text-sm font-semibold\", active ? \"text-fg\" : \"text-fg-secondary\")}>{s.title}</span>\n </span>\n <span className=\"mt-1 block pl-8 text-xs leading-relaxed text-fg-secondary\">{s.description}</span>\n </span>\n {active && auto && (\n <span aria-hidden className=\"absolute inset-x-4 bottom-0 hidden h-0.5 overflow-hidden rounded-full bg-border-subtle md:block\">\n <span\n key={`${s.id}-${playable}`}\n ref={bar}\n data-fill\n className={cn(\"block h-full bg-accent\", !playable && \"kz-step-fill\")}\n style={{ transform: playable ? \"scaleX(0)\" : undefined, animationPlayState: running ? \"running\" : \"paused\", [\"--kz-step-ms\" as string]: `${s.duration ?? 6000}ms` }}\n onAnimationEnd={() => go(index + 1, false)}\n />\n </span>\n )}\n </button>\n );\n })}\n </div>\n <p aria-hidden className=\"text-center text-sm md:hidden\">\n <span className=\"font-semibold text-fg\">{current?.title}</span> <span className=\"text-fg-secondary\">{current?.description}</span>\n </p>\n {auto && (\n <button type=\"button\" onClick={() => setPaused((p) => !p)} aria-pressed={paused} className=\"mx-auto inline-flex h-8 items-center gap-2 rounded-full border border-border-subtle px-3 text-xs font-medium text-fg-secondary hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring md:mx-0 md:w-fit\">\n <svg viewBox=\"0 0 24 24\" className=\"h-3.5 w-3.5\" fill=\"currentColor\" aria-hidden>\n {paused ? <path d=\"M8 5v14l11-7z\" /> : <path d=\"M7 5h4v14H7zM13 5h4v14h-4z\" />}\n </svg>\n {paused ? labels.play : labels.pause}\n </button>\n )}\n </div>\n\n <div\n id={`${id}-panel`}\n role=\"tabpanel\"\n aria-roledescription=\"slide\"\n aria-labelledby={`${id}-tab-${index}`}\n className=\"order-1 touch-pan-y md:order-2\"\n onPointerDown={(e) => {\n swipe.current = e.clientX;\n }}\n onPointerUp={(e) => {\n if (swipe.current === null) return;\n const dx = e.clientX - swipe.current;\n swipe.current = null;\n if (Math.abs(dx) > 40) go(index + (dx < 0 ? 1 : -1), true);\n }}\n >\n <DeviceFrame kind={device} title={deviceTitle}>\n {steps.map((s, i) => {\n const active = i === index;\n return (\n <div key={s.id} data-step={s.id} aria-hidden={!active} className={cn(\"absolute inset-0 transition-opacity duration-500 motion-reduce:transition-none\", active ? \"opacity-100\" : \"opacity-0\")}>\n <img src={s.poster} alt={active ? s.alt : \"\"} loading={i === 0 ? \"eager\" : \"lazy\"} decoding=\"async\" className=\"h-full w-full object-cover\" />\n {active && playable && s.video && (\n <video\n ref={video}\n key={s.id}\n muted\n playsInline\n preload=\"metadata\"\n poster={s.poster}\n aria-hidden\n tabIndex={-1}\n onTimeUpdate={onTime}\n onEnded={() => go(index + 1, false)}\n className=\"absolute inset-0 h-full w-full object-cover\"\n >\n {s.video.webm && <source src={s.video.webm} type=\"video/webm\" />}\n {s.video.mp4 && <source src={s.video.mp4} type=\"video/mp4\" />}\n </video>\n )}\n </div>\n );\n })}\n </DeviceFrame>\n <span className=\"sr-only\" aria-live=\"off\">\n {labels.step(index + 1, total)}\n </span>\n </div>\n </section>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
package/dist/tabs.js CHANGED
@@ -15,7 +15,7 @@ var tabs = tv({
15
15
  // (server render), each trigger carries its own active style.
16
16
  list: "group/tabs relative isolate flex shrink-0 data-[orientation=vertical]:flex-col before:pointer-events-none before:absolute before:-z-10 before:opacity-0 before:transition-[translate,width,height,opacity] before:duration-300 motion-reduce:before:transition-none data-[indicator=on]:before:opacity-100",
17
17
  trigger: "inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40",
18
- content: "kz-fade min-w-0 flex-1 rounded-lg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
18
+ content: "kz-fade min-w-0 flex-1 rounded-lg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-[state=inactive]:hidden"
19
19
  },
20
20
  variants: {
21
21
  variant: {
package/dist/tabs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tabs/tabs.tsx"],"sourcesContent":["// Client (a context). Radix Tabs does the roles (tablist, tab, tabpanel), the aria-selected / aria-controls wiring,\n// the roving focus (arrows, Home, End) and automatic activation: this file only holds the three looks.\nimport { Tabs as TabsPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { useSlidingIndicator } from \"../sliding-indicator\";\n\nexport const tabs = tv({\n slots: {\n root: \"flex gap-4 data-[orientation=horizontal]:flex-col data-[orientation=vertical]:flex-row\",\n // One light glides from the active tab to the next (`before:`, placed by useSlidingIndicator); until it is placed\n // (server render), each trigger carries its own active style.\n list:\n \"group/tabs relative isolate flex shrink-0 data-[orientation=vertical]:flex-col \" +\n \"before:pointer-events-none before:absolute before:-z-10 before:opacity-0 before:transition-[translate,width,height,opacity] before:duration-300 \" +\n \"motion-reduce:before:transition-none data-[indicator=on]:before:opacity-100\",\n trigger:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40\",\n content: \"kz-fade min-w-0 flex-1 rounded-lg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n variants: {\n variant: {\n /* The section of a page: a line under the list, the active tab underlined in the accent. */\n underline: {\n list:\n \"gap-1 border-border-default data-[orientation=horizontal]:border-b data-[orientation=vertical]:border-r before:rounded-full before:bg-accent \" +\n \"data-[orientation=horizontal]:before:-bottom-px data-[orientation=horizontal]:before:left-0 data-[orientation=horizontal]:before:h-0.5 \" +\n \"data-[orientation=horizontal]:before:w-(--kz-ind-w) data-[orientation=horizontal]:before:translate-x-(--kz-ind-x) \" +\n \"data-[orientation=vertical]:before:-right-px data-[orientation=vertical]:before:top-0 data-[orientation=vertical]:before:w-0.5 \" +\n \"data-[orientation=vertical]:before:h-(--kz-ind-h) data-[orientation=vertical]:before:translate-y-(--kz-ind-y)\",\n trigger:\n \"relative rounded-md px-3 py-2.5 text-sm text-fg-secondary hover:text-fg data-[state=active]:text-fg \" +\n \"after:absolute after:rounded-full after:bg-transparent data-[state=active]:after:bg-accent \" +\n \"data-[orientation=horizontal]:after:inset-x-2 data-[orientation=horizontal]:after:-bottom-px data-[orientation=horizontal]:after:h-0.5 \" +\n \"data-[orientation=vertical]:justify-start data-[orientation=vertical]:after:inset-y-1.5 data-[orientation=vertical]:after:-right-px data-[orientation=vertical]:after:w-0.5 \" +\n \"group-data-[indicator=on]/tabs:data-[state=active]:after:bg-transparent\",\n },\n /* A view switch: equal segments in a track, the active one filled. */\n segmented: {\n list:\n \"inline-grid auto-cols-fr grid-flow-col gap-1 self-start rounded-xl border border-border-default bg-surface-1 p-1 data-[orientation=vertical]:grid-flow-row \" +\n \"before:left-0 before:top-0 before:h-(--kz-ind-h) before:w-(--kz-ind-w) before:translate-x-(--kz-ind-x) before:translate-y-(--kz-ind-y) before:rounded-lg before:bg-accent before:shadow-sm\",\n trigger:\n \"min-h-8 rounded-lg px-3 py-1.5 text-xs text-fg-secondary hover:bg-surface-2 hover:text-fg \" +\n \"data-[state=active]:bg-accent data-[state=active]:text-on-accent data-[state=active]:shadow-sm data-[state=active]:hover:bg-accent \" +\n \"transition-colors group-data-[indicator=on]/tabs:data-[state=active]:bg-transparent group-data-[indicator=on]/tabs:data-[state=active]:shadow-none\",\n },\n /* Pills that scroll sideways on a phone: a feed's sections. */\n pills: {\n list:\n \"gap-1.5 overflow-x-auto overflow-y-hidden overscroll-x-contain pt-1 -mt-1 pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden \" +\n \"before:left-0 before:top-0 before:h-(--kz-ind-h) before:w-(--kz-ind-w) before:translate-x-(--kz-ind-x) before:translate-y-(--kz-ind-y) \" +\n \"before:rounded-full before:border before:border-accent before:bg-accent-soft\",\n trigger:\n \"h-9 rounded-full border border-border-default bg-surface-1 px-4 text-xs text-fg-secondary hover:border-border-strong hover:text-fg \" +\n \"data-[state=active]:border-accent data-[state=active]:bg-accent-soft data-[state=active]:text-fg \" +\n \"group-data-[indicator=on]/tabs:data-[state=active]:border-transparent group-data-[indicator=on]/tabs:data-[state=active]:bg-transparent\",\n },\n },\n },\n defaultVariants: { variant: \"underline\" },\n});\n\nexport type TabsVariants = VariantProps<typeof tabs>;\ntype Variant = NonNullable<TabsVariants[\"variant\"]>;\n\nconst VariantContext = React.createContext<Variant>(\"underline\");\n\nexport type TabsRootProps = React.ComponentProps<typeof TabsPrimitive.Root> & {\n /** underline (the sections of a page) · segmented (a view switch) · pills (a feed's sections). */\n variant?: TabsVariants[\"variant\"];\n};\n\n/** `value`/`defaultValue` + `onValueChange`, `orientation` (horizontal by default), `variant` for the list. */\nexport function TabsRoot({ variant = \"underline\", className, ...props }: TabsRootProps) {\n return (\n <VariantContext.Provider value={variant}>\n <TabsPrimitive.Root data-variant={variant} className={tabs({ variant }).root({ className })} {...props} />\n </VariantContext.Provider>\n );\n}\n\n/** The tabs. Name it (`aria-label`) when no heading says what it switches. One light glides to the active tab. */\nexport function TabsList({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {\n const variant = React.useContext(VariantContext);\n const { ref } = useSlidingIndicator<HTMLDivElement>({ item: \"[role=tab]\", active: \"[role=tab][data-state=active]\" });\n return <TabsPrimitive.List ref={ref} data-variant={variant} className={tabs({ variant }).list({ className })} {...props} />;\n}\n\nexport function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n const variant = React.useContext(VariantContext);\n return <TabsPrimitive.Trigger className={tabs({ variant }).trigger({ className })} {...props} />;\n}\n\nexport function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>) {\n return <TabsPrimitive.Content className={tabs().content({ className })} {...props} />;\n}\n\n/** `Tabs.Root/List/Trigger/Content` — `variant` underline · segmented · pills on the root. */\nexport const Tabs = { Root: TabsRoot, List: TabsList, Trigger: TabsTrigger, Content: TabsContent };\n"],"mappings":";;;;;;AAEA,SAAS,QAAQ,qBAAqB;AACtC,YAAY,WAAW;AACvB,SAAS,UAA6B;AA2EhC;AAvEC,IAAM,OAAO,GAAG;AAAA,EACrB,OAAO;AAAA,IACL,MAAM;AAAA;AAAA;AAAA,IAGN,MACE;AAAA,IAGF,SACE;AAAA,IAEF,SAAS;AAAA,EACX;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA;AAAA,MAEP,WAAW;AAAA,QACT,MACE;AAAA,QAKF,SACE;AAAA,MAKJ;AAAA;AAAA,MAEA,WAAW;AAAA,QACT,MACE;AAAA,QAEF,SACE;AAAA,MAGJ;AAAA;AAAA,MAEA,OAAO;AAAA,QACL,MACE;AAAA,QAGF,SACE;AAAA,MAGJ;AAAA,IACF;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,SAAS,YAAY;AAC1C,CAAC;AAKD,IAAM,iBAAuB,oBAAuB,WAAW;AAQxD,SAAS,SAAS,EAAE,UAAU,aAAa,WAAW,GAAG,MAAM,GAAkB;AACtF,SACE,oBAAC,eAAe,UAAf,EAAwB,OAAO,SAC9B,8BAAC,cAAc,MAAd,EAAmB,gBAAc,SAAS,WAAW,KAAK,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO,GAC1G;AAEJ;AAGO,SAAS,SAAS,EAAE,WAAW,GAAG,MAAM,GAAoD;AACjG,QAAM,UAAgB,iBAAW,cAAc;AAC/C,QAAM,EAAE,IAAI,IAAI,oBAAoC,EAAE,MAAM,cAAc,QAAQ,gCAAgC,CAAC;AACnH,SAAO,oBAAC,cAAc,MAAd,EAAmB,KAAU,gBAAc,SAAS,WAAW,KAAK,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AAC3H;AAEO,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAuD;AACvG,QAAM,UAAgB,iBAAW,cAAc;AAC/C,SAAO,oBAAC,cAAc,SAAd,EAAsB,WAAW,KAAK,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AAChG;AAEO,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAuD;AACvG,SAAO,oBAAC,cAAc,SAAd,EAAsB,WAAW,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AACrF;AAGO,IAAM,OAAO,EAAE,MAAM,UAAU,MAAM,UAAU,SAAS,aAAa,SAAS,YAAY;","names":[]}
1
+ {"version":3,"sources":["../src/tabs/tabs.tsx"],"sourcesContent":["// Client (a context). Radix Tabs does the roles (tablist, tab, tabpanel), the aria-selected / aria-controls wiring,\n// the roving focus (arrows, Home, End) and automatic activation: this file only holds the three looks.\nimport { Tabs as TabsPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { useSlidingIndicator } from \"../sliding-indicator\";\n\nexport const tabs = tv({\n slots: {\n root: \"flex gap-4 data-[orientation=horizontal]:flex-col data-[orientation=vertical]:flex-row\",\n // One light glides from the active tab to the next (`before:`, placed by useSlidingIndicator); until it is placed\n // (server render), each trigger carries its own active style.\n list:\n \"group/tabs relative isolate flex shrink-0 data-[orientation=vertical]:flex-col \" +\n \"before:pointer-events-none before:absolute before:-z-10 before:opacity-0 before:transition-[translate,width,height,opacity] before:duration-300 \" +\n \"motion-reduce:before:transition-none data-[indicator=on]:before:opacity-100\",\n trigger:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40\",\n content: \"kz-fade min-w-0 flex-1 rounded-lg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-[state=inactive]:hidden\",\n },\n variants: {\n variant: {\n /* The section of a page: a line under the list, the active tab underlined in the accent. */\n underline: {\n list:\n \"gap-1 border-border-default data-[orientation=horizontal]:border-b data-[orientation=vertical]:border-r before:rounded-full before:bg-accent \" +\n \"data-[orientation=horizontal]:before:-bottom-px data-[orientation=horizontal]:before:left-0 data-[orientation=horizontal]:before:h-0.5 \" +\n \"data-[orientation=horizontal]:before:w-(--kz-ind-w) data-[orientation=horizontal]:before:translate-x-(--kz-ind-x) \" +\n \"data-[orientation=vertical]:before:-right-px data-[orientation=vertical]:before:top-0 data-[orientation=vertical]:before:w-0.5 \" +\n \"data-[orientation=vertical]:before:h-(--kz-ind-h) data-[orientation=vertical]:before:translate-y-(--kz-ind-y)\",\n trigger:\n \"relative rounded-md px-3 py-2.5 text-sm text-fg-secondary hover:text-fg data-[state=active]:text-fg \" +\n \"after:absolute after:rounded-full after:bg-transparent data-[state=active]:after:bg-accent \" +\n \"data-[orientation=horizontal]:after:inset-x-2 data-[orientation=horizontal]:after:-bottom-px data-[orientation=horizontal]:after:h-0.5 \" +\n \"data-[orientation=vertical]:justify-start data-[orientation=vertical]:after:inset-y-1.5 data-[orientation=vertical]:after:-right-px data-[orientation=vertical]:after:w-0.5 \" +\n \"group-data-[indicator=on]/tabs:data-[state=active]:after:bg-transparent\",\n },\n /* A view switch: equal segments in a track, the active one filled. */\n segmented: {\n list:\n \"inline-grid auto-cols-fr grid-flow-col gap-1 self-start rounded-xl border border-border-default bg-surface-1 p-1 data-[orientation=vertical]:grid-flow-row \" +\n \"before:left-0 before:top-0 before:h-(--kz-ind-h) before:w-(--kz-ind-w) before:translate-x-(--kz-ind-x) before:translate-y-(--kz-ind-y) before:rounded-lg before:bg-accent before:shadow-sm\",\n trigger:\n \"min-h-8 rounded-lg px-3 py-1.5 text-xs text-fg-secondary hover:bg-surface-2 hover:text-fg \" +\n \"data-[state=active]:bg-accent data-[state=active]:text-on-accent data-[state=active]:shadow-sm data-[state=active]:hover:bg-accent \" +\n \"transition-colors group-data-[indicator=on]/tabs:data-[state=active]:bg-transparent group-data-[indicator=on]/tabs:data-[state=active]:shadow-none\",\n },\n /* Pills that scroll sideways on a phone: a feed's sections. */\n pills: {\n list:\n \"gap-1.5 overflow-x-auto overflow-y-hidden overscroll-x-contain pt-1 -mt-1 pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden \" +\n \"before:left-0 before:top-0 before:h-(--kz-ind-h) before:w-(--kz-ind-w) before:translate-x-(--kz-ind-x) before:translate-y-(--kz-ind-y) \" +\n \"before:rounded-full before:border before:border-accent before:bg-accent-soft\",\n trigger:\n \"h-9 rounded-full border border-border-default bg-surface-1 px-4 text-xs text-fg-secondary hover:border-border-strong hover:text-fg \" +\n \"data-[state=active]:border-accent data-[state=active]:bg-accent-soft data-[state=active]:text-fg \" +\n \"group-data-[indicator=on]/tabs:data-[state=active]:border-transparent group-data-[indicator=on]/tabs:data-[state=active]:bg-transparent\",\n },\n },\n },\n defaultVariants: { variant: \"underline\" },\n});\n\nexport type TabsVariants = VariantProps<typeof tabs>;\ntype Variant = NonNullable<TabsVariants[\"variant\"]>;\n\nconst VariantContext = React.createContext<Variant>(\"underline\");\n\nexport type TabsRootProps = React.ComponentProps<typeof TabsPrimitive.Root> & {\n /** underline (the sections of a page) · segmented (a view switch) · pills (a feed's sections). */\n variant?: TabsVariants[\"variant\"];\n};\n\n/** `value`/`defaultValue` + `onValueChange`, `orientation` (horizontal by default), `variant` for the list. */\nexport function TabsRoot({ variant = \"underline\", className, ...props }: TabsRootProps) {\n return (\n <VariantContext.Provider value={variant}>\n <TabsPrimitive.Root data-variant={variant} className={tabs({ variant }).root({ className })} {...props} />\n </VariantContext.Provider>\n );\n}\n\n/** The tabs. Name it (`aria-label`) when no heading says what it switches. One light glides to the active tab. */\nexport function TabsList({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {\n const variant = React.useContext(VariantContext);\n const { ref } = useSlidingIndicator<HTMLDivElement>({ item: \"[role=tab]\", active: \"[role=tab][data-state=active]\" });\n return <TabsPrimitive.List ref={ref} data-variant={variant} className={tabs({ variant }).list({ className })} {...props} />;\n}\n\nexport function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n const variant = React.useContext(VariantContext);\n return <TabsPrimitive.Trigger className={tabs({ variant }).trigger({ className })} {...props} />;\n}\n\nexport function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>) {\n return <TabsPrimitive.Content className={tabs().content({ className })} {...props} />;\n}\n\n/** `Tabs.Root/List/Trigger/Content` — `variant` underline · segmented · pills on the root. */\nexport const Tabs = { Root: TabsRoot, List: TabsList, Trigger: TabsTrigger, Content: TabsContent };\n"],"mappings":";;;;;;AAEA,SAAS,QAAQ,qBAAqB;AACtC,YAAY,WAAW;AACvB,SAAS,UAA6B;AA2EhC;AAvEC,IAAM,OAAO,GAAG;AAAA,EACrB,OAAO;AAAA,IACL,MAAM;AAAA;AAAA;AAAA,IAGN,MACE;AAAA,IAGF,SACE;AAAA,IAEF,SAAS;AAAA,EACX;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA;AAAA,MAEP,WAAW;AAAA,QACT,MACE;AAAA,QAKF,SACE;AAAA,MAKJ;AAAA;AAAA,MAEA,WAAW;AAAA,QACT,MACE;AAAA,QAEF,SACE;AAAA,MAGJ;AAAA;AAAA,MAEA,OAAO;AAAA,QACL,MACE;AAAA,QAGF,SACE;AAAA,MAGJ;AAAA,IACF;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,SAAS,YAAY;AAC1C,CAAC;AAKD,IAAM,iBAAuB,oBAAuB,WAAW;AAQxD,SAAS,SAAS,EAAE,UAAU,aAAa,WAAW,GAAG,MAAM,GAAkB;AACtF,SACE,oBAAC,eAAe,UAAf,EAAwB,OAAO,SAC9B,8BAAC,cAAc,MAAd,EAAmB,gBAAc,SAAS,WAAW,KAAK,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO,GAC1G;AAEJ;AAGO,SAAS,SAAS,EAAE,WAAW,GAAG,MAAM,GAAoD;AACjG,QAAM,UAAgB,iBAAW,cAAc;AAC/C,QAAM,EAAE,IAAI,IAAI,oBAAoC,EAAE,MAAM,cAAc,QAAQ,gCAAgC,CAAC;AACnH,SAAO,oBAAC,cAAc,MAAd,EAAmB,KAAU,gBAAc,SAAS,WAAW,KAAK,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AAC3H;AAEO,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAuD;AACvG,QAAM,UAAgB,iBAAW,cAAc;AAC/C,SAAO,oBAAC,cAAc,SAAd,EAAsB,WAAW,KAAK,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AAChG;AAEO,SAAS,YAAY,EAAE,WAAW,GAAG,MAAM,GAAuD;AACvG,SAAO,oBAAC,cAAc,SAAd,EAAsB,WAAW,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AACrF;AAGO,IAAM,OAAO,EAAE,MAAM,UAAU,MAAM,UAAU,SAAS,aAAa,SAAS,YAAY;","names":[]}
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-KDXRYUD3.js";
8
8
  import {
9
9
  cn
10
- } from "./chunk-2FRWNSRO.js";
10
+ } from "./chunk-NSLXEDIS.js";
11
11
 
12
12
  // src/terminal-replay/terminal-replay.tsx
13
13
  import * as React from "react";
package/dist/theme.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import {
3
3
  buttonVariants
4
- } from "./chunk-OWC2LZD2.js";
4
+ } from "./chunk-CHOJUCVE.js";
5
5
  import "./chunk-D3T54RSL.js";
6
6
  import "./chunk-WEVYKZIF.js";
7
+ import "./chunk-NSLXEDIS.js";
7
8
 
8
9
  // src/theme/theme.tsx
9
10
  import * as React from "react";
package/dist/theme.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme/theme.tsx"],"sourcesContent":["// Client. ONE mechanism for the whole organisation: dark by default, `html.light` for light, `html.theme-<name>` for a\n// named theme, persisted in localStorage (`kz-theme` for the mode, `kz-theme-name` for the named theme).\nimport * as React from \"react\";\n\nimport { type ButtonVariants, buttonVariants } from \"../button/button\";\n\nexport type Mode = \"dark\" | \"light\" | \"system\";\n\nconst MODE_KEY = \"kz-theme\";\nconst NAME_KEY = \"kz-theme-name\";\nconst MODES: readonly Mode[] = [\"dark\", \"light\", \"system\"];\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\nconst isMode = (value: unknown): value is Mode => MODES.includes(value as Mode);\n\n// Storage blocked (private mode, sandbox): the choice lives in memory for the page.\nconst memory = new Map<string, string>();\n\nfunction read(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return memory.get(key) ?? null;\n }\n}\n\nfunction write(key: string, value: string | null) {\n if (value === null) memory.delete(key);\n else memory.set(key, value);\n try {\n if (value === null) localStorage.removeItem(key);\n else localStorage.setItem(key, value);\n } catch {\n // storage blocked: memory holds it\n }\n}\n\n// The persisted choice is an external store: every provider and tab reads the same value, the server reads none.\nconst listeners = new Set<() => void>();\nconst notify = () => listeners.forEach((listener) => listener());\nfunction subscribe(listener: () => void) {\n listeners.add(listener);\n window.addEventListener(\"storage\", listener);\n return () => {\n listeners.delete(listener);\n window.removeEventListener(\"storage\", listener);\n };\n}\n\nfunction applyMode(mode: Mode) {\n const dark = window.matchMedia(DARK_QUERY).matches;\n document.documentElement.classList.toggle(\"light\", mode === \"light\" || (mode === \"system\" && !dark));\n}\n\nfunction applyName(previous: string | null, next: string | null) {\n const classes = document.documentElement.classList;\n if (previous) classes.remove(`theme-${previous}`);\n if (next) classes.add(`theme-${next}`);\n}\n\nexport type ThemeScriptProps = {\n /** The nonce of a strict Content-Security-Policy (`script-src 'nonce-…'`). */\n nonce?: string;\n /**\n * The mode before the visitor chooses one — pass the same value as `ThemeProvider`'s `defaultMode`. A persisted\n * choice (`kz-theme`) always wins.\n * @default \"system\"\n */\n defaultMode?: Mode;\n};\n\n/**\n * In <head>, before anything renders: applies the persisted mode (else `defaultMode`) and named theme, so the page\n * never flashes. `nonce` for a strict Content-Security-Policy.\n */\nexport function ThemeScript({ nonce, defaultMode = \"system\" }: ThemeScriptProps) {\n const fallback = isMode(defaultMode) ? defaultMode : \"system\";\n const js =\n `(function(){try{var m=localStorage.getItem(\"${MODE_KEY}\");if(m!==\"dark\"&&m!==\"light\"&&m!==\"system\")m=\"${fallback}\";` +\n `var n=localStorage.getItem(\"${NAME_KEY}\");var d=matchMedia(\"${DARK_QUERY}\").matches;var c=document.documentElement.classList;` +\n `c.toggle(\"light\",m===\"light\"||(m===\"system\"&&!d));if(n)c.add(\"theme-\"+n)}catch(e){}})()`;\n return <script nonce={nonce} dangerouslySetInnerHTML={{ __html: js }} />;\n}\n\nexport type ThemeContextValue = {\n /** The chosen mode: dark, light or follow the system. */\n mode: Mode;\n setMode: (mode: Mode) => void;\n /** The named theme (`html.theme-<name>`), or null. */\n theme: string | null;\n setTheme: (theme: string | null) => void;\n};\n\nconst ThemeContext = React.createContext<ThemeContextValue | null>(null);\n\nexport type ThemeProviderProps = {\n children: React.ReactNode;\n /**\n * The mode before the visitor chooses one (nothing persisted as `kz-theme`) — pass the same value to `ThemeScript`.\n * @default \"system\"\n */\n defaultMode?: Mode;\n};\n\nexport function ThemeProvider({ children, defaultMode = \"system\" }: ThemeProviderProps) {\n // Before hydration the server knows nothing persisted (ThemeScript has already applied it to <html>).\n const stored = React.useSyncExternalStore(subscribe, () => read(MODE_KEY), () => null);\n const mode: Mode = isMode(stored) ? stored : defaultMode;\n const theme = React.useSyncExternalStore(subscribe, () => read(NAME_KEY), () => null);\n\n // The same resolution as ThemeScript (a no-op after it), for an app that renders the provider without the script.\n React.useEffect(() => {\n const persisted = read(MODE_KEY);\n applyMode(isMode(persisted) ? persisted : defaultMode);\n }, [defaultMode]);\n\n // \"system\" follows the operating system while the page is open.\n React.useEffect(() => {\n if (mode !== \"system\") return;\n const query = window.matchMedia(DARK_QUERY);\n const onChange = () => applyMode(\"system\");\n query.addEventListener?.(\"change\", onChange);\n return () => query.removeEventListener?.(\"change\", onChange);\n }, [mode]);\n\n const setMode = React.useCallback((next: Mode) => {\n write(MODE_KEY, next);\n applyMode(next);\n notify();\n }, []);\n\n const setTheme = React.useCallback((next: string | null) => {\n applyName(read(NAME_KEY), next);\n write(NAME_KEY, next);\n notify();\n }, []);\n\n const value = React.useMemo(() => ({ mode, setMode, theme, setTheme }), [mode, setMode, theme, setTheme]);\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = React.useContext(ThemeContext);\n if (!context) throw new Error(\"useTheme: wrap the app in <ThemeProvider>\");\n return context;\n}\n\nconst ICONS: Record<Mode, React.ReactNode> = {\n dark: <path d=\"M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5Z\" />,\n light: (\n <>\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4\" />\n </>\n ),\n system: (\n <>\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"12\" rx=\"2\" />\n <path d=\"M8 20h8M12 16v4\" />\n </>\n ),\n};\n\nexport type ThemeToggleProps = Omit<React.ComponentProps<\"button\">, \"onClick\" | \"children\"> &\n Pick<ButtonVariants, \"variant\" | \"shape\"> & {\n /** Any `Button` variant. */\n variant?: ButtonVariants[\"variant\"];\n /**\n * rounded · pill.\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** The accessible name — a string, or one per current mode (e.g. `(mode) => t(\"theme.\" + mode)`). */\n label: string | ((mode: Mode) => string);\n };\n\n/**\n * An icon button (styled as `IconButton`, without its Slot) that cycles dark → light → system. Needs a\n * <ThemeProvider> above it. State: `data-mode`.\n */\nexport function ThemeToggle({ label, variant = \"ghost\", shape, className, ...props }: ThemeToggleProps) {\n const { mode, setMode } = useTheme();\n const next = MODES[(MODES.indexOf(mode) + 1) % MODES.length] as Mode;\n const name = typeof label === \"function\" ? label(mode) : label;\n return (\n <button\n type=\"button\"\n aria-label={name}\n title={name}\n data-mode={mode}\n onClick={() => setMode(next)}\n className={buttonVariants({ variant, shape, size: \"icon\", className })}\n {...props}\n >\n <svg viewBox=\"0 0 24 24\" className=\"h-5 w-5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n {ICONS[mode]}\n </svg>\n </button>\n );\n}\n"],"mappings":";;;;;;;;AAEA,YAAY,WAAW;AA+Ed,SAqEL,UArEK,KAqEL,YArEK;AAzET,IAAM,WAAW;AACjB,IAAM,WAAW;AACjB,IAAM,QAAyB,CAAC,QAAQ,SAAS,QAAQ;AACzD,IAAM,aAAa;AAEnB,IAAM,SAAS,CAAC,UAAkC,MAAM,SAAS,KAAa;AAG9E,IAAM,SAAS,oBAAI,IAAoB;AAEvC,SAAS,KAAK,KAA4B;AACxC,MAAI;AACF,WAAO,aAAa,QAAQ,GAAG;AAAA,EACjC,QAAQ;AACN,WAAO,OAAO,IAAI,GAAG,KAAK;AAAA,EAC5B;AACF;AAEA,SAAS,MAAM,KAAa,OAAsB;AAChD,MAAI,UAAU,KAAM,QAAO,OAAO,GAAG;AAAA,MAChC,QAAO,IAAI,KAAK,KAAK;AAC1B,MAAI;AACF,QAAI,UAAU,KAAM,cAAa,WAAW,GAAG;AAAA,QAC1C,cAAa,QAAQ,KAAK,KAAK;AAAA,EACtC,QAAQ;AAAA,EAER;AACF;AAGA,IAAM,YAAY,oBAAI,IAAgB;AACtC,IAAM,SAAS,MAAM,UAAU,QAAQ,CAAC,aAAa,SAAS,CAAC;AAC/D,SAAS,UAAU,UAAsB;AACvC,YAAU,IAAI,QAAQ;AACtB,SAAO,iBAAiB,WAAW,QAAQ;AAC3C,SAAO,MAAM;AACX,cAAU,OAAO,QAAQ;AACzB,WAAO,oBAAoB,WAAW,QAAQ;AAAA,EAChD;AACF;AAEA,SAAS,UAAU,MAAY;AAC7B,QAAM,OAAO,OAAO,WAAW,UAAU,EAAE;AAC3C,WAAS,gBAAgB,UAAU,OAAO,SAAS,SAAS,WAAY,SAAS,YAAY,CAAC,IAAK;AACrG;AAEA,SAAS,UAAU,UAAyB,MAAqB;AAC/D,QAAM,UAAU,SAAS,gBAAgB;AACzC,MAAI,SAAU,SAAQ,OAAO,SAAS,QAAQ,EAAE;AAChD,MAAI,KAAM,SAAQ,IAAI,SAAS,IAAI,EAAE;AACvC;AAiBO,SAAS,YAAY,EAAE,OAAO,cAAc,SAAS,GAAqB;AAC/E,QAAM,WAAW,OAAO,WAAW,IAAI,cAAc;AACrD,QAAM,KACJ,+CAA+C,QAAQ,kDAAkD,QAAQ,iCAClF,QAAQ,wBAAwB,UAAU;AAE3E,SAAO,oBAAC,YAAO,OAAc,yBAAyB,EAAE,QAAQ,GAAG,GAAG;AACxE;AAWA,IAAM,eAAqB,oBAAwC,IAAI;AAWhE,SAAS,cAAc,EAAE,UAAU,cAAc,SAAS,GAAuB;AAEtF,QAAM,SAAe,2BAAqB,WAAW,MAAM,KAAK,QAAQ,GAAG,MAAM,IAAI;AACrF,QAAM,OAAa,OAAO,MAAM,IAAI,SAAS;AAC7C,QAAM,QAAc,2BAAqB,WAAW,MAAM,KAAK,QAAQ,GAAG,MAAM,IAAI;AAGpF,EAAM,gBAAU,MAAM;AACpB,UAAM,YAAY,KAAK,QAAQ;AAC/B,cAAU,OAAO,SAAS,IAAI,YAAY,WAAW;AAAA,EACvD,GAAG,CAAC,WAAW,CAAC;AAGhB,EAAM,gBAAU,MAAM;AACpB,QAAI,SAAS,SAAU;AACvB,UAAM,QAAQ,OAAO,WAAW,UAAU;AAC1C,UAAM,WAAW,MAAM,UAAU,QAAQ;AACzC,UAAM,mBAAmB,UAAU,QAAQ;AAC3C,WAAO,MAAM,MAAM,sBAAsB,UAAU,QAAQ;AAAA,EAC7D,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,UAAgB,kBAAY,CAAC,SAAe;AAChD,UAAM,UAAU,IAAI;AACpB,cAAU,IAAI;AACd,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,WAAiB,kBAAY,CAAC,SAAwB;AAC1D,cAAU,KAAK,QAAQ,GAAG,IAAI;AAC9B,UAAM,UAAU,IAAI;AACpB,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,QAAc,cAAQ,OAAO,EAAE,MAAM,SAAS,OAAO,SAAS,IAAI,CAAC,MAAM,SAAS,OAAO,QAAQ,CAAC;AACxG,SAAO,oBAAC,aAAa,UAAb,EAAsB,OAAe,UAAS;AACxD;AAEO,SAAS,WAA8B;AAC5C,QAAM,UAAgB,iBAAW,YAAY;AAC7C,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,2CAA2C;AACzE,SAAO;AACT;AAEA,IAAM,QAAuC;AAAA,EAC3C,MAAM,oBAAC,UAAK,GAAE,iDAAgD;AAAA,EAC9D,OACE,iCACE;AAAA,wBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,IAC9B,oBAAC,UAAK,GAAE,sGAAqG;AAAA,KAC/G;AAAA,EAEF,QACE,iCACE;AAAA,wBAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,IAChD,oBAAC,UAAK,GAAE,mBAAkB;AAAA,KAC5B;AAEJ;AAmBO,SAAS,YAAY,EAAE,OAAO,UAAU,SAAS,OAAO,WAAW,GAAG,MAAM,GAAqB;AACtG,QAAM,EAAE,MAAM,QAAQ,IAAI,SAAS;AACnC,QAAM,OAAO,OAAO,MAAM,QAAQ,IAAI,IAAI,KAAK,MAAM,MAAM;AAC3D,QAAM,OAAO,OAAO,UAAU,aAAa,MAAM,IAAI,IAAI;AACzD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,OAAO;AAAA,MACP,aAAW;AAAA,MACX,SAAS,MAAM,QAAQ,IAAI;AAAA,MAC3B,WAAW,eAAe,EAAE,SAAS,OAAO,MAAM,QAAQ,UAAU,CAAC;AAAA,MACpE,GAAG;AAAA,MAEJ,8BAAC,SAAI,SAAQ,aAAY,WAAU,WAAU,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACpJ,gBAAM,IAAI,GACb;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/theme/theme.tsx"],"sourcesContent":["// Client. ONE mechanism for the whole organisation: dark by default, `html.light` for light, `html.theme-<name>` for a\n// named theme, persisted in localStorage (`kz-theme` for the mode, `kz-theme-name` for the named theme).\nimport * as React from \"react\";\n\nimport { type ButtonVariants, buttonVariants } from \"../button/button\";\n\nexport type Mode = \"dark\" | \"light\" | \"system\";\n\nconst MODE_KEY = \"kz-theme\";\nconst NAME_KEY = \"kz-theme-name\";\nconst MODES: readonly Mode[] = [\"dark\", \"light\", \"system\"];\nconst DARK_QUERY = \"(prefers-color-scheme: dark)\";\n\nconst isMode = (value: unknown): value is Mode => MODES.includes(value as Mode);\n\n// Storage blocked (private mode, sandbox): the choice lives in memory for the page.\nconst memory = new Map<string, string>();\n\nfunction read(key: string): string | null {\n try {\n return localStorage.getItem(key);\n } catch {\n return memory.get(key) ?? null;\n }\n}\n\nfunction write(key: string, value: string | null) {\n if (value === null) memory.delete(key);\n else memory.set(key, value);\n try {\n if (value === null) localStorage.removeItem(key);\n else localStorage.setItem(key, value);\n } catch {\n // storage blocked: memory holds it\n }\n}\n\n// The persisted choice is an external store: every provider and tab reads the same value, the server reads none.\nconst listeners = new Set<() => void>();\nconst notify = () => listeners.forEach((listener) => listener());\nfunction subscribe(listener: () => void) {\n listeners.add(listener);\n window.addEventListener(\"storage\", listener);\n return () => {\n listeners.delete(listener);\n window.removeEventListener(\"storage\", listener);\n };\n}\n\nfunction applyMode(mode: Mode) {\n const dark = window.matchMedia(DARK_QUERY).matches;\n document.documentElement.classList.toggle(\"light\", mode === \"light\" || (mode === \"system\" && !dark));\n}\n\nfunction applyName(previous: string | null, next: string | null) {\n const classes = document.documentElement.classList;\n if (previous) classes.remove(`theme-${previous}`);\n if (next) classes.add(`theme-${next}`);\n}\n\nexport type ThemeScriptProps = {\n /** The nonce of a strict Content-Security-Policy (`script-src 'nonce-…'`). */\n nonce?: string;\n /**\n * The mode before the visitor chooses one — pass the same value as `ThemeProvider`'s `defaultMode`. A persisted\n * choice (`kz-theme`) always wins.\n * @default \"system\"\n */\n defaultMode?: Mode;\n};\n\n/**\n * In <head>, before anything renders: applies the persisted mode (else `defaultMode`) and named theme, so the page\n * never flashes. `nonce` for a strict Content-Security-Policy.\n */\nexport function ThemeScript({ nonce, defaultMode = \"system\" }: ThemeScriptProps) {\n const fallback = isMode(defaultMode) ? defaultMode : \"system\";\n const js =\n `(function(){try{var m=localStorage.getItem(\"${MODE_KEY}\");if(m!==\"dark\"&&m!==\"light\"&&m!==\"system\")m=\"${fallback}\";` +\n `var n=localStorage.getItem(\"${NAME_KEY}\");var d=matchMedia(\"${DARK_QUERY}\").matches;var c=document.documentElement.classList;` +\n `c.toggle(\"light\",m===\"light\"||(m===\"system\"&&!d));if(n)c.add(\"theme-\"+n)}catch(e){}})()`;\n return <script nonce={nonce} dangerouslySetInnerHTML={{ __html: js }} />;\n}\n\nexport type ThemeContextValue = {\n /** The chosen mode: dark, light or follow the system. */\n mode: Mode;\n setMode: (mode: Mode) => void;\n /** The named theme (`html.theme-<name>`), or null. */\n theme: string | null;\n setTheme: (theme: string | null) => void;\n};\n\nconst ThemeContext = React.createContext<ThemeContextValue | null>(null);\n\nexport type ThemeProviderProps = {\n children: React.ReactNode;\n /**\n * The mode before the visitor chooses one (nothing persisted as `kz-theme`) — pass the same value to `ThemeScript`.\n * @default \"system\"\n */\n defaultMode?: Mode;\n};\n\nexport function ThemeProvider({ children, defaultMode = \"system\" }: ThemeProviderProps) {\n // Before hydration the server knows nothing persisted (ThemeScript has already applied it to <html>).\n const stored = React.useSyncExternalStore(subscribe, () => read(MODE_KEY), () => null);\n const mode: Mode = isMode(stored) ? stored : defaultMode;\n const theme = React.useSyncExternalStore(subscribe, () => read(NAME_KEY), () => null);\n\n // The same resolution as ThemeScript (a no-op after it), for an app that renders the provider without the script.\n React.useEffect(() => {\n const persisted = read(MODE_KEY);\n applyMode(isMode(persisted) ? persisted : defaultMode);\n }, [defaultMode]);\n\n // \"system\" follows the operating system while the page is open.\n React.useEffect(() => {\n if (mode !== \"system\") return;\n const query = window.matchMedia(DARK_QUERY);\n const onChange = () => applyMode(\"system\");\n query.addEventListener?.(\"change\", onChange);\n return () => query.removeEventListener?.(\"change\", onChange);\n }, [mode]);\n\n const setMode = React.useCallback((next: Mode) => {\n write(MODE_KEY, next);\n applyMode(next);\n notify();\n }, []);\n\n const setTheme = React.useCallback((next: string | null) => {\n applyName(read(NAME_KEY), next);\n write(NAME_KEY, next);\n notify();\n }, []);\n\n const value = React.useMemo(() => ({ mode, setMode, theme, setTheme }), [mode, setMode, theme, setTheme]);\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = React.useContext(ThemeContext);\n if (!context) throw new Error(\"useTheme: wrap the app in <ThemeProvider>\");\n return context;\n}\n\nconst ICONS: Record<Mode, React.ReactNode> = {\n dark: <path d=\"M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5Z\" />,\n light: (\n <>\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4\" />\n </>\n ),\n system: (\n <>\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"12\" rx=\"2\" />\n <path d=\"M8 20h8M12 16v4\" />\n </>\n ),\n};\n\nexport type ThemeToggleProps = Omit<React.ComponentProps<\"button\">, \"onClick\" | \"children\"> &\n Pick<ButtonVariants, \"variant\" | \"shape\"> & {\n /** Any `Button` variant. */\n variant?: ButtonVariants[\"variant\"];\n /**\n * rounded · pill.\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** The accessible name — a string, or one per current mode (e.g. `(mode) => t(\"theme.\" + mode)`). */\n label: string | ((mode: Mode) => string);\n };\n\n/**\n * An icon button (styled as `IconButton`, without its Slot) that cycles dark → light → system. Needs a\n * <ThemeProvider> above it. State: `data-mode`.\n */\nexport function ThemeToggle({ label, variant = \"ghost\", shape, className, ...props }: ThemeToggleProps) {\n const { mode, setMode } = useTheme();\n const next = MODES[(MODES.indexOf(mode) + 1) % MODES.length] as Mode;\n const name = typeof label === \"function\" ? label(mode) : label;\n return (\n <button\n type=\"button\"\n aria-label={name}\n title={name}\n data-mode={mode}\n onClick={() => setMode(next)}\n className={buttonVariants({ variant, shape, size: \"icon\", className })}\n {...props}\n >\n <svg viewBox=\"0 0 24 24\" className=\"h-5 w-5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n {ICONS[mode]}\n </svg>\n </button>\n );\n}\n"],"mappings":"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","names":[]}
package/dist/toast.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-WEVYKZIF.js";
5
5
  import {
6
6
  cn
7
- } from "./chunk-2FRWNSRO.js";
7
+ } from "./chunk-NSLXEDIS.js";
8
8
 
9
9
  // src/toast/toast.tsx
10
10
  import { toast, Toaster as Sonner } from "sonner";
package/dist/toc.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  cn
4
- } from "./chunk-G3ETON2A.js";
4
+ } from "./chunk-WU4VLSEA.js";
5
5
 
6
6
  // src/toc/toc.tsx
7
7
  import * as React from "react";
package/dist/tooltip.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-J3NC6ER4.js";
5
5
  import {
6
6
  cn
7
- } from "./chunk-2FRWNSRO.js";
7
+ } from "./chunk-NSLXEDIS.js";
8
8
 
9
9
  // src/tooltip/tooltip.tsx
10
10
  import { Tooltip as TooltipPrimitive } from "radix-ui";
@@ -1,9 +1,10 @@
1
1
  import "./chunk-TDG7ED2W.js";
2
2
  import {
3
3
  Button
4
- } from "./chunk-3IN6TOPM.js";
4
+ } from "./chunk-6ZYRUOTA.js";
5
5
  import "./chunk-43PTCDTL.js";
6
6
  import "./chunk-2VNYHG4E.js";
7
+ import "./chunk-W675RFOA.js";
7
8
 
8
9
  // src/update-prompt/update-prompt.tsx
9
10
  import { tv } from "tailwind-variants";