@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
package/README.md CHANGED
@@ -152,6 +152,7 @@ light or a product's — is a set of tokens.
152
152
  | `@krizaka/ui/site-footer` | `SiteFooter` (`current`, `labels`, `version`, `env`, `legal`; own columns as children) `.Column` (`title`) `.Link` (`active`, `asChild`): the footer of every Krizaka site — the family in columns, “A Krizaka company / product / open-source project”, the version, Montréal | client |
153
153
  | `@krizaka/ui/chip` | `Chip` (`selected`/`defaultSelected` + `onSelectedChange`, `size` sm·md; `removable` + `removeLabel` + `onRemove`), `Chip.Group` (`type` single·multiple, `label`, `required` for single), `chip` (the slots) | client |
154
154
  | `@krizaka/ui/chip-link` | `ChipLink` (a filter that is a link: `selected`, `current`, `size`, `asChild`), `chipVariants` (`size`, `selected`) | server |
155
+ | `@krizaka/ui/meta-row` | `MetaRow` (`items`, `chips`, `size` sm·md): one quiet line of dot-separated facts with status chips at its end; a real list, dots hidden from assistive technology; `/native` has the same | server |
155
156
  | `@krizaka/ui/switch` | `Switch` (`checked`/`defaultChecked` + `onCheckedChange`, `label` unless a visible label names it, `size` sm·md, `invalid`), `switchVariants` | client |
156
157
  | `@krizaka/ui/slider` | `Slider` (`value`: a number or a `[min, max]` range, `onValueChange`, `onValueCommit`, `label`, `thumbLabels`, `formatValue` → aria-valuetext, `showLabel`, `origin`), `slider` (the slots) | client |
157
158
  | `@krizaka/ui/checkbox` | `Checkbox` (`checked` true·false·"indeterminate" + `onCheckedChange`, `invalid`, its words as children) — sits in a `Field` | client |
@@ -191,6 +192,7 @@ light or a product's — is a set of tokens.
191
192
  | `@krizaka/ui/media-capture` | `MediaCapture` (`mode` photo·video·both, `facing`, `maxDuration`, permission asked on a gesture, the file picker as the way out, `onCapture({ blob, kind, url })`) | client |
192
193
  | `@krizaka/ui/video-trimmer` | `VideoTrimmer` (`duration`, `value` [start, end], `minLength`, `step`/`largeStep`, `frames` or children, `time` + `onSeek`, `classNames` per part, `renderHandle`) | client |
193
194
  | `@krizaka/ui/audio-player` | `AudioPlayer` (a seekable waveform: `peaks` or `computePeaks`, `bars`, `playbackRates`, `duration`), `resamplePeaks`, `computeAudioPeaks` | client |
195
+ | `@krizaka/ui/waveform` | `Waveform` (`peaks`, `bars`, `size` sm·md·lg, `tone` accent·neutral, `playing`, `label`): the bars of a sound, decorative by default (`aria-hidden`), breathing gently while it plays, still under reduced motion and off screen; `/native` has the same | client |
194
196
  | `@krizaka/ui/image-cropper` | `ImageCropper` (`aspect`, `round`, an image or a `<video>`, a focus point + zoom out, keyboard and zoom slider), `cropRect` | client |
195
197
  | `@krizaka/ui/document-viewer` | `DocumentViewer` (a PDF drawn by pdf.js — `loadPdfjs={() => import("pdfjs-dist")}`, an optional peer — with `highlights` lit where their quotes sit, `activeId` / `onActiveChange`, `onLocate`; page + quote when the text layer cannot place one), `locateQuote` | client |
196
198
  | `@krizaka/ui/page` | the page frame: `Page` (`size` narrow·default·wide·full, `as`), `Section` (`id`, `eyebrow`, `title`, `lead`, `actions`, `divider`, `spacing` sm·md·lg, `backdrop`, `size`, `reveal`), `SectionHeading`, `Facts` (`items`: `label`, `tone` ok·wip·neutral, `href`), `Ticks` (backticks read as code) — see [Page blocks](#page-blocks) | server |
@@ -208,6 +210,8 @@ light or a product's — is a set of tokens.
208
210
  | `@krizaka/ui/cta-panel` | `CtaPanel` (`id`, `title`, `body`, the actions as children, `level`, `reveal`) | server |
209
211
  | `@krizaka/ui/toc` | `Toc` (`label`, `items`; the section being read marked), `TocLayout` (`toc`, the sections as children) | client |
210
212
  | `@krizaka/ui/app-shell` | `AppShell.Root` (`defaultCollapsed`, `collapsed` + `onCollapsedChange`) `/Sidebar` (`label`, `brand`, `footer`, `collapseLabels`, `closeLabel`; a drawer on a phone) `/Group/Item` (`icon`, `label`, `current`, `badge`, `shortcut`, `asChild`) `/Body/Header` (`title`, `menuLabel`, `actions`) `/Search` (`label`, `onOpen`, `shortcut` ⌘K — opens the app's `CommandDialog`) `/Main`; `collapseShortcut` (⌘B), `useShortcuts` — see [Layouts and templates](#layouts-and-templates) | client |
213
+ | `@krizaka/ui/rail-nav` | `RailNav.Shell/Root/Item/Body`: `Root` (`label`, `mark`, `accent`, `footer`, `expandable` + `expanded`/`onExpandedChange`, `expandLabels`) is a vertical rail of icons on a desktop — the mark on top, a tooltip per icon, an accent bar on the current item — and a bottom tab bar on a phone; `Item` (`icon`, `label`, `current`, `badge`, `badgeLabel`, `asChild`); arrow keys, Home and End move between items | client |
214
+ | `@krizaka/ui/app-header` | `AppHeader` (`name`, `mark`, `href` or `homeLink`, `chips`, `actions`): the bar beside a `RailNav` — the name as text, the mark below `md` only (the rail carries it above), so one mark shows at every width | server |
211
215
  | `@krizaka/ui/dashboard-layout` | `DashboardLayout` (`title`, `eyebrow`, `description`, `actions`, `toolbar`, `headingAs`), `Widget` (`title`, `description`, `action`, `span` 1·2·3·full, `level`) | server |
212
216
  | `@krizaka/ui/settings-layout` | `SettingsLayout` (`title`, `description`, `nav`, `navLabel`, `linkAs`), `SettingsSection` (`title`, `description`, `footer`) | server |
213
217
  | `@krizaka/ui/auth-layout` | `AuthLayout` (`brand`, `title`, `description`, `footer`, `legal`, `promise`, `aside`, `asideFooter`) | server |
@@ -215,6 +219,7 @@ light or a product's — is a set of tokens.
215
219
  | `@krizaka/ui/split-view` | `SplitView` (`listTitle`, `listActions`, `list`, `detailHead`, `detail`, `empty`, `showDetail`, `back`) | server |
216
220
  | `@krizaka/ui/marketing-layout` | `MarketingLayout` (`header`, `footer`, `skipLabel`) | server |
217
221
  | `@krizaka/ui/docs-layout` | `DocsLayout` (`sidebar`, `sidebarLabel`, `toc`) | server |
222
+ | `@krizaka/ui/docs-nav` | `DocsNav` (`label`, `groups`, `current`) | server |
218
223
  | `@krizaka/ui/landing-page` | `LandingPage` — a page template, see [Page templates](#page-templates) | server |
219
224
  | `@krizaka/ui/product-page` | `ProductPage` — a page template, see [Page templates](#page-templates) | server |
220
225
  | `@krizaka/ui/how-it-works-page` | `HowItWorksPage` — a page template, see [Page templates](#page-templates) | server |
@@ -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/achievement/achievement.tsx
8
8
  import * as React from "react";
@@ -5,14 +5,14 @@ import {
5
5
  import {
6
6
  ExternalGlyph
7
7
  } from "./chunk-XCBVFMNV.js";
8
- import {
9
- cn
10
- } from "./chunk-4LOMIQVX.js";
11
8
  import {
12
9
  buttonVariants
13
- } from "./chunk-3IN6TOPM.js";
10
+ } from "./chunk-6ZYRUOTA.js";
14
11
  import "./chunk-43PTCDTL.js";
15
12
  import "./chunk-2VNYHG4E.js";
13
+ import {
14
+ cn
15
+ } from "./chunk-W675RFOA.js";
16
16
 
17
17
  // src/action-bar/action-bar.tsx
18
18
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -0,0 +1,79 @@
1
+ import * as tailwind_variants from 'tailwind-variants';
2
+ import * as React from 'react';
3
+
4
+ declare const appHeader: tailwind_variants.TVReturnType<{
5
+ [key: string]: {
6
+ [key: string]: tailwind_variants.ClassValue | {
7
+ root?: tailwind_variants.ClassValue;
8
+ brand?: tailwind_variants.ClassValue;
9
+ mark?: tailwind_variants.ClassValue;
10
+ name?: tailwind_variants.ClassValue;
11
+ chips?: tailwind_variants.ClassValue;
12
+ actions?: tailwind_variants.ClassValue;
13
+ };
14
+ };
15
+ } | {
16
+ [x: string]: {
17
+ [x: string]: tailwind_variants.ClassValue | {
18
+ root?: tailwind_variants.ClassValue;
19
+ brand?: tailwind_variants.ClassValue;
20
+ mark?: tailwind_variants.ClassValue;
21
+ name?: tailwind_variants.ClassValue;
22
+ chips?: tailwind_variants.ClassValue;
23
+ actions?: tailwind_variants.ClassValue;
24
+ };
25
+ };
26
+ } | {}, {
27
+ root: string;
28
+ brand: string;
29
+ mark: string;
30
+ name: string;
31
+ chips: string;
32
+ actions: string;
33
+ }, undefined, {
34
+ [key: string]: {
35
+ [key: string]: tailwind_variants.ClassValue | {
36
+ root?: tailwind_variants.ClassValue;
37
+ brand?: tailwind_variants.ClassValue;
38
+ mark?: tailwind_variants.ClassValue;
39
+ name?: tailwind_variants.ClassValue;
40
+ chips?: tailwind_variants.ClassValue;
41
+ actions?: tailwind_variants.ClassValue;
42
+ };
43
+ };
44
+ } | {}, {
45
+ root: string;
46
+ brand: string;
47
+ mark: string;
48
+ name: string;
49
+ chips: string;
50
+ actions: string;
51
+ }, tailwind_variants.TVReturnTypeLike<unknown, {
52
+ root: string;
53
+ brand: string;
54
+ mark: string;
55
+ name: string;
56
+ chips: string;
57
+ actions: string;
58
+ }>>;
59
+ type AppHeaderProps = Omit<React.ComponentProps<"header">, "children"> & {
60
+ /** The product's name, as text (`Orazaka`): the only brand element on a desktop. */
61
+ name: string;
62
+ /** The product's mark (`<ProductLogo id="orazaka" size={22} />`): shown below `md` only, where the rail (which carries it) is a bottom bar. */
63
+ mark?: React.ReactNode;
64
+ /** Makes the name (and the mark) a link home: pass your router's link as `homeLink` or give a `href`. */
65
+ href?: string;
66
+ /** Your router's link element for the home link; it receives the name and the mark as children. */
67
+ homeLink?: React.ReactElement<{
68
+ className?: string;
69
+ children?: React.ReactNode;
70
+ }>;
71
+ /** Status chips beside the name (`Badge`): « Local · Sovereign », « Dev », a version. */
72
+ chips?: React.ReactNode;
73
+ /** On the right: theme, notifications, the account menu. */
74
+ actions?: React.ReactNode;
75
+ };
76
+ /** The app's top bar: the name next to the rail, the mark on a phone, chips, actions. */
77
+ declare function AppHeader({ name, mark, href, homeLink, chips, actions, className, ...props }: AppHeaderProps): React.JSX.Element;
78
+
79
+ export { AppHeader, type AppHeaderProps, appHeader };
@@ -0,0 +1,32 @@
1
+ // src/app-header/app-header.tsx
2
+ import * as React from "react";
3
+ import { tv } from "tailwind-variants";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ var appHeader = tv({
6
+ slots: {
7
+ root: "sticky top-0 z-30 flex h-14 w-full shrink-0 items-center gap-3 border-b border-border-subtle bg-surface-1/90 px-4 backdrop-blur-xl md:bg-surface-1 md:pl-3 md:pr-5 md:backdrop-blur-none",
8
+ // The rail's mark is 56 px tall and so is this bar: the word shares the mark's line, right after the rail.
9
+ brand: "flex min-w-0 items-center gap-2 font-display text-sm font-bold tracking-tight text-fg no-underline",
10
+ mark: "inline-flex shrink-0 md:hidden",
11
+ name: "truncate",
12
+ chips: "flex shrink-0 items-center gap-2",
13
+ actions: "ml-auto flex shrink-0 items-center gap-2"
14
+ }
15
+ });
16
+ var s = appHeader();
17
+ function AppHeader({ name, mark, href, homeLink, chips, actions, className, ...props }) {
18
+ const brand = /* @__PURE__ */ jsxs(Fragment, { children: [
19
+ mark && /* @__PURE__ */ jsx("span", { "data-brand-mark": true, className: s.mark(), children: mark }),
20
+ /* @__PURE__ */ jsx("span", { className: s.name(), children: name })
21
+ ] });
22
+ return /* @__PURE__ */ jsxs("header", { className: s.root({ className }), ...props, children: [
23
+ homeLink ? React.cloneElement(homeLink, { className: s.brand() }, brand) : href ? /* @__PURE__ */ jsx("a", { href, className: s.brand(), children: brand }) : /* @__PURE__ */ jsx("div", { className: s.brand(), children: brand }),
24
+ chips && /* @__PURE__ */ jsx("div", { className: s.chips(), children: chips }),
25
+ actions && /* @__PURE__ */ jsx("div", { className: s.actions(), children: actions })
26
+ ] });
27
+ }
28
+ export {
29
+ AppHeader,
30
+ appHeader
31
+ };
32
+ //# sourceMappingURL=app-header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/app-header/app-header.tsx"],"sourcesContent":["// Server-safe: no hook, no context. The top bar that sits next to a `RailNav`: the product's NAME as text (the mark is the\n// rail's), then optional chips, then the actions. Where the rail is a bottom tab bar (a phone) it has no room for the mark,\n// so the header shows it there and only there: exactly one brand mark is visible at every width.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const appHeader = tv({\n slots: {\n root: \"sticky top-0 z-30 flex h-14 w-full shrink-0 items-center gap-3 border-b border-border-subtle bg-surface-1/90 px-4 backdrop-blur-xl md:bg-surface-1 md:pl-3 md:pr-5 md:backdrop-blur-none\",\n // The rail's mark is 56 px tall and so is this bar: the word shares the mark's line, right after the rail.\n brand: \"flex min-w-0 items-center gap-2 font-display text-sm font-bold tracking-tight text-fg no-underline\",\n mark: \"inline-flex shrink-0 md:hidden\",\n name: \"truncate\",\n chips: \"flex shrink-0 items-center gap-2\",\n actions: \"ml-auto flex shrink-0 items-center gap-2\",\n },\n});\nconst s = appHeader();\n\nexport type AppHeaderProps = Omit<React.ComponentProps<\"header\">, \"children\"> & {\n /** The product's name, as text (`Orazaka`): the only brand element on a desktop. */\n name: string;\n /** The product's mark (`<ProductLogo id=\"orazaka\" size={22} />`): shown below `md` only, where the rail (which carries it) is a bottom bar. */\n mark?: React.ReactNode;\n /** Makes the name (and the mark) a link home: pass your router's link as `homeLink` or give a `href`. */\n href?: string;\n /** Your router's link element for the home link; it receives the name and the mark as children. */\n homeLink?: React.ReactElement<{ className?: string; children?: React.ReactNode }>;\n /** Status chips beside the name (`Badge`): « Local · Sovereign », « Dev », a version. */\n chips?: React.ReactNode;\n /** On the right: theme, notifications, the account menu. */\n actions?: React.ReactNode;\n};\n\n/** The app's top bar: the name next to the rail, the mark on a phone, chips, actions. */\nexport function AppHeader({ name, mark, href, homeLink, chips, actions, className, ...props }: AppHeaderProps) {\n const brand = (\n <>\n {mark && <span data-brand-mark className={s.mark()}>{mark}</span>}\n <span className={s.name()}>{name}</span>\n </>\n );\n return (\n <header className={s.root({ className })} {...props}>\n {homeLink ? (\n React.cloneElement(homeLink, { className: s.brand() }, brand)\n ) : href ? (\n <a href={href} className={s.brand()}>{brand}</a>\n ) : (\n <div className={s.brand()}>{brand}</div>\n )}\n {chips && <div className={s.chips()}>{chips}</div>}\n {actions && <div className={s.actions()}>{actions}</div>}\n </header>\n );\n}\n"],"mappings":";AAGA,YAAY,WAAW;AACvB,SAAS,UAAU;AAiCf,mBACW,KADX;AA/BG,IAAM,YAAY,GAAG;AAAA,EAC1B,OAAO;AAAA,IACL,MAAM;AAAA;AAAA,IAEN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AACF,CAAC;AACD,IAAM,IAAI,UAAU;AAkBb,SAAS,UAAU,EAAE,MAAM,MAAM,MAAM,UAAU,OAAO,SAAS,WAAW,GAAG,MAAM,GAAmB;AAC7G,QAAM,QACJ,iCACG;AAAA,YAAQ,oBAAC,UAAK,mBAAe,MAAC,WAAW,EAAE,KAAK,GAAI,gBAAK;AAAA,IAC1D,oBAAC,UAAK,WAAW,EAAE,KAAK,GAAI,gBAAK;AAAA,KACnC;AAEF,SACE,qBAAC,YAAO,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC3C;AAAA,eACO,mBAAa,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,KAAK,IAC1D,OACF,oBAAC,OAAE,MAAY,WAAW,EAAE,MAAM,GAAI,iBAAM,IAE5C,oBAAC,SAAI,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,IAEnC,SAAS,oBAAC,SAAI,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,IAC3C,WAAW,oBAAC,SAAI,WAAW,EAAE,QAAQ,GAAI,mBAAQ;AAAA,KACpD;AAEJ;","names":[]}
@@ -13,6 +13,7 @@ declare const appShell: tailwind_variants.TVReturnType<{
13
13
  title?: tailwind_variants.ClassValue;
14
14
  group?: tailwind_variants.ClassValue;
15
15
  root?: tailwind_variants.ClassValue;
16
+ titlebar?: tailwind_variants.ClassValue;
16
17
  drawer?: tailwind_variants.ClassValue;
17
18
  overlay?: tailwind_variants.ClassValue;
18
19
  brand?: tailwind_variants.ClassValue;
@@ -40,6 +41,7 @@ declare const appShell: tailwind_variants.TVReturnType<{
40
41
  title?: tailwind_variants.ClassValue;
41
42
  group?: tailwind_variants.ClassValue;
42
43
  root?: tailwind_variants.ClassValue;
44
+ titlebar?: tailwind_variants.ClassValue;
43
45
  drawer?: tailwind_variants.ClassValue;
44
46
  overlay?: tailwind_variants.ClassValue;
45
47
  brand?: tailwind_variants.ClassValue;
@@ -58,6 +60,7 @@ declare const appShell: tailwind_variants.TVReturnType<{
58
60
  } | {}, {
59
61
  root: string;
60
62
  sidebar: string;
63
+ titlebar: string;
61
64
  drawer: string;
62
65
  overlay: string;
63
66
  brand: string;
@@ -90,6 +93,7 @@ declare const appShell: tailwind_variants.TVReturnType<{
90
93
  title?: tailwind_variants.ClassValue;
91
94
  group?: tailwind_variants.ClassValue;
92
95
  root?: tailwind_variants.ClassValue;
96
+ titlebar?: tailwind_variants.ClassValue;
93
97
  drawer?: tailwind_variants.ClassValue;
94
98
  overlay?: tailwind_variants.ClassValue;
95
99
  brand?: tailwind_variants.ClassValue;
@@ -108,6 +112,7 @@ declare const appShell: tailwind_variants.TVReturnType<{
108
112
  } | {}, {
109
113
  root: string;
110
114
  sidebar: string;
115
+ titlebar: string;
111
116
  drawer: string;
112
117
  overlay: string;
113
118
  brand: string;
@@ -131,6 +136,7 @@ declare const appShell: tailwind_variants.TVReturnType<{
131
136
  }, tailwind_variants.TVReturnTypeLike<unknown, {
132
137
  root: string;
133
138
  sidebar: string;
139
+ titlebar: string;
134
140
  drawer: string;
135
141
  overlay: string;
136
142
  brand: string;
@@ -167,9 +173,15 @@ type AppShellRootProps = React.ComponentProps<"div"> & {
167
173
  * @default "mod+b"
168
174
  */
169
175
  collapseShortcut?: string | false;
176
+ /**
177
+ * The shell is a desktop app's window (the Orazaka Mac app, Tauri 2 — ADR-002): no drawer, the sidebar's top clears the
178
+ * window's traffic lights (`--kz-titlebar-inset`, 28 px; the window's height is `--kz-window-height`, the viewport by default), the header and that top move the window
179
+ * (`data-tauri-drag-region`), a denser layout, the chrome not selectable. In a browser it is a fixed-height shell.
180
+ */
181
+ desktop?: boolean;
170
182
  };
171
183
  /** The shell: holds the collapse (desktop) and the drawer (phone) state. Children: Sidebar, then Body. */
172
- declare function AppShellRoot({ defaultCollapsed, collapsed: controlled, onCollapsedChange, skipLabel, collapseShortcut, className, children, ...props }: AppShellRootProps): React.JSX.Element;
184
+ declare function AppShellRoot({ defaultCollapsed, collapsed: controlled, onCollapsedChange, skipLabel, collapseShortcut, desktop, className, children, ...props }: AppShellRootProps): React.JSX.Element;
173
185
  type AppShellSidebarProps = Omit<React.ComponentProps<"nav">, "children"> & {
174
186
  /** The navigation's accessible name (`Studio`, `Administration`). */
175
187
  label: string;
@@ -266,6 +278,12 @@ declare function parseCombo(combo: string): Combo;
266
278
  declare function matchesCombo(event: Pick<KeyboardEvent, "key" | "metaKey" | "ctrlKey" | "altKey" | "shiftKey">, combo: string, apple?: boolean): boolean;
267
279
  /** The keys of a shortcut to show on a keycap: `["⌘", "K"]` on a Mac, `["Ctrl", "K"]` elsewhere; a sequence `g d` is `["G", "D"]`. */
268
280
  declare function formatShortcut(shortcut: string, apple?: boolean): string[];
281
+ /**
282
+ * The accelerator of a combination for a desktop app's native menu bar (Tauri's `MenuItem`, Electron's — ADR-002):
283
+ * `mod+k` → `CmdOrCtrl+K`, `shift+mod+/` → `Shift+CmdOrCtrl+/`. The menu and the shell then answer the same keys, and the
284
+ * menu shows them. A sequence (`g d`) has none: a menu item takes one chord.
285
+ */
286
+ declare function acceleratorOf(shortcut: string): string | undefined;
269
287
  /** Whether the person is on an Apple device — `false` on the server and in the first client render (no mismatch), then right. */
270
288
  declare function useApple(): boolean;
271
289
  /** The `aria-keyshortcuts` of a combination (`Control+K`, `Meta+K` on a Mac); a sequence has none (it is not a chord). */
@@ -280,4 +298,4 @@ declare function useShortcuts(map: ShortcutMap, { enabled, timeout }?: {
280
298
  timeout?: number;
281
299
  }): void;
282
300
 
283
- export { AppShell, AppShellBody, AppShellGroup, type AppShellGroupProps, AppShellHeader, type AppShellHeaderProps, AppShellItem, type AppShellItemProps, AppShellMain, AppShellRoot, type AppShellRootProps, AppShellSearch, type AppShellSearchProps, AppShellSidebar, type AppShellSidebarProps, type ShortcutMap, appShell, ariaKeyShortcuts, formatShortcut, matchesCombo, parseCombo, useApple, useShortcuts };
301
+ export { AppShell, AppShellBody, AppShellGroup, type AppShellGroupProps, AppShellHeader, type AppShellHeaderProps, AppShellItem, type AppShellItemProps, AppShellMain, AppShellRoot, type AppShellRootProps, AppShellSearch, type AppShellSearchProps, AppShellSidebar, type AppShellSidebarProps, type ShortcutMap, acceleratorOf, appShell, ariaKeyShortcuts, formatShortcut, matchesCombo, parseCombo, useApple, useShortcuts };
package/dist/app-shell.js CHANGED
@@ -6,10 +6,10 @@ import {
6
6
  } from "./chunk-AFY35UCB.js";
7
7
  import {
8
8
  cn
9
- } from "./chunk-G3ETON2A.js";
9
+ } from "./chunk-WU4VLSEA.js";
10
10
  import {
11
11
  SkipLink
12
- } from "./chunk-3GODX3D6.js";
12
+ } from "./chunk-QDXV544C.js";
13
13
 
14
14
  // src/app-shell/app-shell.tsx
15
15
  import { Dialog as DialogPrimitive, Slot } from "radix-ui";
@@ -68,6 +68,16 @@ function formatShortcut(shortcut, apple = isApple()) {
68
68
  const last = glyph[ALIASES[key.toLowerCase()] ?? key.toLowerCase()] ?? key.toUpperCase();
69
69
  return [...shown, last];
70
70
  }
71
+ function acceleratorOf(shortcut) {
72
+ if (shortcut.trim().includes(" ")) return void 0;
73
+ const parts = shortcut.split("+").filter(Boolean);
74
+ const names = { mod: "CmdOrCtrl", meta: "Super", ctrl: "Ctrl", alt: "Alt", shift: "Shift" };
75
+ const raw = (parts.at(-1) ?? "").toLowerCase();
76
+ const key = ALIASES[raw] ?? raw;
77
+ const keys = { escape: "Escape", enter: "Enter", " ": "Space", arrowup: "Up", arrowdown: "Down", arrowleft: "Left", arrowright: "Right", delete: "Delete", backspace: "Backspace", tab: "Tab", "+": "Plus" };
78
+ const last = keys[key] ?? (key.length === 1 ? key.toUpperCase() : key.charAt(0).toUpperCase() + key.slice(1));
79
+ return [...parts.slice(0, -1).map((part) => names[part.toLowerCase()] ?? part), last].join("+");
80
+ }
71
81
  var noop = () => () => void 0;
72
82
  function useApple() {
73
83
  return React2.useSyncExternalStore(noop, isApple, () => false);
@@ -119,28 +129,29 @@ function useShortcuts(map, { enabled = true, timeout = 900 } = {}) {
119
129
  import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
120
130
  var appShell = tv2({
121
131
  slots: {
122
- root: "flex min-h-dvh w-full bg-surface-0 text-fg",
123
- sidebar: "sticky top-0 hidden h-dvh shrink-0 flex-col border-r border-border-subtle bg-surface-1 transition-[width] duration-300 motion-reduce:transition-none md:flex w-64 data-collapsed:w-[4.25rem]",
132
+ root: "flex min-h-dvh w-full bg-surface-0 text-fg data-desktop:h-[var(--kz-window-height,100dvh)] data-desktop:overflow-hidden",
133
+ sidebar: "sticky top-0 hidden h-dvh shrink-0 flex-col border-r border-border-subtle bg-surface-1 transition-[width] duration-300 motion-reduce:transition-none md:flex w-64 data-collapsed:w-[4.25rem] [[data-desktop]_&]:static [[data-desktop]_&]:flex [[data-desktop]_&]:h-auto [[data-desktop]_&]:w-60 [[data-desktop]_&]:select-none [[data-desktop]_&]:data-collapsed:w-[4.75rem]",
134
+ titlebar: "h-[var(--kz-titlebar-inset,1.75rem)] shrink-0",
124
135
  drawer: "kz-dialog fixed inset-y-0 left-0 z-50 flex w-[min(20rem,88vw)] flex-col border-r border-border-default bg-surface-1 pl-[env(safe-area-inset-left)] shadow-lg focus:outline-hidden",
125
136
  overlay: "kz-overlay fixed inset-0 z-50 bg-overlay backdrop-blur-xs",
126
- brand: "flex h-14 shrink-0 items-center gap-2.5 px-4 font-display text-[15px] font-bold tracking-tight [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0",
137
+ brand: "flex h-14 shrink-0 items-center gap-2.5 px-4 font-display text-[15px] font-bold tracking-tight [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0 [[data-desktop]_&]:h-11",
127
138
  nav: "flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 py-2",
128
139
  group: "mt-3 mb-1 px-3 font-mono text-[10.5px] font-semibold uppercase tracking-[0.14em] text-fg-secondary [[data-collapsed]_&]:sr-only",
129
- item: "group/item relative flex h-10 items-center gap-3 rounded-lg px-3 text-sm font-medium text-fg-secondary no-underline transition-colors hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg aria-[current=page]:before:absolute aria-[current=page]:before:inset-y-2 aria-[current=page]:before:-left-2 aria-[current=page]:before:w-1 aria-[current=page]:before:rounded-full aria-[current=page]:before:bg-accent [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0 [&>svg]:h-[18px] [&>svg]:w-[18px] [&>svg]:shrink-0",
140
+ item: "group/item relative flex h-10 items-center gap-3 rounded-lg px-3 text-sm font-medium text-fg-secondary no-underline transition-colors hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg aria-[current=page]:before:absolute aria-[current=page]:before:inset-y-2 aria-[current=page]:before:-left-2 aria-[current=page]:before:w-1 aria-[current=page]:before:rounded-full aria-[current=page]:before:bg-accent [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0 [&>svg]:h-[18px] [&>svg]:w-[18px] [&>svg]:shrink-0 [[data-desktop]_&]:h-8 [[data-desktop]_&]:cursor-default [[data-desktop]_&]:rounded-md [[data-desktop]_&]:text-[13px] [[data-desktop]_&_svg]:h-4 [[data-desktop]_&_svg]:w-4",
130
141
  itemLabel: "min-w-0 flex-1 truncate [[data-collapsed]_&]:sr-only",
131
142
  itemHint: "ml-auto hidden items-center gap-0.5 text-fg-secondary group-hover/item:flex group-focus-visible/item:flex [[data-collapsed]_&]:!hidden",
132
143
  itemBadge: "ml-auto inline-flex min-w-5 items-center justify-center rounded-full bg-accent px-1.5 text-[11px] font-bold text-on-accent [[data-collapsed]_&]:absolute [[data-collapsed]_&]:right-1.5 [[data-collapsed]_&]:top-1 [[data-collapsed]_&]:min-w-4 [[data-collapsed]_&]:px-1 [[data-collapsed]_&]:text-[10px]",
133
144
  footer: "shrink-0 border-t border-border-subtle p-2",
134
145
  collapse: "hidden h-9 w-full items-center gap-2 rounded-lg px-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg md:flex focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0",
135
- body: "flex min-w-0 flex-1 flex-col",
136
- header: "sticky top-0 z-30 flex h-14 shrink-0 items-center gap-3 border-b border-border-subtle bg-surface-0/85 px-4 backdrop-blur-xl md:px-6",
137
- menuButton: "inline-flex h-9 w-9 items-center justify-center rounded-lg border border-border-subtle bg-surface-1 text-fg md:hidden focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
138
- title: "min-w-0 flex-1 truncate font-display text-base font-bold tracking-tight",
146
+ body: "flex min-w-0 flex-1 flex-col [[data-desktop]_&]:min-h-0 [[data-desktop]_&]:overflow-y-auto",
147
+ header: "sticky top-0 z-30 flex h-14 shrink-0 items-center gap-3 border-b border-border-subtle bg-surface-0/85 px-4 backdrop-blur-xl md:px-6 [[data-desktop]_&]:h-12 [[data-desktop]_&]:select-none [[data-desktop]_&]:px-5",
148
+ menuButton: "inline-flex h-9 w-9 items-center justify-center rounded-lg border border-border-subtle bg-surface-1 text-fg md:hidden [[data-desktop]_&]:hidden focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
149
+ title: "min-w-0 flex-1 truncate font-display text-base font-bold tracking-tight [[data-desktop]_&]:text-[15px]",
139
150
  search: "inline-flex h-9 min-w-9 items-center justify-center gap-2 rounded-lg border border-border-subtle bg-surface-1 px-2.5 text-sm text-fg-secondary transition-colors hover:border-border-default hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring md:w-56 md:justify-start [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0",
140
151
  searchLabel: "sr-only md:not-sr-only md:flex-1 md:truncate md:text-left",
141
152
  searchKeys: "hidden items-center gap-0.5 md:flex",
142
153
  actions: "ml-auto flex shrink-0 items-center gap-2",
143
- main: "min-w-0 flex-1 px-4 py-6 md:px-6 md:py-8"
154
+ main: "min-w-0 flex-1 px-4 py-6 md:px-6 md:py-8 [[data-desktop]_&]:px-6 [[data-desktop]_&]:py-6"
144
155
  }
145
156
  });
146
157
  var s = appShell();
@@ -150,7 +161,7 @@ var useShell = () => {
150
161
  if (!ctx) throw new Error("AppShell parts must be inside <AppShell.Root>");
151
162
  return ctx;
152
163
  };
153
- function AppShellRoot({ defaultCollapsed = false, collapsed: controlled, onCollapsedChange, skipLabel, collapseShortcut = "mod+b", className, children, ...props }) {
164
+ function AppShellRoot({ defaultCollapsed = false, collapsed: controlled, onCollapsedChange, skipLabel, collapseShortcut = "mod+b", desktop = false, className, children, ...props }) {
154
165
  const [own, setOwn] = React3.useState(defaultCollapsed);
155
166
  const [open, setOpen] = React3.useState(false);
156
167
  const collapsed = controlled ?? own;
@@ -161,17 +172,19 @@ function AppShellRoot({ defaultCollapsed = false, collapsed: controlled, onColla
161
172
  },
162
173
  [controlled, onCollapsedChange]
163
174
  );
164
- const value = React3.useMemo(() => ({ collapsed, setCollapsed, open, setOpen, inDrawer: false }), [collapsed, setCollapsed, open]);
175
+ const value = React3.useMemo(() => ({ collapsed, setCollapsed, open, setOpen, inDrawer: false, desktop }), [collapsed, setCollapsed, open, desktop]);
165
176
  useShortcuts(collapseShortcut ? { [collapseShortcut]: () => setCollapsed(!collapsed) } : {});
166
- return /* @__PURE__ */ jsx2(ShellContext.Provider, { value, children: /* @__PURE__ */ jsxs("div", { className: s.root({ className }), ...props, children: [
177
+ return /* @__PURE__ */ jsx2(ShellContext.Provider, { value, children: /* @__PURE__ */ jsxs("div", { "data-desktop": desktop ? "" : void 0, className: s.root({ className }), ...props, children: [
167
178
  skipLabel && /* @__PURE__ */ jsx2(SkipLink, { href: "#content", children: skipLabel }),
168
179
  children
169
180
  ] }) });
170
181
  }
171
182
  function SidebarContent({ brand, children, footer, collapseLabels, closeLabel }) {
172
- const { collapsed, setCollapsed, inDrawer } = useShell();
183
+ const { collapsed, setCollapsed, inDrawer, desktop } = useShell();
184
+ const drag = desktop ? { "data-tauri-drag-region": "" } : {};
173
185
  return /* @__PURE__ */ jsxs(Fragment, { children: [
174
- /* @__PURE__ */ jsxs("div", { className: s.brand(), children: [
186
+ desktop && /* @__PURE__ */ jsx2("div", { "aria-hidden": true, className: s.titlebar(), ...drag }),
187
+ /* @__PURE__ */ jsxs("div", { className: s.brand(), ...drag, children: [
175
188
  brand,
176
189
  inDrawer && /* @__PURE__ */ jsx2(DialogPrimitive.Close, { className: cn(s.menuButton(), "ml-auto flex"), "aria-label": closeLabel, children: /* @__PURE__ */ jsx2(CloseGlyph, { className: "h-4 w-4" }) })
177
190
  ] }),
@@ -190,7 +203,7 @@ function AppShellSidebar({ label, brand, children, footer, collapseLabels, close
190
203
  const content = { brand, children, footer, collapseLabels, closeLabel };
191
204
  return /* @__PURE__ */ jsxs(Fragment, { children: [
192
205
  /* @__PURE__ */ jsx2("nav", { "aria-label": label, "data-collapsed": shell.collapsed ? "" : void 0, className: s.sidebar({ className }), ...props, children: /* @__PURE__ */ jsx2(SidebarContent, { ...content }) }),
193
- /* @__PURE__ */ jsx2(DialogPrimitive.Root, { open: shell.open, onOpenChange: shell.setOpen, children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
206
+ !shell.desktop && /* @__PURE__ */ jsx2(DialogPrimitive.Root, { open: shell.open, onOpenChange: shell.setOpen, children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
194
207
  /* @__PURE__ */ jsx2(DialogPrimitive.Overlay, { className: s.overlay() }),
195
208
  /* @__PURE__ */ jsxs(DialogPrimitive.Content, { className: s.drawer(), "aria-describedby": void 0, children: [
196
209
  /* @__PURE__ */ jsx2(DialogPrimitive.Title, { className: "sr-only", children: label }),
@@ -220,10 +233,11 @@ function AppShellBody({ className, ...props }) {
220
233
  return /* @__PURE__ */ jsx2("div", { className: s.body({ className }), ...props });
221
234
  }
222
235
  function AppShellHeader({ title, menuLabel, actions, className, children, ...props }) {
223
- const { open, setOpen } = useShell();
224
- return /* @__PURE__ */ jsxs("header", { className: s.header({ className }), ...props, children: [
236
+ const { open, setOpen, desktop } = useShell();
237
+ const drag = desktop ? { "data-tauri-drag-region": "" } : {};
238
+ return /* @__PURE__ */ jsxs("header", { className: s.header({ className }), ...drag, ...props, children: [
225
239
  /* @__PURE__ */ jsx2("button", { type: "button", className: s.menuButton(), "aria-label": menuLabel, "aria-expanded": open, "aria-haspopup": "dialog", onClick: () => setOpen(true), children: /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 24 24", className: "h-4 w-4", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "M4 7h16M4 12h16M4 17h10" }) }) }),
226
- title && /* @__PURE__ */ jsx2("h1", { className: s.title(), children: title }),
240
+ title && /* @__PURE__ */ jsx2("h1", { className: s.title(), ...drag, children: title }),
227
241
  children,
228
242
  actions && /* @__PURE__ */ jsx2("div", { className: s.actions(), children: actions })
229
243
  ] });
@@ -260,6 +274,7 @@ export {
260
274
  AppShellRoot,
261
275
  AppShellSearch,
262
276
  AppShellSidebar,
277
+ acceleratorOf,
263
278
  appShell,
264
279
  ariaKeyShortcuts,
265
280
  formatShortcut,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/app-shell/app-shell.tsx","../src/kbd/kbd.tsx","../src/app-shell/shortcuts.ts","../src/media.ts"],"sourcesContent":["// Client (the collapse, the drawer, the shortcuts). The shell of an application screen, read from the products' consoles\n// (Orochia admin and studio, Orazaka web-admin and web-client): a sidebar of sections that collapses to its icons on a\n// desktop, a header with the screen's title, a search that opens the app's command palette and its actions, the content —\n// and below `md` the sidebar becomes a drawer opened from the header (Radix Dialog: focus trap, Escape, focus return).\n// Keyboard: ⌘/Ctrl+B folds the sidebar, ⌘/Ctrl+K opens the search, `g` then a letter goes to a section (`shortcut` of an\n// item). Words arrive as props; links through `asChild`.\nimport { SkipLink } from \"@krizaka/ui/skip-link\";\nimport { Dialog as DialogPrimitive, Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { ChevronGlyph, CloseGlyph, SearchGlyph } from \"../glyphs\";\nimport { Kbd } from \"../kbd\";\nimport { ariaKeyShortcuts, formatShortcut, useApple, useShortcuts } from \"./shortcuts\";\n\nexport const appShell = tv({\n slots: {\n root: \"flex min-h-dvh w-full bg-surface-0 text-fg\",\n sidebar:\n \"sticky top-0 hidden h-dvh shrink-0 flex-col border-r border-border-subtle bg-surface-1 transition-[width] duration-300 motion-reduce:transition-none md:flex \" +\n \"w-64 data-collapsed:w-[4.25rem]\",\n drawer:\n \"kz-dialog fixed inset-y-0 left-0 z-50 flex w-[min(20rem,88vw)] flex-col border-r border-border-default bg-surface-1 pl-[env(safe-area-inset-left)] shadow-lg focus:outline-hidden\",\n overlay: \"kz-overlay fixed inset-0 z-50 bg-overlay backdrop-blur-xs\",\n brand: \"flex h-14 shrink-0 items-center gap-2.5 px-4 font-display text-[15px] font-bold tracking-tight [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0\",\n nav: \"flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 py-2\",\n group: \"mt-3 mb-1 px-3 font-mono text-[10.5px] font-semibold uppercase tracking-[0.14em] text-fg-secondary [[data-collapsed]_&]:sr-only\",\n item:\n \"group/item relative flex h-10 items-center gap-3 rounded-lg px-3 text-sm font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n \"aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg \" +\n \"aria-[current=page]:before:absolute aria-[current=page]:before:inset-y-2 aria-[current=page]:before:-left-2 aria-[current=page]:before:w-1 aria-[current=page]:before:rounded-full aria-[current=page]:before:bg-accent \" +\n \"[[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0 [&>svg]:h-[18px] [&>svg]:w-[18px] [&>svg]:shrink-0\",\n itemLabel: \"min-w-0 flex-1 truncate [[data-collapsed]_&]:sr-only\",\n itemHint: \"ml-auto hidden items-center gap-0.5 text-fg-secondary group-hover/item:flex group-focus-visible/item:flex [[data-collapsed]_&]:!hidden\",\n itemBadge:\n \"ml-auto inline-flex min-w-5 items-center justify-center rounded-full bg-accent px-1.5 text-[11px] font-bold text-on-accent \" +\n \"[[data-collapsed]_&]:absolute [[data-collapsed]_&]:right-1.5 [[data-collapsed]_&]:top-1 [[data-collapsed]_&]:min-w-4 [[data-collapsed]_&]:px-1 [[data-collapsed]_&]:text-[10px]\",\n footer: \"shrink-0 border-t border-border-subtle p-2\",\n collapse:\n \"hidden h-9 w-full items-center gap-2 rounded-lg px-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg md:flex \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0\",\n body: \"flex min-w-0 flex-1 flex-col\",\n header:\n \"sticky top-0 z-30 flex h-14 shrink-0 items-center gap-3 border-b border-border-subtle bg-surface-0/85 px-4 backdrop-blur-xl md:px-6\",\n menuButton:\n \"inline-flex h-9 w-9 items-center justify-center rounded-lg border border-border-subtle bg-surface-1 text-fg md:hidden \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n title: \"min-w-0 flex-1 truncate font-display text-base font-bold tracking-tight\",\n search:\n \"inline-flex h-9 min-w-9 items-center justify-center gap-2 rounded-lg border border-border-subtle bg-surface-1 px-2.5 text-sm text-fg-secondary transition-colors \" +\n \"hover:border-border-default hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring md:w-56 md:justify-start [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0\",\n searchLabel: \"sr-only md:not-sr-only md:flex-1 md:truncate md:text-left\",\n searchKeys: \"hidden items-center gap-0.5 md:flex\",\n actions: \"ml-auto flex shrink-0 items-center gap-2\",\n main: \"min-w-0 flex-1 px-4 py-6 md:px-6 md:py-8\",\n },\n});\nconst s = appShell();\n\ninterface ShellState {\n collapsed: boolean;\n setCollapsed: (value: boolean) => void;\n open: boolean;\n setOpen: (value: boolean) => void;\n inDrawer: boolean;\n}\nconst ShellContext = React.createContext<ShellState | null>(null);\nconst useShell = () => {\n const ctx = React.useContext(ShellContext);\n if (!ctx) throw new Error(\"AppShell parts must be inside <AppShell.Root>\");\n return ctx;\n};\n\nexport type AppShellRootProps = React.ComponentProps<\"div\"> & {\n /** The sidebar starts collapsed to its icons (desktop). */\n defaultCollapsed?: boolean;\n /** Controlled collapse (desktop): pair with `onCollapsedChange` to persist the choice. */\n collapsed?: boolean;\n /** Called when the sidebar collapses or expands. */\n onCollapsedChange?: (collapsed: boolean) => void;\n /** The words of the \"skip to content\" link (`Skip to content`), the first tab stop; it lands on `AppShell.Main`. Without it, no link. */\n skipLabel?: string;\n /**\n * The shortcut that folds and unfolds the sidebar (a combination: `mod+b` is ⌘B on a Mac, Ctrl+B elsewhere), or `false`\n * for none.\n * @default \"mod+b\"\n */\n collapseShortcut?: string | false;\n};\n\n/** The shell: holds the collapse (desktop) and the drawer (phone) state. Children: Sidebar, then Body. */\nexport function AppShellRoot({ defaultCollapsed = false, collapsed: controlled, onCollapsedChange, skipLabel, collapseShortcut = \"mod+b\", className, children, ...props }: AppShellRootProps) {\n const [own, setOwn] = React.useState(defaultCollapsed);\n const [open, setOpen] = React.useState(false);\n const collapsed = controlled ?? own;\n const setCollapsed = React.useCallback(\n (value: boolean) => {\n if (controlled === undefined) setOwn(value);\n onCollapsedChange?.(value);\n },\n [controlled, onCollapsedChange],\n );\n const value = React.useMemo(() => ({ collapsed, setCollapsed, open, setOpen, inDrawer: false }), [collapsed, setCollapsed, open]);\n useShortcuts(collapseShortcut ? { [collapseShortcut]: () => setCollapsed(!collapsed) } : {});\n return (\n <ShellContext.Provider value={value}>\n <div className={s.root({ className })} {...props}>\n {skipLabel && <SkipLink href=\"#content\">{skipLabel}</SkipLink>}\n {children}\n </div>\n </ShellContext.Provider>\n );\n}\n\nexport type AppShellSidebarProps = Omit<React.ComponentProps<\"nav\">, \"children\"> & {\n /** The navigation's accessible name (`Studio`, `Administration`). */\n label: string;\n /** The brand at the top: the product's mark and name (a link home through `asChild` of your router, or plain). */\n brand?: React.ReactNode;\n /** The sections: `AppShell.Group` and `AppShell.Item`. */\n children: React.ReactNode;\n /** At the bottom, above the collapse button: the account, a plan, the version. */\n footer?: React.ReactNode;\n /** The collapse button's words, `[collapse, expand]` (desktop only). Without it the sidebar cannot collapse. */\n collapseLabels?: readonly [string, string];\n /** The drawer's close button words (phone). */\n closeLabel: string;\n};\n\nfunction SidebarContent({ brand, children, footer, collapseLabels, closeLabel }: Pick<AppShellSidebarProps, \"brand\" | \"children\" | \"footer\" | \"collapseLabels\" | \"closeLabel\">) {\n const { collapsed, setCollapsed, inDrawer } = useShell();\n return (\n <>\n <div className={s.brand()}>\n {brand}\n {inDrawer && (\n <DialogPrimitive.Close className={cn(s.menuButton(), \"ml-auto flex\")} aria-label={closeLabel}>\n <CloseGlyph className=\"h-4 w-4\" />\n </DialogPrimitive.Close>\n )}\n </div>\n <div className={s.nav()}>{children}</div>\n {(footer || (collapseLabels && !inDrawer)) && (\n <div className={s.footer()}>\n {footer}\n {collapseLabels && !inDrawer && (\n <button type=\"button\" className={s.collapse()} aria-expanded={!collapsed} onClick={() => setCollapsed(!collapsed)}>\n <ChevronGlyph direction={collapsed ? \"right\" : \"left\"} className=\"h-4 w-4\" />\n <span className={collapsed ? \"sr-only\" : undefined}>{collapsed ? collapseLabels[1] : collapseLabels[0]}</span>\n </button>\n )}\n </div>\n )}\n </>\n );\n}\n\n/** The sidebar: on a desktop a column that collapses to its icons; on a phone the same content in a drawer. */\nexport function AppShellSidebar({ label, brand, children, footer, collapseLabels, closeLabel, className, ...props }: AppShellSidebarProps) {\n const shell = useShell();\n const content = { brand, children, footer, collapseLabels, closeLabel };\n return (\n <>\n <nav aria-label={label} data-collapsed={shell.collapsed ? \"\" : undefined} className={s.sidebar({ className })} {...props}>\n <SidebarContent {...content} />\n </nav>\n <DialogPrimitive.Root open={shell.open} onOpenChange={shell.setOpen}>\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay className={s.overlay()} />\n <DialogPrimitive.Content className={s.drawer()} aria-describedby={undefined}>\n <DialogPrimitive.Title className=\"sr-only\">{label}</DialogPrimitive.Title>\n <ShellContext.Provider value={{ ...shell, collapsed: false, inDrawer: true }}>\n <nav aria-label={label} className=\"flex min-h-0 flex-1 flex-col\" onClick={(e) => (e.target as Element).closest(\"a\") && shell.setOpen(false)}>\n <SidebarContent {...content} />\n </nav>\n </ShellContext.Provider>\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n </>\n );\n}\n\nexport type AppShellGroupProps = React.ComponentProps<\"p\"> & {\n /** The group's name, above its items (hidden when the sidebar is collapsed). */\n children: React.ReactNode;\n};\n\n/** A heading between groups of items. */\nexport function AppShellGroup({ className, ...props }: AppShellGroupProps) {\n return <p className={s.group({ className })} {...props} />;\n}\n\nexport type AppShellItemProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The item's icon (a signature icon): it stays when the sidebar collapses. */\n icon?: React.ReactNode;\n /** Its words: the accessible name, hidden visually when collapsed (the icon carries a tooltip through `title`). */\n label: string;\n /** The screen it opens is the current one: `aria-current=\"page\"`. */\n current?: boolean;\n /** A count beside it (unread, pending): a number or a few characters. */\n badge?: React.ReactNode;\n /**\n * A keyboard shortcut that goes to it: a sequence (`g d`: G then D) or a combination (`mod+1`). It clicks the item, so a\n * router link navigates. The keys are shown on hover and focus when the sidebar is open.\n */\n shortcut?: string;\n /** Renders your link (Next's `Link`) with the item's look: pass it as the only child. */\n asChild?: boolean;\n /** Your link element when `asChild`. */\n children?: React.ReactElement;\n};\n\n/** A destination of the sidebar: icon, words, a count. */\nexport function AppShellItem({ icon, label, current, badge, shortcut, asChild, children, className, ...props }: AppShellItemProps) {\n const { collapsed, inDrawer } = useShell();\n const element = React.useRef<HTMLAnchorElement>(null);\n const apple = useApple();\n // Only the sidebar's own items listen: the drawer holds a copy of them, open or not.\n useShortcuts(shortcut && !inDrawer ? { [shortcut]: () => element.current?.click() } : {});\n const Comp = asChild ? Slot.Root : \"a\";\n const inner = (\n <>\n {icon}\n <span className={s.itemLabel()}>{label}</span>\n {badge != null && <span className={s.itemBadge()}>{badge}</span>}\n {shortcut && !inDrawer ? (\n <span className={s.itemHint()} aria-hidden>\n {formatShortcut(shortcut, apple).map((key) => (\n <Kbd key={key} size=\"sm\">\n {key}\n </Kbd>\n ))}\n </span>\n ) : null}\n </>\n );\n return (\n <Comp ref={element} aria-current={current ? \"page\" : undefined} aria-keyshortcuts={shortcut ? ariaKeyShortcuts(shortcut, apple) : undefined} title={collapsed ? label : undefined} className={s.item({ className })} {...props}>\n {asChild && children ? React.cloneElement(children, undefined, inner) : inner}\n </Comp>\n );\n}\n\n/** The column right of the sidebar: Header, then Main. */\nexport function AppShellBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport type AppShellHeaderProps = Omit<React.ComponentProps<\"header\">, \"title\"> & {\n /** The screen's title (an `h1`). */\n title?: React.ReactNode;\n /** The button that opens the drawer on a phone: its words. */\n menuLabel: string;\n /** The screen's actions, on the right. */\n actions?: React.ReactNode;\n};\n\n/** The top of the screen: the drawer's button (phone), the title, the actions. Sticky. */\nexport function AppShellHeader({ title, menuLabel, actions, className, children, ...props }: AppShellHeaderProps) {\n const { open, setOpen } = useShell();\n return (\n <header className={s.header({ className })} {...props}>\n <button type=\"button\" className={s.menuButton()} aria-label={menuLabel} aria-expanded={open} aria-haspopup=\"dialog\" onClick={() => setOpen(true)}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M4 7h16M4 12h16M4 17h10\" />\n </svg>\n </button>\n {title && <h1 className={s.title()}>{title}</h1>}\n {children}\n {actions && <div className={s.actions()}>{actions}</div>}\n </header>\n );\n}\n\nexport type AppShellSearchProps = Omit<React.ComponentProps<\"button\">, \"children\" | \"onClick\"> & {\n /** The words (\"Search\", \"Search creators\"): the accessible name, shown beside the keys on a desktop. */\n label: string;\n /** Called when the button is pressed or the shortcut is typed: open your command palette (`CommandDialog`) here. */\n onOpen: () => void;\n /**\n * The shortcut that opens it (a combination); shown on its keys.\n * @default \"mod+k\"\n */\n shortcut?: string;\n};\n\n/** The header's search: a button that looks like a field (a magnifier, its words, ⌘K) and opens the app's command palette. */\nexport function AppShellSearch({ label, onOpen, shortcut = \"mod+k\", className, ...props }: AppShellSearchProps) {\n const apple = useApple();\n useShortcuts({ [shortcut]: () => onOpen() });\n return (\n <button type=\"button\" className={s.search({ className })} aria-keyshortcuts={ariaKeyShortcuts(shortcut, apple)} onClick={onOpen} {...props}>\n <SearchGlyph />\n <span className={s.searchLabel()}>{label}</span>\n <span className={s.searchKeys()} aria-hidden>\n {formatShortcut(shortcut, apple).map((key) => (\n <Kbd key={key} size=\"sm\">\n {key}\n </Kbd>\n ))}\n </span>\n </button>\n );\n}\n\n/** The screen's content. */\nexport function AppShellMain({ className, ...props }: React.ComponentProps<\"main\">) {\n return <main id=\"content\" tabIndex={-1} className={s.main({ className })} {...props} />;\n}\n\nexport const AppShell = {\n Root: AppShellRoot,\n Sidebar: AppShellSidebar,\n Group: AppShellGroup,\n Item: AppShellItem,\n Body: AppShellBody,\n Header: AppShellHeader,\n Search: AppShellSearch,\n Main: AppShellMain,\n};\n","// Server-safe. A key, or a shortcut of several (`<Kbd>⌘</Kbd><Kbd>K</Kbd>`).\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const kbdVariants = tv({\n base:\n \"inline-flex shrink-0 items-center justify-center rounded-md border border-border-default border-b-2 bg-surface-2 \" +\n \"font-mono font-semibold text-fg-secondary\",\n variants: { size: { sm: \"h-5 min-w-5 px-1 text-[10px]\", md: \"h-6 min-w-6 px-1.5 text-xs\" } },\n defaultVariants: { size: \"md\" },\n});\n\nexport type KbdProps = React.ComponentProps<\"kbd\"> & {\n /**\n * sm · md.\n * @default \"md\"\n */\n size?: VariantProps<typeof kbdVariants>[\"size\"];\n};\n\nexport function Kbd({ size, className, ...props }: KbdProps) {\n return <kbd className={kbdVariants({ size, className })} {...props} />;\n}\n","// Keyboard shortcuts for an application: a combination (`mod+k`, `shift+/`, `alt+arrowup`) or a sequence (`g d`: press G,\n// then D). `mod` is ⌘ on Apple devices and Ctrl elsewhere. Plain keys and sequences stay out of text fields; a combination\n// with `mod` works in an input (not in a rich-text editor, where ⌘B is bold). Nothing is decided here about the words.\nimport * as React from \"react\";\n\nimport { useLatest } from \"../media\";\n\nexport type ShortcutMap = Readonly<Record<string, ((event: KeyboardEvent) => void) | undefined>>;\n\nconst isApple = () => typeof navigator !== \"undefined\" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);\n\nconst ALIASES: Record<string, string> = { esc: \"escape\", return: \"enter\", space: \" \", spacebar: \" \", up: \"arrowup\", down: \"arrowdown\", left: \"arrowleft\", right: \"arrowright\", del: \"delete\", plus: \"+\" };\ntype Modifier = \"mod\" | \"ctrl\" | \"alt\" | \"shift\" | \"meta\";\n\ntype Combo = { key: string; mod: boolean; ctrl: boolean; alt: boolean; shift: boolean; meta: boolean };\n\n/** `\"mod+shift+k\"` → its parts. A lone `+` key is written `plus`. */\nexport function parseCombo(combo: string): Combo {\n const parts = combo.toLowerCase().split(\"+\").filter(Boolean);\n const key = ALIASES[parts.at(-1) ?? \"\"] ?? parts.at(-1) ?? \"\";\n const has = (name: Modifier) => parts.slice(0, -1).includes(name);\n return { key, mod: has(\"mod\"), ctrl: has(\"ctrl\"), alt: has(\"alt\"), shift: has(\"shift\"), meta: has(\"meta\") };\n}\n\n/** Whether a key event is this combination: its modifiers exactly (`mod` is ⌘ or Ctrl by platform), then its key. */\nexport function matchesCombo(event: Pick<KeyboardEvent, \"key\" | \"metaKey\" | \"ctrlKey\" | \"altKey\" | \"shiftKey\">, combo: string, apple = isApple()): boolean {\n const want = parseCombo(combo);\n const meta = want.meta || (want.mod && apple);\n const ctrl = want.ctrl || (want.mod && !apple);\n if (event.metaKey !== meta || event.ctrlKey !== ctrl || event.altKey !== want.alt) return false;\n // Shift is only checked when the binding names it: `?` and `/` need it on most layouts.\n if (want.shift && !event.shiftKey) return false;\n return event.key.toLowerCase() === want.key;\n}\n\n/** The keys of a shortcut to show on a keycap: `[\"⌘\", \"K\"]` on a Mac, `[\"Ctrl\", \"K\"]` elsewhere; a sequence `g d` is `[\"G\", \"D\"]`. */\nexport function formatShortcut(shortcut: string, apple = isApple()): string[] {\n if (shortcut.includes(\" \")) return shortcut.split(/\\s+/).map((key) => key.toUpperCase());\n const parts = shortcut.split(\"+\").filter(Boolean);\n const key = parts.at(-1) ?? \"\";\n const names: Record<string, [string, string]> = { mod: [\"⌘\", \"Ctrl\"], meta: [\"⌘\", \"Win\"], ctrl: [\"⌃\", \"Ctrl\"], alt: [\"⌥\", \"Alt\"], shift: [\"⇧\", \"Shift\"] };\n const shown = parts.slice(0, -1).map((part) => names[part.toLowerCase()]?.[apple ? 0 : 1] ?? part);\n const glyph: Record<string, string> = { escape: \"Esc\", enter: \"↵\", arrowup: \"↑\", arrowdown: \"↓\", arrowleft: \"←\", arrowright: \"→\", \" \": \"Space\" };\n const last = glyph[ALIASES[key.toLowerCase()] ?? key.toLowerCase()] ?? key.toUpperCase();\n return [...shown, last];\n}\n\nconst noop = () => () => undefined;\n\n/** Whether the person is on an Apple device — `false` on the server and in the first client render (no mismatch), then right. */\nexport function useApple(): boolean {\n return React.useSyncExternalStore(noop, isApple, () => false);\n}\n\n/** The `aria-keyshortcuts` of a combination (`Control+K`, `Meta+K` on a Mac); a sequence has none (it is not a chord). */\nexport function ariaKeyShortcuts(shortcut: string, apple = isApple()): string | undefined {\n if (shortcut.includes(\" \")) return undefined;\n const parts = shortcut.split(\"+\").filter(Boolean);\n const names: Record<string, string> = { mod: apple ? \"Meta\" : \"Control\", meta: \"Meta\", ctrl: \"Control\", alt: \"Alt\", shift: \"Shift\" };\n const key = parts.at(-1) ?? \"\";\n return [...parts.slice(0, -1).map((part) => names[part.toLowerCase()] ?? part), key.length === 1 ? key.toUpperCase() : key.charAt(0).toUpperCase() + key.slice(1)].join(\"+\");\n}\n\n/** Whether a key press happens in something you type in. */\nfunction isEditable(target: EventTarget | null): { field: boolean; rich: boolean } {\n const element = target instanceof HTMLElement ? target : null;\n if (!element) return { field: false, rich: false };\n const rich = element.isContentEditable;\n return { field: rich || /^(input|textarea|select)$/i.test(element.tagName), rich };\n}\n\n/**\n * Binds shortcuts for as long as the component lives (`enabled` turns them off). Each key is a combination or a sequence,\n * each value runs when it is pressed; the handler may change on every render. A shortcut that fires is `preventDefault`ed.\n * A sequence waits `timeout` ms for its next key.\n */\nexport function useShortcuts(map: ShortcutMap, { enabled = true, timeout = 900 }: { enabled?: boolean; timeout?: number } = {}) {\n const latest = useLatest(map);\n const names = Object.keys(map).sort().join(\"\\n\");\n React.useEffect(() => {\n if (!enabled) return;\n const bindings = names.split(\"\\n\").filter(Boolean);\n let buffer: { key: string; at: number }[] = [];\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.isComposing || event.repeat || !event.key) return;\n const editing = isEditable(event.target);\n const chord = event.metaKey || event.ctrlKey || event.altKey;\n const now = Date.now();\n buffer = [...buffer.filter((entry) => now - entry.at <= timeout), { key: event.key.toLowerCase(), at: now }].slice(-4);\n for (const binding of bindings) {\n const handler = latest.current[binding];\n if (!handler) continue;\n const keys = binding.toLowerCase().split(/\\s+/).map((key) => ALIASES[key] ?? key);\n const fired =\n keys.length > 1\n ? !chord && !editing.field && buffer.length >= keys.length && keys.every((key, i) => buffer[buffer.length - keys.length + i]?.key === key)\n : matchesCombo(event, binding) && (chord ? !editing.rich : !editing.field);\n if (!fired) continue;\n event.preventDefault();\n buffer = [];\n handler(event);\n return;\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [enabled, names, latest, timeout]);\n}\n","// Shared by the data and media primitives (client): the clock format, the reduced-motion preference, the\n// in-view observer, a debounced callback. Never an entry of its own.\nimport * as React from \"react\";\n\n/** Seconds as a clock: `75` → `1:15`, `3725` → `1:02:05`. Negative or unknown values read `0:00`. */\nexport function formatClock(seconds: number): string {\n const s = Number.isFinite(seconds) && seconds > 0 ? Math.floor(seconds) : 0;\n const h = Math.floor(s / 3600);\n const m = Math.floor((s % 3600) / 60);\n const rest = String(s % 60).padStart(2, \"0\");\n return h > 0 ? `${h}:${String(m).padStart(2, \"0\")}:${rest}` : `${m}:${rest}`;\n}\n\n/** Clamps `value` between `min` and `max`. */\nexport const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\nconst REDUCE = \"(prefers-reduced-motion: reduce)\";\nconst subscribeReduce = (notify: () => void) => {\n if (typeof window === \"undefined\" || !window.matchMedia) return () => undefined;\n const query = window.matchMedia(REDUCE);\n query.addEventListener?.(\"change\", notify);\n return () => query.removeEventListener?.(\"change\", notify);\n};\n\n/** `true` when the person asked for less motion (`prefers-reduced-motion: reduce`); follows a change of the setting. */\nexport function usePrefersReducedMotion(): boolean {\n return React.useSyncExternalStore(\n subscribeReduce,\n () => (typeof window !== \"undefined\" && window.matchMedia ? window.matchMedia(REDUCE).matches : false),\n () => false,\n );\n}\n\n/** The latest value of a callback, for an effect or an event that must not re-subscribe when it changes. */\nexport function useLatest<T>(value: T) {\n const ref = React.useRef(value);\n React.useLayoutEffect(() => {\n ref.current = value;\n });\n return ref;\n}\n\n/** Calls `onChange(visible)` when at least `threshold` of the element enters or leaves the viewport. */\nexport function useInView(ref: React.RefObject<Element | null>, onChange: (visible: boolean) => void, enabled = true, threshold = 0.25) {\n const latest = useLatest(onChange);\n React.useEffect(() => {\n const element = ref.current;\n if (!enabled || !element || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(([entry]) => entry && latest.current(entry.isIntersecting), { threshold });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref, enabled, threshold, latest]);\n}\n\n/** A value controlled by a prop when it is given, held inside otherwise; `set` calls `onChange` either way. */\nexport function useControllable<T>(value: T | undefined, defaultValue: T, onChange?: (next: T) => void) {\n const [inner, setInner] = React.useState(defaultValue);\n const controlled = value !== undefined;\n const current = controlled ? value : inner;\n const set = React.useCallback(\n (next: T) => {\n if (!controlled) setInner(next);\n onChange?.(next);\n },\n [controlled, onChange],\n );\n return [current, set] as const;\n}\n\n/** Starts a media element without an unhandled rejection (autoplay refused, the source replaced meanwhile). */\nexport function playSafely(media: HTMLMediaElement | null | undefined) {\n try {\n const started = media?.play() as Promise<void> | undefined;\n started?.catch?.(() => undefined);\n } catch {\n // Not playable here (no media support): the controls stay as they are.\n }\n}\n"],"mappings":"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","names":["React","tv","React","key","jsx","tv","value"]}
1
+ {"version":3,"sources":["../src/app-shell/app-shell.tsx","../src/kbd/kbd.tsx","../src/app-shell/shortcuts.ts","../src/media.ts"],"sourcesContent":["// Client (the collapse, the drawer, the shortcuts). The shell of an application screen, read from the products' consoles\n// (Orochia admin and studio, Orazaka web-admin and web-client): a sidebar of sections that collapses to its icons on a\n// desktop, a header with the screen's title, a search that opens the app's command palette and its actions, the content —\n// and below `md` the sidebar becomes a drawer opened from the header (Radix Dialog: focus trap, Escape, focus return).\n// Keyboard: ⌘/Ctrl+B folds the sidebar, ⌘/Ctrl+K opens the search, `g` then a letter goes to a section (`shortcut` of an\n// item). Words arrive as props; links through `asChild`.\n// `desktop` (ADR-002): the shell is the window of a desktop app (the Orazaka Mac app, Tauri 2): the sidebar is always\n// there (a window has a minimum width, no drawer), its top clears the traffic lights, the header and the sidebar's top are\n// the title bar (`data-tauri-drag-region`: dragging them moves the window), the density is the desktop's (32 px rows,\n// 13 px text, a 48 px header), the chrome is not selectable, and the content scrolls under a fixed header.\nimport { SkipLink } from \"@krizaka/ui/skip-link\";\nimport { Dialog as DialogPrimitive, Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { ChevronGlyph, CloseGlyph, SearchGlyph } from \"../glyphs\";\nimport { Kbd } from \"../kbd\";\nimport { ariaKeyShortcuts, formatShortcut, useApple, useShortcuts } from \"./shortcuts\";\n\nexport const appShell = tv({\n slots: {\n root: \"flex min-h-dvh w-full bg-surface-0 text-fg data-desktop:h-[var(--kz-window-height,100dvh)] data-desktop:overflow-hidden\",\n sidebar:\n \"sticky top-0 hidden h-dvh shrink-0 flex-col border-r border-border-subtle bg-surface-1 transition-[width] duration-300 motion-reduce:transition-none md:flex \" +\n \"w-64 data-collapsed:w-[4.25rem] \" +\n \"[[data-desktop]_&]:static [[data-desktop]_&]:flex [[data-desktop]_&]:h-auto [[data-desktop]_&]:w-60 [[data-desktop]_&]:select-none [[data-desktop]_&]:data-collapsed:w-[4.75rem]\",\n titlebar: \"h-[var(--kz-titlebar-inset,1.75rem)] shrink-0\",\n drawer:\n \"kz-dialog fixed inset-y-0 left-0 z-50 flex w-[min(20rem,88vw)] flex-col border-r border-border-default bg-surface-1 pl-[env(safe-area-inset-left)] shadow-lg focus:outline-hidden\",\n overlay: \"kz-overlay fixed inset-0 z-50 bg-overlay backdrop-blur-xs\",\n brand: \"flex h-14 shrink-0 items-center gap-2.5 px-4 font-display text-[15px] font-bold tracking-tight [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0 [[data-desktop]_&]:h-11\",\n nav: \"flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 py-2\",\n group: \"mt-3 mb-1 px-3 font-mono text-[10.5px] font-semibold uppercase tracking-[0.14em] text-fg-secondary [[data-collapsed]_&]:sr-only\",\n item:\n \"group/item relative flex h-10 items-center gap-3 rounded-lg px-3 text-sm font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n \"aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg \" +\n \"aria-[current=page]:before:absolute aria-[current=page]:before:inset-y-2 aria-[current=page]:before:-left-2 aria-[current=page]:before:w-1 aria-[current=page]:before:rounded-full aria-[current=page]:before:bg-accent \" +\n \"[[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0 [&>svg]:h-[18px] [&>svg]:w-[18px] [&>svg]:shrink-0 \" +\n \"[[data-desktop]_&]:h-8 [[data-desktop]_&]:cursor-default [[data-desktop]_&]:rounded-md [[data-desktop]_&]:text-[13px] [[data-desktop]_&_svg]:h-4 [[data-desktop]_&_svg]:w-4\",\n itemLabel: \"min-w-0 flex-1 truncate [[data-collapsed]_&]:sr-only\",\n itemHint: \"ml-auto hidden items-center gap-0.5 text-fg-secondary group-hover/item:flex group-focus-visible/item:flex [[data-collapsed]_&]:!hidden\",\n itemBadge:\n \"ml-auto inline-flex min-w-5 items-center justify-center rounded-full bg-accent px-1.5 text-[11px] font-bold text-on-accent \" +\n \"[[data-collapsed]_&]:absolute [[data-collapsed]_&]:right-1.5 [[data-collapsed]_&]:top-1 [[data-collapsed]_&]:min-w-4 [[data-collapsed]_&]:px-1 [[data-collapsed]_&]:text-[10px]\",\n footer: \"shrink-0 border-t border-border-subtle p-2\",\n collapse:\n \"hidden h-9 w-full items-center gap-2 rounded-lg px-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg md:flex \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring [[data-collapsed]_&]:justify-center [[data-collapsed]_&]:px-0\",\n body: \"flex min-w-0 flex-1 flex-col [[data-desktop]_&]:min-h-0 [[data-desktop]_&]:overflow-y-auto\",\n header:\n \"sticky top-0 z-30 flex h-14 shrink-0 items-center gap-3 border-b border-border-subtle bg-surface-0/85 px-4 backdrop-blur-xl md:px-6 \" +\n \"[[data-desktop]_&]:h-12 [[data-desktop]_&]:select-none [[data-desktop]_&]:px-5\",\n menuButton:\n \"inline-flex h-9 w-9 items-center justify-center rounded-lg border border-border-subtle bg-surface-1 text-fg md:hidden [[data-desktop]_&]:hidden \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n title: \"min-w-0 flex-1 truncate font-display text-base font-bold tracking-tight [[data-desktop]_&]:text-[15px]\",\n search:\n \"inline-flex h-9 min-w-9 items-center justify-center gap-2 rounded-lg border border-border-subtle bg-surface-1 px-2.5 text-sm text-fg-secondary transition-colors \" +\n \"hover:border-border-default hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring md:w-56 md:justify-start [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0\",\n searchLabel: \"sr-only md:not-sr-only md:flex-1 md:truncate md:text-left\",\n searchKeys: \"hidden items-center gap-0.5 md:flex\",\n actions: \"ml-auto flex shrink-0 items-center gap-2\",\n main: \"min-w-0 flex-1 px-4 py-6 md:px-6 md:py-8 [[data-desktop]_&]:px-6 [[data-desktop]_&]:py-6\",\n },\n});\nconst s = appShell();\n\ninterface ShellState {\n collapsed: boolean;\n setCollapsed: (value: boolean) => void;\n open: boolean;\n setOpen: (value: boolean) => void;\n inDrawer: boolean;\n desktop: boolean;\n}\nconst ShellContext = React.createContext<ShellState | null>(null);\nconst useShell = () => {\n const ctx = React.useContext(ShellContext);\n if (!ctx) throw new Error(\"AppShell parts must be inside <AppShell.Root>\");\n return ctx;\n};\n\nexport type AppShellRootProps = React.ComponentProps<\"div\"> & {\n /** The sidebar starts collapsed to its icons (desktop). */\n defaultCollapsed?: boolean;\n /** Controlled collapse (desktop): pair with `onCollapsedChange` to persist the choice. */\n collapsed?: boolean;\n /** Called when the sidebar collapses or expands. */\n onCollapsedChange?: (collapsed: boolean) => void;\n /** The words of the \"skip to content\" link (`Skip to content`), the first tab stop; it lands on `AppShell.Main`. Without it, no link. */\n skipLabel?: string;\n /**\n * The shortcut that folds and unfolds the sidebar (a combination: `mod+b` is ⌘B on a Mac, Ctrl+B elsewhere), or `false`\n * for none.\n * @default \"mod+b\"\n */\n collapseShortcut?: string | false;\n /**\n * The shell is a desktop app's window (the Orazaka Mac app, Tauri 2 — ADR-002): no drawer, the sidebar's top clears the\n * window's traffic lights (`--kz-titlebar-inset`, 28 px; the window's height is `--kz-window-height`, the viewport by default), the header and that top move the window\n * (`data-tauri-drag-region`), a denser layout, the chrome not selectable. In a browser it is a fixed-height shell.\n */\n desktop?: boolean;\n};\n\n/** The shell: holds the collapse (desktop) and the drawer (phone) state. Children: Sidebar, then Body. */\nexport function AppShellRoot({ defaultCollapsed = false, collapsed: controlled, onCollapsedChange, skipLabel, collapseShortcut = \"mod+b\", desktop = false, className, children, ...props }: AppShellRootProps) {\n const [own, setOwn] = React.useState(defaultCollapsed);\n const [open, setOpen] = React.useState(false);\n const collapsed = controlled ?? own;\n const setCollapsed = React.useCallback(\n (value: boolean) => {\n if (controlled === undefined) setOwn(value);\n onCollapsedChange?.(value);\n },\n [controlled, onCollapsedChange],\n );\n const value = React.useMemo(() => ({ collapsed, setCollapsed, open, setOpen, inDrawer: false, desktop }), [collapsed, setCollapsed, open, desktop]);\n useShortcuts(collapseShortcut ? { [collapseShortcut]: () => setCollapsed(!collapsed) } : {});\n return (\n <ShellContext.Provider value={value}>\n <div data-desktop={desktop ? \"\" : undefined} className={s.root({ className })} {...props}>\n {skipLabel && <SkipLink href=\"#content\">{skipLabel}</SkipLink>}\n {children}\n </div>\n </ShellContext.Provider>\n );\n}\n\nexport type AppShellSidebarProps = Omit<React.ComponentProps<\"nav\">, \"children\"> & {\n /** The navigation's accessible name (`Studio`, `Administration`). */\n label: string;\n /** The brand at the top: the product's mark and name (a link home through `asChild` of your router, or plain). */\n brand?: React.ReactNode;\n /** The sections: `AppShell.Group` and `AppShell.Item`. */\n children: React.ReactNode;\n /** At the bottom, above the collapse button: the account, a plan, the version. */\n footer?: React.ReactNode;\n /** The collapse button's words, `[collapse, expand]` (desktop only). Without it the sidebar cannot collapse. */\n collapseLabels?: readonly [string, string];\n /** The drawer's close button words (phone). */\n closeLabel: string;\n};\n\nfunction SidebarContent({ brand, children, footer, collapseLabels, closeLabel }: Pick<AppShellSidebarProps, \"brand\" | \"children\" | \"footer\" | \"collapseLabels\" | \"closeLabel\">) {\n const { collapsed, setCollapsed, inDrawer, desktop } = useShell();\n const drag = desktop ? { \"data-tauri-drag-region\": \"\" } : {};\n return (\n <>\n {desktop && <div aria-hidden className={s.titlebar()} {...drag} />}\n <div className={s.brand()} {...drag}>\n {brand}\n {inDrawer && (\n <DialogPrimitive.Close className={cn(s.menuButton(), \"ml-auto flex\")} aria-label={closeLabel}>\n <CloseGlyph className=\"h-4 w-4\" />\n </DialogPrimitive.Close>\n )}\n </div>\n <div className={s.nav()}>{children}</div>\n {(footer || (collapseLabels && !inDrawer)) && (\n <div className={s.footer()}>\n {footer}\n {collapseLabels && !inDrawer && (\n <button type=\"button\" className={s.collapse()} aria-expanded={!collapsed} onClick={() => setCollapsed(!collapsed)}>\n <ChevronGlyph direction={collapsed ? \"right\" : \"left\"} className=\"h-4 w-4\" />\n <span className={collapsed ? \"sr-only\" : undefined}>{collapsed ? collapseLabels[1] : collapseLabels[0]}</span>\n </button>\n )}\n </div>\n )}\n </>\n );\n}\n\n/** The sidebar: on a desktop a column that collapses to its icons; on a phone the same content in a drawer. */\nexport function AppShellSidebar({ label, brand, children, footer, collapseLabels, closeLabel, className, ...props }: AppShellSidebarProps) {\n const shell = useShell();\n const content = { brand, children, footer, collapseLabels, closeLabel };\n return (\n <>\n <nav aria-label={label} data-collapsed={shell.collapsed ? \"\" : undefined} className={s.sidebar({ className })} {...props}>\n <SidebarContent {...content} />\n </nav>\n {!shell.desktop && (\n <DialogPrimitive.Root open={shell.open} onOpenChange={shell.setOpen}>\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay className={s.overlay()} />\n <DialogPrimitive.Content className={s.drawer()} aria-describedby={undefined}>\n <DialogPrimitive.Title className=\"sr-only\">{label}</DialogPrimitive.Title>\n <ShellContext.Provider value={{ ...shell, collapsed: false, inDrawer: true }}>\n <nav aria-label={label} className=\"flex min-h-0 flex-1 flex-col\" onClick={(e) => (e.target as Element).closest(\"a\") && shell.setOpen(false)}>\n <SidebarContent {...content} />\n </nav>\n </ShellContext.Provider>\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n )}\n </>\n );\n}\n\nexport type AppShellGroupProps = React.ComponentProps<\"p\"> & {\n /** The group's name, above its items (hidden when the sidebar is collapsed). */\n children: React.ReactNode;\n};\n\n/** A heading between groups of items. */\nexport function AppShellGroup({ className, ...props }: AppShellGroupProps) {\n return <p className={s.group({ className })} {...props} />;\n}\n\nexport type AppShellItemProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The item's icon (a signature icon): it stays when the sidebar collapses. */\n icon?: React.ReactNode;\n /** Its words: the accessible name, hidden visually when collapsed (the icon carries a tooltip through `title`). */\n label: string;\n /** The screen it opens is the current one: `aria-current=\"page\"`. */\n current?: boolean;\n /** A count beside it (unread, pending): a number or a few characters. */\n badge?: React.ReactNode;\n /**\n * A keyboard shortcut that goes to it: a sequence (`g d`: G then D) or a combination (`mod+1`). It clicks the item, so a\n * router link navigates. The keys are shown on hover and focus when the sidebar is open.\n */\n shortcut?: string;\n /** Renders your link (Next's `Link`) with the item's look: pass it as the only child. */\n asChild?: boolean;\n /** Your link element when `asChild`. */\n children?: React.ReactElement;\n};\n\n/** A destination of the sidebar: icon, words, a count. */\nexport function AppShellItem({ icon, label, current, badge, shortcut, asChild, children, className, ...props }: AppShellItemProps) {\n const { collapsed, inDrawer } = useShell();\n const element = React.useRef<HTMLAnchorElement>(null);\n const apple = useApple();\n // Only the sidebar's own items listen: the drawer holds a copy of them, open or not.\n useShortcuts(shortcut && !inDrawer ? { [shortcut]: () => element.current?.click() } : {});\n const Comp = asChild ? Slot.Root : \"a\";\n const inner = (\n <>\n {icon}\n <span className={s.itemLabel()}>{label}</span>\n {badge != null && <span className={s.itemBadge()}>{badge}</span>}\n {shortcut && !inDrawer ? (\n <span className={s.itemHint()} aria-hidden>\n {formatShortcut(shortcut, apple).map((key) => (\n <Kbd key={key} size=\"sm\">\n {key}\n </Kbd>\n ))}\n </span>\n ) : null}\n </>\n );\n return (\n <Comp ref={element} aria-current={current ? \"page\" : undefined} aria-keyshortcuts={shortcut ? ariaKeyShortcuts(shortcut, apple) : undefined} title={collapsed ? label : undefined} className={s.item({ className })} {...props}>\n {asChild && children ? React.cloneElement(children, undefined, inner) : inner}\n </Comp>\n );\n}\n\n/** The column right of the sidebar: Header, then Main. */\nexport function AppShellBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport type AppShellHeaderProps = Omit<React.ComponentProps<\"header\">, \"title\"> & {\n /** The screen's title (an `h1`). */\n title?: React.ReactNode;\n /** The button that opens the drawer on a phone: its words. */\n menuLabel: string;\n /** The screen's actions, on the right. */\n actions?: React.ReactNode;\n};\n\n/** The top of the screen: the drawer's button (phone), the title, the actions. Sticky. */\nexport function AppShellHeader({ title, menuLabel, actions, className, children, ...props }: AppShellHeaderProps) {\n const { open, setOpen, desktop } = useShell();\n const drag = desktop ? { \"data-tauri-drag-region\": \"\" } : {};\n return (\n <header className={s.header({ className })} {...drag} {...props}>\n <button type=\"button\" className={s.menuButton()} aria-label={menuLabel} aria-expanded={open} aria-haspopup=\"dialog\" onClick={() => setOpen(true)}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M4 7h16M4 12h16M4 17h10\" />\n </svg>\n </button>\n {title && (\n <h1 className={s.title()} {...drag}>\n {title}\n </h1>\n )}\n {children}\n {actions && <div className={s.actions()}>{actions}</div>}\n </header>\n );\n}\n\nexport type AppShellSearchProps = Omit<React.ComponentProps<\"button\">, \"children\" | \"onClick\"> & {\n /** The words (\"Search\", \"Search creators\"): the accessible name, shown beside the keys on a desktop. */\n label: string;\n /** Called when the button is pressed or the shortcut is typed: open your command palette (`CommandDialog`) here. */\n onOpen: () => void;\n /**\n * The shortcut that opens it (a combination); shown on its keys.\n * @default \"mod+k\"\n */\n shortcut?: string;\n};\n\n/** The header's search: a button that looks like a field (a magnifier, its words, ⌘K) and opens the app's command palette. */\nexport function AppShellSearch({ label, onOpen, shortcut = \"mod+k\", className, ...props }: AppShellSearchProps) {\n const apple = useApple();\n useShortcuts({ [shortcut]: () => onOpen() });\n return (\n <button type=\"button\" className={s.search({ className })} aria-keyshortcuts={ariaKeyShortcuts(shortcut, apple)} onClick={onOpen} {...props}>\n <SearchGlyph />\n <span className={s.searchLabel()}>{label}</span>\n <span className={s.searchKeys()} aria-hidden>\n {formatShortcut(shortcut, apple).map((key) => (\n <Kbd key={key} size=\"sm\">\n {key}\n </Kbd>\n ))}\n </span>\n </button>\n );\n}\n\n/** The screen's content. */\nexport function AppShellMain({ className, ...props }: React.ComponentProps<\"main\">) {\n return <main id=\"content\" tabIndex={-1} className={s.main({ className })} {...props} />;\n}\n\nexport const AppShell = {\n Root: AppShellRoot,\n Sidebar: AppShellSidebar,\n Group: AppShellGroup,\n Item: AppShellItem,\n Body: AppShellBody,\n Header: AppShellHeader,\n Search: AppShellSearch,\n Main: AppShellMain,\n};\n","// Server-safe. A key, or a shortcut of several (`<Kbd>⌘</Kbd><Kbd>K</Kbd>`).\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const kbdVariants = tv({\n base:\n \"inline-flex shrink-0 items-center justify-center rounded-md border border-border-default border-b-2 bg-surface-2 \" +\n \"font-mono font-semibold text-fg-secondary\",\n variants: { size: { sm: \"h-5 min-w-5 px-1 text-[10px]\", md: \"h-6 min-w-6 px-1.5 text-xs\" } },\n defaultVariants: { size: \"md\" },\n});\n\nexport type KbdProps = React.ComponentProps<\"kbd\"> & {\n /**\n * sm · md.\n * @default \"md\"\n */\n size?: VariantProps<typeof kbdVariants>[\"size\"];\n};\n\nexport function Kbd({ size, className, ...props }: KbdProps) {\n return <kbd className={kbdVariants({ size, className })} {...props} />;\n}\n","// Keyboard shortcuts for an application: a combination (`mod+k`, `shift+/`, `alt+arrowup`) or a sequence (`g d`: press G,\n// then D). `mod` is ⌘ on Apple devices and Ctrl elsewhere. Plain keys and sequences stay out of text fields; a combination\n// with `mod` works in an input (not in a rich-text editor, where ⌘B is bold). Nothing is decided here about the words.\nimport * as React from \"react\";\n\nimport { useLatest } from \"../media\";\n\nexport type ShortcutMap = Readonly<Record<string, ((event: KeyboardEvent) => void) | undefined>>;\n\nconst isApple = () => typeof navigator !== \"undefined\" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);\n\nconst ALIASES: Record<string, string> = { esc: \"escape\", return: \"enter\", space: \" \", spacebar: \" \", up: \"arrowup\", down: \"arrowdown\", left: \"arrowleft\", right: \"arrowright\", del: \"delete\", plus: \"+\" };\ntype Modifier = \"mod\" | \"ctrl\" | \"alt\" | \"shift\" | \"meta\";\n\ntype Combo = { key: string; mod: boolean; ctrl: boolean; alt: boolean; shift: boolean; meta: boolean };\n\n/** `\"mod+shift+k\"` → its parts. A lone `+` key is written `plus`. */\nexport function parseCombo(combo: string): Combo {\n const parts = combo.toLowerCase().split(\"+\").filter(Boolean);\n const key = ALIASES[parts.at(-1) ?? \"\"] ?? parts.at(-1) ?? \"\";\n const has = (name: Modifier) => parts.slice(0, -1).includes(name);\n return { key, mod: has(\"mod\"), ctrl: has(\"ctrl\"), alt: has(\"alt\"), shift: has(\"shift\"), meta: has(\"meta\") };\n}\n\n/** Whether a key event is this combination: its modifiers exactly (`mod` is ⌘ or Ctrl by platform), then its key. */\nexport function matchesCombo(event: Pick<KeyboardEvent, \"key\" | \"metaKey\" | \"ctrlKey\" | \"altKey\" | \"shiftKey\">, combo: string, apple = isApple()): boolean {\n const want = parseCombo(combo);\n const meta = want.meta || (want.mod && apple);\n const ctrl = want.ctrl || (want.mod && !apple);\n if (event.metaKey !== meta || event.ctrlKey !== ctrl || event.altKey !== want.alt) return false;\n // Shift is only checked when the binding names it: `?` and `/` need it on most layouts.\n if (want.shift && !event.shiftKey) return false;\n return event.key.toLowerCase() === want.key;\n}\n\n/** The keys of a shortcut to show on a keycap: `[\"⌘\", \"K\"]` on a Mac, `[\"Ctrl\", \"K\"]` elsewhere; a sequence `g d` is `[\"G\", \"D\"]`. */\nexport function formatShortcut(shortcut: string, apple = isApple()): string[] {\n if (shortcut.includes(\" \")) return shortcut.split(/\\s+/).map((key) => key.toUpperCase());\n const parts = shortcut.split(\"+\").filter(Boolean);\n const key = parts.at(-1) ?? \"\";\n const names: Record<string, [string, string]> = { mod: [\"⌘\", \"Ctrl\"], meta: [\"⌘\", \"Win\"], ctrl: [\"⌃\", \"Ctrl\"], alt: [\"⌥\", \"Alt\"], shift: [\"⇧\", \"Shift\"] };\n const shown = parts.slice(0, -1).map((part) => names[part.toLowerCase()]?.[apple ? 0 : 1] ?? part);\n const glyph: Record<string, string> = { escape: \"Esc\", enter: \"↵\", arrowup: \"↑\", arrowdown: \"↓\", arrowleft: \"←\", arrowright: \"→\", \" \": \"Space\" };\n const last = glyph[ALIASES[key.toLowerCase()] ?? key.toLowerCase()] ?? key.toUpperCase();\n return [...shown, last];\n}\n\n/**\n * The accelerator of a combination for a desktop app's native menu bar (Tauri's `MenuItem`, Electron's — ADR-002):\n * `mod+k` → `CmdOrCtrl+K`, `shift+mod+/` → `Shift+CmdOrCtrl+/`. The menu and the shell then answer the same keys, and the\n * menu shows them. A sequence (`g d`) has none: a menu item takes one chord.\n */\nexport function acceleratorOf(shortcut: string): string | undefined {\n if (shortcut.trim().includes(\" \")) return undefined;\n const parts = shortcut.split(\"+\").filter(Boolean);\n const names: Record<string, string> = { mod: \"CmdOrCtrl\", meta: \"Super\", ctrl: \"Ctrl\", alt: \"Alt\", shift: \"Shift\" };\n const raw = (parts.at(-1) ?? \"\").toLowerCase();\n const key = ALIASES[raw] ?? raw;\n const keys: Record<string, string> = { escape: \"Escape\", enter: \"Enter\", \" \": \"Space\", arrowup: \"Up\", arrowdown: \"Down\", arrowleft: \"Left\", arrowright: \"Right\", delete: \"Delete\", backspace: \"Backspace\", tab: \"Tab\", \"+\": \"Plus\" };\n const last = keys[key] ?? (key.length === 1 ? key.toUpperCase() : key.charAt(0).toUpperCase() + key.slice(1));\n return [...parts.slice(0, -1).map((part) => names[part.toLowerCase()] ?? part), last].join(\"+\");\n}\n\nconst noop = () => () => undefined;\n\n/** Whether the person is on an Apple device — `false` on the server and in the first client render (no mismatch), then right. */\nexport function useApple(): boolean {\n return React.useSyncExternalStore(noop, isApple, () => false);\n}\n\n/** The `aria-keyshortcuts` of a combination (`Control+K`, `Meta+K` on a Mac); a sequence has none (it is not a chord). */\nexport function ariaKeyShortcuts(shortcut: string, apple = isApple()): string | undefined {\n if (shortcut.includes(\" \")) return undefined;\n const parts = shortcut.split(\"+\").filter(Boolean);\n const names: Record<string, string> = { mod: apple ? \"Meta\" : \"Control\", meta: \"Meta\", ctrl: \"Control\", alt: \"Alt\", shift: \"Shift\" };\n const key = parts.at(-1) ?? \"\";\n return [...parts.slice(0, -1).map((part) => names[part.toLowerCase()] ?? part), key.length === 1 ? key.toUpperCase() : key.charAt(0).toUpperCase() + key.slice(1)].join(\"+\");\n}\n\n/** Whether a key press happens in something you type in. */\nfunction isEditable(target: EventTarget | null): { field: boolean; rich: boolean } {\n const element = target instanceof HTMLElement ? target : null;\n if (!element) return { field: false, rich: false };\n const rich = element.isContentEditable;\n return { field: rich || /^(input|textarea|select)$/i.test(element.tagName), rich };\n}\n\n/**\n * Binds shortcuts for as long as the component lives (`enabled` turns them off). Each key is a combination or a sequence,\n * each value runs when it is pressed; the handler may change on every render. A shortcut that fires is `preventDefault`ed.\n * A sequence waits `timeout` ms for its next key.\n */\nexport function useShortcuts(map: ShortcutMap, { enabled = true, timeout = 900 }: { enabled?: boolean; timeout?: number } = {}) {\n const latest = useLatest(map);\n const names = Object.keys(map).sort().join(\"\\n\");\n React.useEffect(() => {\n if (!enabled) return;\n const bindings = names.split(\"\\n\").filter(Boolean);\n let buffer: { key: string; at: number }[] = [];\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.isComposing || event.repeat || !event.key) return;\n const editing = isEditable(event.target);\n const chord = event.metaKey || event.ctrlKey || event.altKey;\n const now = Date.now();\n buffer = [...buffer.filter((entry) => now - entry.at <= timeout), { key: event.key.toLowerCase(), at: now }].slice(-4);\n for (const binding of bindings) {\n const handler = latest.current[binding];\n if (!handler) continue;\n const keys = binding.toLowerCase().split(/\\s+/).map((key) => ALIASES[key] ?? key);\n const fired =\n keys.length > 1\n ? !chord && !editing.field && buffer.length >= keys.length && keys.every((key, i) => buffer[buffer.length - keys.length + i]?.key === key)\n : matchesCombo(event, binding) && (chord ? !editing.rich : !editing.field);\n if (!fired) continue;\n event.preventDefault();\n buffer = [];\n handler(event);\n return;\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [enabled, names, latest, timeout]);\n}\n","// Shared by the data and media primitives (client): the clock format, the reduced-motion preference, the\n// in-view observer, a debounced callback. Never an entry of its own.\nimport * as React from \"react\";\n\n/** Seconds as a clock: `75` → `1:15`, `3725` → `1:02:05`. Negative or unknown values read `0:00`. */\nexport function formatClock(seconds: number): string {\n const s = Number.isFinite(seconds) && seconds > 0 ? Math.floor(seconds) : 0;\n const h = Math.floor(s / 3600);\n const m = Math.floor((s % 3600) / 60);\n const rest = String(s % 60).padStart(2, \"0\");\n return h > 0 ? `${h}:${String(m).padStart(2, \"0\")}:${rest}` : `${m}:${rest}`;\n}\n\n/** Clamps `value` between `min` and `max`. */\nexport const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));\n\nconst REDUCE = \"(prefers-reduced-motion: reduce)\";\nconst subscribeReduce = (notify: () => void) => {\n if (typeof window === \"undefined\" || !window.matchMedia) return () => undefined;\n const query = window.matchMedia(REDUCE);\n query.addEventListener?.(\"change\", notify);\n return () => query.removeEventListener?.(\"change\", notify);\n};\n\n/** `true` when the person asked for less motion (`prefers-reduced-motion: reduce`); follows a change of the setting. */\nexport function usePrefersReducedMotion(): boolean {\n return React.useSyncExternalStore(\n subscribeReduce,\n () => (typeof window !== \"undefined\" && window.matchMedia ? window.matchMedia(REDUCE).matches : false),\n () => false,\n );\n}\n\n/** The latest value of a callback, for an effect or an event that must not re-subscribe when it changes. */\nexport function useLatest<T>(value: T) {\n const ref = React.useRef(value);\n React.useLayoutEffect(() => {\n ref.current = value;\n });\n return ref;\n}\n\n/** Calls `onChange(visible)` when at least `threshold` of the element enters or leaves the viewport. */\nexport function useInView(ref: React.RefObject<Element | null>, onChange: (visible: boolean) => void, enabled = true, threshold = 0.25) {\n const latest = useLatest(onChange);\n React.useEffect(() => {\n const element = ref.current;\n if (!enabled || !element || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(([entry]) => entry && latest.current(entry.isIntersecting), { threshold });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref, enabled, threshold, latest]);\n}\n\n/** A value controlled by a prop when it is given, held inside otherwise; `set` calls `onChange` either way. */\nexport function useControllable<T>(value: T | undefined, defaultValue: T, onChange?: (next: T) => void) {\n const [inner, setInner] = React.useState(defaultValue);\n const controlled = value !== undefined;\n const current = controlled ? value : inner;\n const set = React.useCallback(\n (next: T) => {\n if (!controlled) setInner(next);\n onChange?.(next);\n },\n [controlled, onChange],\n );\n return [current, set] as const;\n}\n\n/** Starts a media element without an unhandled rejection (autoplay refused, the source replaced meanwhile). */\nexport function playSafely(media: HTMLMediaElement | null | undefined) {\n try {\n const started = media?.play() as Promise<void> | undefined;\n started?.catch?.(() => undefined);\n } catch {\n // Not playable here (no media support): the controls stay as they are.\n }\n}\n"],"mappings":"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","names":["React","tv","React","key","jsx","tv","value"]}