@krizaka/ui 3.54.0 → 3.55.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 (495) hide show
  1. package/README.md +1 -0
  2. package/dist/account-menu.d.ts +6 -2
  3. package/dist/account-menu.js +8 -1
  4. package/dist/account-menu.js.map +1 -1
  5. package/dist/account-settings.js +28 -88
  6. package/dist/account-settings.js.map +1 -1
  7. package/dist/anatomy-plate.d.ts +4 -1
  8. package/dist/anatomy-plate.js +4 -0
  9. package/dist/anatomy-plate.js.map +1 -1
  10. package/dist/app-header/search.d.ts +63 -0
  11. package/dist/app-header/search.js +70 -0
  12. package/dist/app-header/search.js.map +1 -0
  13. package/dist/app-header.d.ts +88 -4
  14. package/dist/app-header.js +63 -5
  15. package/dist/app-header.js.map +1 -1
  16. package/dist/app-shell.js +31 -40
  17. package/dist/app-shell.js.map +1 -1
  18. package/dist/argument-card.js +3 -3
  19. package/dist/bird-plate.d.ts +3 -1
  20. package/dist/bird-plate.js +2 -2
  21. package/dist/bird-plate.js.map +1 -1
  22. package/dist/blocks.css +162 -27
  23. package/dist/chat.js +2 -2
  24. package/dist/chat.js.map +1 -1
  25. package/dist/checkbox.js +1 -1
  26. package/dist/checkbox.js.map +1 -1
  27. package/dist/chip.js +5 -98
  28. package/dist/chip.js.map +1 -1
  29. package/dist/choice-grid.js +28 -88
  30. package/dist/choice-grid.js.map +1 -1
  31. package/dist/{chunk-YGIN2YIY.js → chunk-3X3OF4TI.js} +2 -2
  32. package/dist/chunk-3X3OF4TI.js.map +1 -0
  33. package/dist/chunk-5VEVYDVC.js +11 -0
  34. package/dist/chunk-5VEVYDVC.js.map +1 -0
  35. package/dist/chunk-7U5TXA5Q.js +105 -0
  36. package/dist/chunk-7U5TXA5Q.js.map +1 -0
  37. package/dist/{chunk-KBQD6HE3.js → chunk-AEP3K4YD.js} +3 -3
  38. package/dist/{chunk-KBQD6HE3.js.map → chunk-AEP3K4YD.js.map} +1 -1
  39. package/dist/chunk-BDIU5LZB.js +18 -0
  40. package/dist/chunk-BDIU5LZB.js.map +1 -0
  41. package/dist/chunk-CSRKYZ53.js +39 -0
  42. package/dist/chunk-CSRKYZ53.js.map +1 -0
  43. package/dist/chunk-HEKDKM5Y.js +128 -0
  44. package/dist/chunk-HEKDKM5Y.js.map +1 -0
  45. package/dist/chunk-KGLRZMCY.js +16 -0
  46. package/dist/chunk-KGLRZMCY.js.map +1 -0
  47. package/dist/chunk-KID32IRJ.js +18 -0
  48. package/dist/chunk-KID32IRJ.js.map +1 -0
  49. package/dist/{chunk-ZQW7LF4Y.js → chunk-OIMXKRXF.js} +2 -2
  50. package/dist/{chunk-YHKTYFOQ.js → chunk-QWKCNSPF.js} +271 -47
  51. package/dist/chunk-QWKCNSPF.js.map +1 -0
  52. package/dist/{chunk-4LYKBSOG.js → chunk-USPOIQV5.js} +2 -2
  53. package/dist/chunk-USPOIQV5.js.map +1 -0
  54. package/dist/{chunk-7NRSPHAF.js → chunk-VB7MWE2N.js} +2 -2
  55. package/dist/{chunk-7NRSPHAF.js.map → chunk-VB7MWE2N.js.map} +1 -1
  56. package/dist/chunk-VIPSZXO4.js +103 -0
  57. package/dist/chunk-VIPSZXO4.js.map +1 -0
  58. package/dist/chunk-YCZ7N6Q6.js +385 -0
  59. package/dist/chunk-YCZ7N6Q6.js.map +1 -0
  60. package/dist/code-block.js +81 -98
  61. package/dist/code-block.js.map +1 -1
  62. package/dist/combobox.js +2 -2
  63. package/dist/component-page.d.ts +4 -1
  64. package/dist/component-page.js +5 -0
  65. package/dist/component-page.js.map +1 -1
  66. package/dist/continue-prompt.d.ts +4 -1
  67. package/dist/continue-prompt.js +4 -0
  68. package/dist/continue-prompt.js.map +1 -1
  69. package/dist/data-table.d.ts +60 -4
  70. package/dist/data-table.js +19 -7
  71. package/dist/date-picker.js +2 -2
  72. package/dist/date-picker.js.map +1 -1
  73. package/dist/detail-layout.d.ts +28 -17
  74. package/dist/detail-layout.js +73 -16
  75. package/dist/detail-layout.js.map +1 -1
  76. package/dist/doodle.d.ts +21 -0
  77. package/dist/doodle.js +39 -0
  78. package/dist/doodle.js.map +1 -0
  79. package/dist/drop-overlay.d.ts +12 -4
  80. package/dist/drop-overlay.js +16 -6
  81. package/dist/drop-overlay.js.map +1 -1
  82. package/dist/elephant.d.ts +2 -0
  83. package/dist/elephant.js +4 -0
  84. package/dist/elephant.js.map +1 -1
  85. package/dist/field.js +1 -1
  86. package/dist/field.js.map +1 -1
  87. package/dist/filter-bar.js +2 -2
  88. package/dist/force-update-screen.d.ts +5 -1
  89. package/dist/force-update-screen.js +4 -0
  90. package/dist/force-update-screen.js.map +1 -1
  91. package/dist/gallery-page.d.ts +4 -1
  92. package/dist/gallery-page.js +4 -0
  93. package/dist/gallery-page.js.map +1 -1
  94. package/dist/genui.js +5 -5
  95. package/dist/image-cropper.d.ts +10 -2
  96. package/dist/image-cropper.js +4 -0
  97. package/dist/image-cropper.js.map +1 -1
  98. package/dist/kanban.d.ts +3 -0
  99. package/dist/kanban.js +4 -0
  100. package/dist/kanban.js.map +1 -1
  101. package/dist/landscape.d.ts +4 -1
  102. package/dist/landscape.js +4 -0
  103. package/dist/landscape.js.map +1 -1
  104. package/dist/list.js +1 -1
  105. package/dist/maintenance-screen.d.ts +5 -1
  106. package/dist/maintenance-screen.js +4 -0
  107. package/dist/maintenance-screen.js.map +1 -1
  108. package/dist/map.js +6 -0
  109. package/dist/map.js.map +1 -1
  110. package/dist/markdown.d.ts +5 -1
  111. package/dist/markdown.js +12 -5
  112. package/dist/markdown.js.map +1 -1
  113. package/dist/match-dialog.d.ts +4 -1
  114. package/dist/match-dialog.js +4 -0
  115. package/dist/match-dialog.js.map +1 -1
  116. package/dist/media-capture.d.ts +6 -1
  117. package/dist/media-capture.js +4 -0
  118. package/dist/media-capture.js.map +1 -1
  119. package/dist/meter.js +5 -121
  120. package/dist/meter.js.map +1 -1
  121. package/dist/native/map.js +6 -0
  122. package/dist/native/map.js.map +1 -1
  123. package/dist/native/markdown.d.ts +9 -2
  124. package/dist/native/markdown.js +46 -7
  125. package/dist/native/markdown.js.map +1 -1
  126. package/dist/native/media-capture.d.ts +1 -0
  127. package/dist/native/media-capture.js +5 -0
  128. package/dist/native/media-capture.js.map +1 -1
  129. package/dist/native/vertical-video.d.ts +8 -2
  130. package/dist/native/vertical-video.js +6 -0
  131. package/dist/native/vertical-video.js.map +1 -1
  132. package/dist/native.d.ts +94 -4
  133. package/dist/native.js +1236 -1110
  134. package/dist/native.js.map +1 -1
  135. package/dist/nav-bar/me.d.ts +32 -0
  136. package/dist/nav-bar/me.js +23 -0
  137. package/dist/nav-bar/me.js.map +1 -0
  138. package/dist/nav-bar.d.ts +60 -2
  139. package/dist/nav-bar.js +92 -48
  140. package/dist/nav-bar.js.map +1 -1
  141. package/dist/notification-preferences.d.ts +151 -0
  142. package/dist/notification-preferences.js +77 -0
  143. package/dist/notification-preferences.js.map +1 -0
  144. package/dist/page-header.js +1 -1
  145. package/dist/page-header.js.map +1 -1
  146. package/dist/pointer-light.js +5 -0
  147. package/dist/pointer-light.js.map +1 -1
  148. package/dist/product-page.d.ts +4 -1
  149. package/dist/product-page.js +4 -0
  150. package/dist/product-page.js.map +1 -1
  151. package/dist/profile-card.d.ts +119 -1
  152. package/dist/profile-card.js +68 -21
  153. package/dist/profile-card.js.map +1 -1
  154. package/dist/promise-card.d.ts +4 -1
  155. package/dist/promise-card.js +4 -0
  156. package/dist/promise-card.js.map +1 -1
  157. package/dist/quota-meter.d.ts +113 -0
  158. package/dist/quota-meter.js +58 -0
  159. package/dist/quota-meter.js.map +1 -0
  160. package/dist/radio-group.js +6 -8
  161. package/dist/radio-group.js.map +1 -1
  162. package/dist/rail-nav.d.ts +18 -2
  163. package/dist/rail-nav.js +25 -2
  164. package/dist/rail-nav.js.map +1 -1
  165. package/dist/retro-tv.d.ts +30 -0
  166. package/dist/retro-tv.js +124 -0
  167. package/dist/retro-tv.js.map +1 -0
  168. package/dist/router.d.ts +12 -1
  169. package/dist/router.js +85 -8
  170. package/dist/router.js.map +1 -1
  171. package/dist/scroll-stage.d.ts +5 -1
  172. package/dist/scroll-stage.js +5 -0
  173. package/dist/scroll-stage.js.map +1 -1
  174. package/dist/search-field.js +1 -1
  175. package/dist/showcase.d.ts +9 -2
  176. package/dist/showcase.js +5 -0
  177. package/dist/showcase.js.map +1 -1
  178. package/dist/signature.d.ts +19 -0
  179. package/dist/signature.js +39 -0
  180. package/dist/signature.js.map +1 -0
  181. package/dist/site-footer.js +1 -1
  182. package/dist/sites.js +1 -1
  183. package/dist/sites.js.map +1 -1
  184. package/dist/slot.d.ts +1 -1
  185. package/dist/stat.js +1 -1
  186. package/dist/stat.js.map +1 -1
  187. package/dist/status-page.d.ts +4 -1
  188. package/dist/status-page.js +5 -0
  189. package/dist/status-page.js.map +1 -1
  190. package/dist/stuck.d.ts +27 -0
  191. package/dist/stuck.js +26 -0
  192. package/dist/stuck.js.map +1 -0
  193. package/dist/swipe-deck.d.ts +9 -2
  194. package/dist/swipe-deck.js +5 -0
  195. package/dist/swipe-deck.js.map +1 -1
  196. package/dist/switch.js +4 -32
  197. package/dist/switch.js.map +1 -1
  198. package/dist/tabs.d.ts +47 -8
  199. package/dist/tabs.js +62 -12
  200. package/dist/tabs.js.map +1 -1
  201. package/dist/tag-input.js +2 -2
  202. package/dist/tag-selector.js +1 -1
  203. package/dist/terminal-replay.d.ts +4 -1
  204. package/dist/terminal-replay.js +4 -0
  205. package/dist/terminal-replay.js.map +1 -1
  206. package/dist/tree-view.js +4 -0
  207. package/dist/tree-view.js.map +1 -1
  208. package/dist/update-prompt.d.ts +5 -1
  209. package/dist/update-prompt.js +4 -0
  210. package/dist/update-prompt.js.map +1 -1
  211. package/dist/video-player.js +7 -376
  212. package/dist/video-player.js.map +1 -1
  213. package/dist/video-trimmer.d.ts +6 -1
  214. package/dist/video-trimmer.js +4 -0
  215. package/dist/video-trimmer.js.map +1 -1
  216. package/package.json +141 -29
  217. package/registry/account-menu.json +9 -8
  218. package/registry/account-settings.json +2 -2
  219. package/registry/achievement.json +3 -4
  220. package/registry/action-bar.json +3 -3
  221. package/registry/action-sheet.json +1 -0
  222. package/registry/activity-feed.json +2 -1
  223. package/registry/agenda.json +1 -1
  224. package/registry/alert.json +1 -1
  225. package/registry/anatomy-plate.json +13 -5
  226. package/registry/app-header.json +470 -23
  227. package/registry/app-shell.json +2 -2
  228. package/registry/argument-card.json +1 -1
  229. package/registry/audio-player.json +1 -1
  230. package/registry/auth-layout.json +1 -1
  231. package/registry/avatar.json +3 -2
  232. package/registry/badge.json +2 -1
  233. package/registry/bird-plate.json +16 -2
  234. package/registry/button.json +7 -6
  235. package/registry/captcha.json +1 -1
  236. package/registry/card-grid.json +1 -1
  237. package/registry/card.json +7 -6
  238. package/registry/catalogue-page.json +3 -4
  239. package/registry/changelog-page.json +3 -5
  240. package/registry/chapter.json +1 -1
  241. package/registry/chat.json +3 -2
  242. package/registry/checkbox.json +4 -3
  243. package/registry/chip-link.json +2 -2
  244. package/registry/chip-row.json +2 -2
  245. package/registry/chip.json +3 -2
  246. package/registry/choice-grid.json +3 -4
  247. package/registry/code-block.json +1 -1
  248. package/registry/combobox.json +3 -2
  249. package/registry/command.json +2 -2
  250. package/registry/comparison-table.json +1 -1
  251. package/registry/component-page.json +14 -5
  252. package/registry/confirm-button.json +4 -4
  253. package/registry/contact-page.json +1 -1
  254. package/registry/continue-prompt.json +13 -5
  255. package/registry/countdown.json +4 -3
  256. package/registry/cover-hero.json +3 -4
  257. package/registry/cta-panel.json +1 -1
  258. package/registry/dashboard-layout.json +1 -1
  259. package/registry/data-table.json +63 -7
  260. package/registry/date-picker.json +5 -4
  261. package/registry/decision-list.json +1 -1
  262. package/registry/description-list.json +2 -1
  263. package/registry/detail-layout.json +30 -6
  264. package/registry/dialog.json +7 -6
  265. package/registry/docs-article-page.json +3 -4
  266. package/registry/docs-hub-page.json +1 -1
  267. package/registry/docs-layout.json +1 -1
  268. package/registry/docs-nav.json +1 -1
  269. package/registry/document-viewer.json +3 -5
  270. package/registry/doodle.json +209 -0
  271. package/registry/drop-overlay.json +30 -16
  272. package/registry/dropdown-menu.json +2 -2
  273. package/registry/elephant.json +15 -7
  274. package/registry/empty-state.json +2 -1
  275. package/registry/engine-flow.json +1 -1
  276. package/registry/error-page.json +3 -5
  277. package/registry/examples/app-header/family.d.ts +4 -0
  278. package/registry/examples/app-header/family.js +41 -0
  279. package/registry/examples/app-header/family.tsx +37 -0
  280. package/registry/examples/app-header/native/family.d.ts +4 -0
  281. package/registry/examples/app-header/native/family.dark.png +0 -0
  282. package/registry/examples/app-header/native/family.js +25 -0
  283. package/registry/examples/app-header/native/family.light.png +0 -0
  284. package/registry/examples/app-header/native/family.tsx +33 -0
  285. package/registry/examples/data-table/applicant-files.d.ts +4 -0
  286. package/registry/examples/data-table/applicant-files.js +24 -0
  287. package/registry/examples/data-table/applicant-files.tsx +23 -0
  288. package/registry/examples/data-table/checks.d.ts +4 -0
  289. package/registry/examples/data-table/checks.js +25 -0
  290. package/registry/examples/data-table/checks.tsx +24 -0
  291. package/registry/examples/detail-layout/profile.d.ts +4 -0
  292. package/registry/examples/detail-layout/profile.js +26 -0
  293. package/registry/examples/detail-layout/profile.tsx +21 -0
  294. package/registry/examples/doodle/kinds.d.ts +4 -0
  295. package/registry/examples/doodle/kinds.js +17 -0
  296. package/registry/examples/doodle/kinds.tsx +14 -0
  297. package/registry/examples/doodle/margin.d.ts +4 -0
  298. package/registry/examples/doodle/margin.js +17 -0
  299. package/registry/examples/doodle/margin.tsx +17 -0
  300. package/registry/examples/markdown/native/basic.dark.png +0 -0
  301. package/registry/examples/markdown/native/basic.light.png +0 -0
  302. package/registry/examples/markdown/native/wide-table.d.ts +4 -0
  303. package/registry/examples/markdown/native/wide-table.dark.png +0 -0
  304. package/registry/examples/markdown/native/wide-table.js +23 -0
  305. package/registry/examples/markdown/native/wide-table.light.png +0 -0
  306. package/registry/examples/markdown/native/wide-table.tsx +22 -0
  307. package/registry/examples/markdown/wide-table.d.ts +4 -0
  308. package/registry/examples/markdown/wide-table.js +28 -0
  309. package/registry/examples/markdown/wide-table.tsx +23 -0
  310. package/registry/examples/nav-bar/family-product.js +2 -4
  311. package/registry/examples/nav-bar/family-product.tsx +3 -5
  312. package/registry/examples/notification-preferences/default.d.ts +4 -0
  313. package/registry/examples/notification-preferences/default.js +29 -0
  314. package/registry/examples/notification-preferences/default.tsx +28 -0
  315. package/registry/examples/profile-card/banner.d.ts +4 -0
  316. package/registry/examples/profile-card/banner.js +28 -0
  317. package/registry/examples/profile-card/banner.tsx +24 -0
  318. package/registry/examples/profile-card/native/banner.d.ts +4 -0
  319. package/registry/examples/profile-card/native/banner.dark.png +0 -0
  320. package/registry/examples/profile-card/native/banner.js +22 -0
  321. package/registry/examples/profile-card/native/banner.light.png +0 -0
  322. package/registry/examples/profile-card/native/banner.tsx +18 -0
  323. package/registry/examples/quota-meter/default.d.ts +4 -0
  324. package/registry/examples/quota-meter/default.js +26 -0
  325. package/registry/examples/quota-meter/default.tsx +20 -0
  326. package/registry/examples/quota-meter/full.d.ts +4 -0
  327. package/registry/examples/quota-meter/full.js +25 -0
  328. package/registry/examples/quota-meter/full.tsx +18 -0
  329. package/registry/examples/rail-nav/shortcuts.d.ts +4 -0
  330. package/registry/examples/rail-nav/shortcuts.js +49 -0
  331. package/registry/examples/rail-nav/shortcuts.tsx +40 -0
  332. package/registry/examples/retro-tv/cabinet.d.ts +4 -0
  333. package/registry/examples/retro-tv/cabinet.js +12 -0
  334. package/registry/examples/retro-tv/cabinet.tsx +7 -0
  335. package/registry/examples/retro-tv/portable.d.ts +4 -0
  336. package/registry/examples/retro-tv/portable.js +12 -0
  337. package/registry/examples/retro-tv/portable.tsx +7 -0
  338. package/registry/examples/signature/both.d.ts +4 -0
  339. package/registry/examples/signature/both.js +11 -0
  340. package/registry/examples/signature/both.tsx +6 -0
  341. package/registry/examples/signature/variants.d.ts +4 -0
  342. package/registry/examples/signature/variants.js +14 -0
  343. package/registry/examples/signature/variants.tsx +11 -0
  344. package/registry/examples/stuck/card.d.ts +4 -0
  345. package/registry/examples/stuck/card.js +13 -0
  346. package/registry/examples/stuck/card.tsx +14 -0
  347. package/registry/examples/stuck/holds.d.ts +4 -0
  348. package/registry/examples/stuck/holds.js +12 -0
  349. package/registry/examples/stuck/holds.tsx +16 -0
  350. package/registry/examples/stuck/tag.d.ts +4 -0
  351. package/registry/examples/stuck/tag.js +12 -0
  352. package/registry/examples/stuck/tag.tsx +13 -0
  353. package/registry/examples/tabs/binder.d.ts +4 -0
  354. package/registry/examples/tabs/binder.js +22 -0
  355. package/registry/examples/tabs/binder.tsx +20 -0
  356. package/registry/examples/tabs/native/binder.d.ts +4 -0
  357. package/registry/examples/tabs/native/binder.dark.png +0 -0
  358. package/registry/examples/tabs/native/binder.js +26 -0
  359. package/registry/examples/tabs/native/binder.light.png +0 -0
  360. package/registry/examples/tabs/native/binder.tsx +22 -0
  361. package/registry/fab.json +1 -0
  362. package/registry/field.json +3 -2
  363. package/registry/file-upload.json +6 -11
  364. package/registry/filter-bar.json +2 -2
  365. package/registry/flock.json +3 -4
  366. package/registry/footnote.json +2 -3
  367. package/registry/force-update-screen.json +14 -5
  368. package/registry/form.json +5 -4
  369. package/registry/gallery-page.json +14 -5
  370. package/registry/genui.json +2 -2
  371. package/registry/glossary-term.json +1 -1
  372. package/registry/glossary.json +1 -1
  373. package/registry/glow-card.json +2 -2
  374. package/registry/goal-gauge.json +2 -1
  375. package/registry/header.json +1 -0
  376. package/registry/how-it-works-page.json +3 -5
  377. package/registry/image-cropper.json +13 -5
  378. package/registry/image-viewer.json +3 -4
  379. package/registry/index.json +301 -87
  380. package/registry/iso.json +1 -1
  381. package/registry/kanban.json +13 -5
  382. package/registry/kbd.json +1 -1
  383. package/registry/kpi-explained.json +2 -2
  384. package/registry/landing-page.json +3 -5
  385. package/registry/landscape.json +13 -5
  386. package/registry/language-switch.json +1 -1
  387. package/registry/legal-page.json +1 -1
  388. package/registry/link-card.json +1 -1
  389. package/registry/list.json +2 -1
  390. package/registry/loader.json +2 -1
  391. package/registry/longform-page.json +1 -1
  392. package/registry/maintenance-screen.json +14 -5
  393. package/registry/map.json +3 -2
  394. package/registry/markdown.json +86 -9
  395. package/registry/marketing-layout.json +1 -1
  396. package/registry/marquee.json +1 -1
  397. package/registry/mascot-quote.json +1 -1
  398. package/registry/mascot-state.json +12 -11
  399. package/registry/mascots.json +2 -1
  400. package/registry/match-dialog.json +14 -5
  401. package/registry/media-capture.json +14 -5
  402. package/registry/media-gallery.json +3 -5
  403. package/registry/media-grid.json +1 -1
  404. package/registry/media-picker.json +2 -3
  405. package/registry/meta-row.json +2 -1
  406. package/registry/meter.json +4 -3
  407. package/registry/nav-bar.json +100 -9
  408. package/registry/next-actions.json +1 -1
  409. package/registry/notification-preferences.json +250 -0
  410. package/registry/number-ticker.json +2 -1
  411. package/registry/onboarding.json +1 -0
  412. package/registry/opening-hours.json +1 -1
  413. package/registry/otp-input.json +1 -0
  414. package/registry/page-header.json +2 -2
  415. package/registry/page-hero.json +1 -1
  416. package/registry/page-index.json +1 -1
  417. package/registry/page.json +3 -3
  418. package/registry/pagination.json +2 -1
  419. package/registry/permission-prompt.json +2 -2
  420. package/registry/photo-grid.json +4 -4
  421. package/registry/pointer-light.json +6 -2
  422. package/registry/popover.json +2 -2
  423. package/registry/pricing-page.json +4 -6
  424. package/registry/product-page.json +14 -5
  425. package/registry/profile-card.json +232 -8
  426. package/registry/progress.json +4 -3
  427. package/registry/promise-card.json +13 -5
  428. package/registry/pull-to-refresh.json +1 -0
  429. package/registry/quota-meter.json +308 -0
  430. package/registry/radio-group.json +4 -3
  431. package/registry/rail-nav.json +48 -10
  432. package/registry/recipes.json +1 -1
  433. package/registry/retro-tv.json +478 -0
  434. package/registry/router.json +3 -3
  435. package/registry/screen.json +1 -0
  436. package/registry/scroll-stage.json +14 -5
  437. package/registry/search-field.json +3 -2
  438. package/registry/section-backdrop.json +1 -1
  439. package/registry/segmented.json +1 -0
  440. package/registry/separator.json +2 -2
  441. package/registry/service-card.json +1 -1
  442. package/registry/settings-layout.json +2 -1
  443. package/registry/showcase.json +14 -5
  444. package/registry/signature.json +185 -0
  445. package/registry/site-footer.json +3 -3
  446. package/registry/sites.json +2 -2
  447. package/registry/skeleton.json +2 -1
  448. package/registry/skip-link.json +1 -1
  449. package/registry/slider.json +5 -4
  450. package/registry/slot-picker.json +1 -1
  451. package/registry/slot.json +2 -2
  452. package/registry/specimen-tag.json +1 -1
  453. package/registry/spinner.json +4 -3
  454. package/registry/splash-handoff.json +1 -0
  455. package/registry/split-view.json +1 -1
  456. package/registry/stage-banner.json +2 -3
  457. package/registry/stat.json +2 -2
  458. package/registry/status-page.json +13 -5
  459. package/registry/step-progress.json +2 -1
  460. package/registry/step-showcase.json +3 -5
  461. package/registry/stepper.json +2 -1
  462. package/registry/sticky-action.json +1 -1
  463. package/registry/stuck.json +219 -0
  464. package/registry/swipe-deck.json +14 -5
  465. package/registry/swipeable-row.json +1 -0
  466. package/registry/switch.json +3 -2
  467. package/registry/tab-bar.json +1 -0
  468. package/registry/tabs.json +154 -22
  469. package/registry/tag-input.json +1 -1
  470. package/registry/tag-selector.json +2 -1
  471. package/registry/taped-photo.json +1 -1
  472. package/registry/terminal-replay.json +14 -5
  473. package/registry/text-style.json +5 -5
  474. package/registry/theme.json +2 -1
  475. package/registry/toast.json +2 -1
  476. package/registry/toc.json +1 -1
  477. package/registry/tooltip.json +2 -2
  478. package/registry/tree-view.json +6 -2
  479. package/registry/txt.json +1 -0
  480. package/registry/update-prompt.json +14 -5
  481. package/registry/upload-queue.json +1 -1
  482. package/registry/verified-badge.json +6 -6
  483. package/registry/vertical-video.json +8 -3
  484. package/registry/video-player.json +5 -6
  485. package/registry/video-trimmer.json +13 -5
  486. package/registry/virtual.json +2 -2
  487. package/registry/waveform.json +4 -3
  488. package/dist/chunk-4LYKBSOG.js.map +0 -1
  489. package/dist/chunk-HHFWK2HH.js +0 -163
  490. package/dist/chunk-HHFWK2HH.js.map +0 -1
  491. package/dist/chunk-R3LTSMS5.js +0 -75
  492. package/dist/chunk-R3LTSMS5.js.map +0 -1
  493. package/dist/chunk-YGIN2YIY.js.map +0 -1
  494. package/dist/chunk-YHKTYFOQ.js.map +0 -1
  495. /package/dist/{chunk-ZQW7LF4Y.js.map → chunk-OIMXKRXF.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/nav-bar/nav-bar.tsx","../src/nav-bar/placement.ts","../src/nav-bar/product-actions.tsx"],"sourcesContent":["// Client (scroll, a sliding indicator, menus). Radix NavigationMenu does the menus' semantics and keyboard (Enter, Space\n// and ↓ open; ↑ ↓ Home End walk; Escape closes and returns the focus; Tab out closes); this file draws the Krizaka bar:\n// a floating pill that tightens once the page scrolls, one light that glides to the item under the pointer or the\n// focus and rests on the current page, and a mobile panel that is a plain disclosure (no focus trap, Escape closes).\nimport { NavigationMenu as Nav, Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { FamilyMark, GitHubGlyph } from \"../family-mark\";\nimport { LanguageSwitch, type LanguageSwitchProps } from \"../language-switch/language-switch\";\nimport { type FamilyLabels, familyLabels, type Site, type SiteId, sitesByGroup } from \"../sites/sites\";\nimport { useSlidingIndicator } from \"../sliding-indicator\";\nimport { placePanel } from \"./placement\";\n\nexport const navBar = tv({\n slots: {\n root:\n \"group/nav relative z-40 mx-auto flex h-14 w-full items-center gap-2 border-border-subtle bg-surface-1 \" +\n \"transition-[height,background-color,border-color,box-shadow] duration-300 motion-reduce:transition-none \" +\n \"data-compact:h-12 data-compact:border-border-default data-compact:bg-surface-1 data-compact:shadow-lg\",\n brand:\n \"mr-2 inline-flex shrink-0 items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg no-underline \" +\n \"rounded-md focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n items: \"relative hidden md:block\",\n list:\n \"group/list relative isolate flex items-center gap-0.5 \" +\n // The ink rule (Cahier, ADR-004): a pen line under the item that is pointed at or focused, resting on the current page.\n \"before:absolute before:left-0 before:top-0 before:-z-10 before:h-0.5 before:w-(--kz-ind-w) before:translate-x-(--kz-ind-x) before:translate-y-[calc(var(--kz-ind-y)+var(--kz-ind-h)-6px)] \" +\n \"before:scale-x-[0.72] before:bg-fg before:opacity-0 before:transition-[translate,width,opacity] before:duration-300 motion-reduce:before:transition-none \" +\n \"data-[indicator=on]:before:opacity-100\",\n item:\n \"inline-flex h-9 select-none items-center gap-1 rounded-sm px-3.5 text-sm font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:text-fg data-active:text-fg data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n // Before the light is ready (server render), the current page carries its own tint.\n \"group-not-data-[indicator=on]/list:data-active:underline group-not-data-[indicator=on]/list:data-active:decoration-2 group-not-data-[indicator=on]/list:data-active:underline-offset-8\",\n chevron: \"h-3.5 w-3.5 transition-transform duration-300 group-data-[state=open]/trigger:rotate-180 motion-reduce:transition-none\",\n viewport:\n // `left` is set by NavBarItems (--kz-menu-left): the panel's edge under its trigger, kept inside the page.\n \"kz-pop absolute left-[var(--kz-menu-left,0px)] top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden \" +\n \"rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[left,width,height] duration-300 motion-reduce:transition-none\",\n // Icon · title · a description of two lines at most. 28 rem (40 rem in two columns), never wider than the page\n // between its gutters, and never taller than the screen.\n panel: \"grid w-[min(28rem,calc(100vw-2rem))] max-h-[calc(100dvh-6rem)] gap-0.5 overflow-y-auto p-1.5\",\n panelWide: \"w-[min(40rem,calc(100vw-2rem))] md:grid-cols-2\",\n menuLink:\n \"group/link flex items-start gap-3 rounded-lg px-2.5 py-2 text-left no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring data-active:bg-accent-soft\",\n menuIcon:\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-border-default bg-surface-2 text-fg-accent \" +\n \"transition-[transform,border-color] duration-300 group-hover/link:-translate-y-0.5 group-hover/link:border-accent [&>svg]:h-4 [&>svg]:w-4 motion-reduce:transform-none\",\n menuTitle: \"block line-clamp-2 wrap-break-word text-sm font-semibold leading-5 text-fg\",\n // Two lines at most, wrapped at word boundaries — a longer one ends in an ellipsis, never cut mid-sentence.\n menuText: \"mt-0.5 block line-clamp-2 wrap-break-word text-xs leading-4 text-fg-secondary\",\n actions: \"ml-auto flex items-center gap-2\",\n toggle:\n \"inline-flex h-9 w-9 items-center justify-center rounded-sm border border-border-subtle bg-surface-2 text-fg md:hidden \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n mobile: \"kz-pop absolute inset-x-0 top-full mt-2 grid gap-1 rounded-2xl border border-border-default bg-surface-1 p-2 shadow-lg md:hidden\",\n mobileGroup: \"grid gap-0.5 [&+&]:mt-1 [&+&]:border-t [&+&]:border-border-subtle [&+&]:pt-2\",\n mobileGroupTitle: \"px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary\",\n mobileLink:\n \"flex items-center justify-between rounded-xl px-3 py-3 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg-accent\",\n // The family switcher: a chevron attached to the brand, its panel aligned on the bar's left edge.\n family: \"hidden md:block\",\n familyTrigger:\n \"group/trigger -ml-2 mr-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-sm text-fg-secondary transition-colors \" +\n \"hover:bg-surface-3 hover:text-fg data-[state=open]:bg-surface-3 data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n familyViewport:\n \"kz-pop absolute left-0 top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden \" +\n \"rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[width,height] duration-300 motion-reduce:transition-none\",\n familyPanel: \"grid w-[min(92vw,42rem)] gap-x-2 gap-y-3 p-3 sm:grid-cols-2\",\n familyGroupTitle: \"px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary\",\n familyLink:\n \"group/link flex items-start gap-3 rounded-xl px-3 py-2.5 text-left no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft\",\n familyMark: \"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-fg\",\n familyName: \"flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm font-semibold text-fg\",\n familyText: \"mt-0.5 block text-xs leading-relaxed text-fg-secondary\",\n familyTag: \"rounded-sm px-1.5 py-px text-[10px] font-semibold\",\n mobileFamily: \"mt-1 grid gap-2 border-t border-border-subtle px-1 pb-1 pt-3\",\n mobileFamilyLink:\n \"flex min-h-11 items-center gap-3 rounded-xl px-2 py-2 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft\",\n badge:\n \"hidden h-6 shrink-0 items-center gap-1 rounded-sm border border-border-subtle bg-surface-2 px-2 font-mono text-[11px] font-medium text-fg-secondary sm:inline-flex\",\n repo:\n \"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-sm text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n variants: {\n floating: {\n true: { root: \"max-w-5xl rounded-sm border pl-5 pr-2 data-compact:max-w-4xl\" },\n false: { root: \"border-b px-4 md:px-6\" },\n },\n },\n defaultVariants: { floating: true },\n});\nconst s = navBar();\n\ninterface NavBarContext {\n label: string;\n open: boolean;\n setOpen: (open: boolean) => void;\n panelId: string;\n}\nconst Context = React.createContext<NavBarContext | null>(null);\n/** The open menu of `NavBar.Items` (`\"\"`: none), so a plain link can close it when the pointer moves on to it. */\nconst ItemsContext = React.createContext<{ close: () => void }>({ close: () => {} });\n/** True inside `NavBar.Mobile`: the family renders as the panel's last group instead of a switcher. */\nconst MobileContext = React.createContext(false);\nconst useNavBar = () => {\n const ctx = React.useContext(Context);\n if (!ctx) throw new Error(\"NavBar parts must be inside <NavBar.Root>.\");\n return ctx;\n};\n\nexport type NavBarRootProps = React.ComponentProps<\"header\"> & {\n /** The accessible name of the navigation (“Main”) — passed translated. */\n label: string;\n /**\n * Pixels of scroll after which the bar tightens (denser, lower, lifted). `false`: never.\n * @default 24\n */\n compactAfter?: number | false;\n /**\n * A floating pill (the Krizaka bar) or a full-width bar with a hairline under it.\n * @default true\n */\n floating?: boolean;\n};\n\n/** The bar. Place it in a `sticky top-3` (floating) or `sticky top-0` wrapper — or let it scroll. */\nexport function NavBarRoot({ label, compactAfter = 24, floating = true, className, children, ...props }: NavBarRootProps) {\n const [compact, setCompact] = React.useState(false);\n const [open, setOpen] = React.useState(false);\n const panelId = React.useId();\n React.useEffect(() => {\n if (compactAfter === false) return;\n const onScroll = () => setCompact(window.scrollY > compactAfter);\n onScroll();\n window.addEventListener(\"scroll\", onScroll, { passive: true });\n return () => window.removeEventListener(\"scroll\", onScroll);\n }, [compactAfter]);\n const ctx = React.useMemo(() => ({ label, open, setOpen, panelId }), [label, open, panelId]);\n return (\n <Context.Provider value={ctx}>\n <header data-compact={compact ? \"\" : undefined} data-floating={floating} className={navBar({ floating }).root({ className })} {...props}>\n {children}\n </header>\n </Context.Provider>\n );\n}\n\nexport type NavBarBrandProps = React.ComponentProps<\"a\"> & {\n /** Renders your link (a router `<Link>`) with the brand's look. */\n asChild?: boolean;\n};\n\n/** The brand: a mark and a name, linking home. */\nexport function NavBarBrand({ asChild, className, ...props }: NavBarBrandProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp className={s.brand({ className })} {...props} />;\n}\n\nexport type NavBarItemsProps = Omit<React.ComponentProps<typeof Nav.Root>, \"orientation\">;\n\n/**\n * The desktop navigation: links and menus, with the light that glides between them. Hidden below `md` (see\n * `NavBar.Mobile`). A menu opens on click, Enter, Space or ↓ — or when the pointer rests on its trigger (hover intent,\n * `delayDuration`, 200 ms): passing over the bar opens nothing. While a menu is open the light stays on its trigger;\n * moving on to a plain link closes the menu, so the bar never shows two current items. A click outside or Escape closes.\n */\nexport function NavBarItems({ className, children, value: valueProp, defaultValue, onValueChange, delayDuration = 200, ...props }: NavBarItemsProps) {\n const { label } = useNavBar();\n const [inner, setInner] = React.useState(defaultValue ?? \"\");\n const value = valueProp ?? inner;\n const setValue = React.useCallback(\n (next: string) => {\n setInner(next);\n onValueChange?.(next);\n },\n [onValueChange],\n );\n const items = React.useMemo(() => ({ close: () => setValue(\"\") }), [setValue]);\n const { ref, handlers } = useSlidingIndicator<HTMLUListElement>({\n item: \"[data-nav-item]\",\n active: \"[data-nav-item][data-active]\",\n prefer: \"[data-nav-item][data-state=open]\",\n follow: true,\n });\n const root = React.useRef<HTMLElement>(null);\n const viewport = React.useRef<HTMLDivElement>(null);\n // The open panel sits under its trigger and stays inside the page (collision): measured when a menu opens, when\n // the panel changes size (another menu) and when the window does.\n React.useLayoutEffect(() => {\n const panel = viewport.current;\n const nav = root.current;\n if (!panel || !nav || !value) return;\n const place = () => {\n const trigger = nav.querySelector<HTMLElement>(\"[data-nav-item][data-state=open]\");\n const width = Number.parseFloat(panel.style.getPropertyValue(\"--radix-navigation-menu-viewport-width\"));\n if (!trigger || !Number.isFinite(width)) return;\n const left = `${placePanel({ trigger: trigger.getBoundingClientRect().left, root: nav.getBoundingClientRect().left, panel: width, window: document.documentElement.clientWidth })}px`;\n if (panel.style.getPropertyValue(\"--kz-menu-left\") !== left) panel.style.setProperty(\"--kz-menu-left\", left);\n };\n place();\n const watch = new MutationObserver(place);\n watch.observe(panel, { attributes: true, attributeFilter: [\"style\"] });\n window.addEventListener(\"resize\", place);\n return () => {\n watch.disconnect();\n window.removeEventListener(\"resize\", place);\n };\n }, [value]);\n return (\n <ItemsContext.Provider value={items}>\n <Nav.Root ref={root} aria-label={label} className={s.items({ className })} value={value} onValueChange={setValue} delayDuration={delayDuration} {...props}>\n <Nav.List ref={ref} className={s.list()} {...handlers}>\n {children}\n </Nav.List>\n <Nav.Viewport ref={viewport} className={s.viewport()} />\n </Nav.Root>\n </ItemsContext.Provider>\n );\n}\n\nexport type NavBarLinkProps = Omit<React.ComponentProps<typeof Nav.Link>, \"active\"> & {\n /** The current page: `aria-current=\"page\"`, and the light rests on it. */\n active?: boolean;\n /** Classes on the list item around the link (to show it from a breakpoint only). */\n itemClassName?: string;\n};\n\n/** A link of the bar. `asChild` renders your router's `<Link>`. */\nexport function NavBarLink({ active, className, itemClassName, onPointerEnter, ...props }: NavBarLinkProps) {\n const { close } = React.useContext(ItemsContext);\n return (\n <Nav.Item className={itemClassName}>\n <Nav.Link\n data-nav-item=\"\"\n data-active={active ? \"\" : undefined}\n active={active}\n aria-current={active ? \"page\" : undefined}\n className={s.item({ className })}\n onPointerEnter={(e) => {\n onPointerEnter?.(e);\n close();\n }}\n {...props}\n />\n </Nav.Item>\n );\n}\n\nexport type NavBarMenuProps = Omit<React.ComponentProps<typeof Nav.Item>, \"children\"> & {\n /** The trigger's words (“Products”) — passed translated. */\n label: string;\n /** The current page is inside this menu: the light rests on its trigger. */\n active?: boolean;\n /** The menu's links (`NavBar.MenuLink`), laid out in a panel; `columns` sets the grid. */\n children: React.ReactNode;\n /**\n * Columns of the panel.\n * @default 1\n */\n columns?: 1 | 2;\n /**\n * A section with this many links or fewer needs no hidden list: they sit in the bar as plain links (the active one\n * marked, no dropdown, `label` unused on the desktop). Above it, a dropdown. `0` always makes a dropdown.\n * @default 3\n */\n inlineUpTo?: number;\n /**\n * From which breakpoint the inline links stand in the bar. Below it (between the phone panel at `md` and this\n * breakpoint) the section is the dropdown, so long labels never overflow a tablet-width bar. `md` inlines as soon as\n * the bar is shown.\n * @default \"lg\"\n */\n inlineFrom?: \"md\" | \"lg\" | \"xl\";\n};\n\n// Static class names (Tailwind reads them at build time).\nconst INLINE_HIDE = { md: \"\", lg: \"max-lg:hidden\", xl: \"max-xl:hidden\" } as const;\nconst DROPDOWN_HIDE = { md: \"\", lg: \"lg:hidden\", xl: \"xl:hidden\" } as const;\n\n/**\n * A menu of the bar: its trigger, and its links in a panel that opens under the bar. A menu of `inlineUpTo` links or\n * fewer (3 by default) is not a menu at all: its links stand in the bar, each with its active state — a hidden list of\n * three is one click more for nothing. The phone's panel groups them as usual (`NavBar.MobileGroup`).\n */\nexport function NavBarMenu({ label, active, columns = 1, inlineUpTo = 3, inlineFrom = \"lg\", children, className, ...props }: NavBarMenuProps) {\n const links = React.Children.toArray(children);\n const dropdown = (hide: string) => (\n <Nav.Item className={cn(hide, className)} {...props}>\n <Nav.Trigger data-nav-item=\"\" data-active={active ? \"\" : undefined} className={cn(s.item(), \"group/trigger\")}>\n {label}\n <svg viewBox=\"0 0 24 24\" className={s.chevron()} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </Nav.Trigger>\n <Nav.Content className={cn(s.panel(), columns === 2 && s.panelWide())}>{children}</Nav.Content>\n </Nav.Item>\n );\n const inline = links.length > 0 && links.length <= inlineUpTo && links.every((c) => React.isValidElement(c) && c.type === NavBarMenuLink);\n if (inline) {\n return (\n <>\n {inlineFrom !== \"md\" && dropdown(DROPDOWN_HIDE[inlineFrom])}\n {links.map((link) => {\n const { title, href, active: here, asChild, children: child, icon: _icon, description: _description, className: linkClass, ...rest } = (link as React.ReactElement<NavBarMenuLinkProps>).props;\n return (\n <NavBarLink key={(link as React.ReactElement).key} asChild={asChild} href={asChild ? undefined : href} active={here} className={linkClass} itemClassName={INLINE_HIDE[inlineFrom]} {...rest}>\n {asChild && React.isValidElement<{ children?: React.ReactNode }>(child) ? React.cloneElement(child, undefined, title) : title}\n </NavBarLink>\n );\n })}\n </>\n );\n }\n return dropdown(\"\");\n}\n\nexport type NavBarMenuLinkProps = Omit<React.ComponentProps<typeof Nav.Link>, \"title\" | \"active\"> & {\n /** The link's name — passed translated. */\n title: string;\n /** One line under it — passed translated. */\n description?: string;\n /** An icon (a signature icon of `@krizaka/icons`: its node lights up on hover). */\n icon?: React.ReactNode;\n /** The current page. */\n active?: boolean;\n};\n\n/** A link inside a menu: an icon, a name and a line of text. */\nexport function NavBarMenuLink({ title, description, icon, active, href, className, asChild, children, ...props }: NavBarMenuLinkProps) {\n const body = (\n <>\n {icon && <span className={s.menuIcon()}>{icon}</span>}\n <span className=\"min-w-0 flex-1\">\n <span className={s.menuTitle()}>{title}</span>\n {description && <span className={s.menuText()}>{description}</span>}\n </span>\n </>\n );\n return (\n <Nav.Link asChild={asChild} href={asChild ? undefined : href} active={active} aria-current={active ? \"page\" : undefined} data-active={active ? \"\" : undefined} className={s.menuLink({ className })} {...props}>\n {asChild && React.isValidElement<{ children?: React.ReactNode }>(children) ? React.cloneElement(children, undefined, body) : body}\n </Nav.Link>\n );\n}\n\n/** The right side: search, theme, language, the call to action. */\nexport function NavBarActions({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.actions({ className })} {...props} />;\n}\n\nexport type NavBarMobileProps = React.ComponentProps<\"nav\"> & {\n /** The toggle's name when closed (“Open the menu”) — passed translated. */\n openLabel: string;\n /** The toggle's name when open (“Close the menu”) — passed translated. */\n closeLabel: string;\n};\n\n/**\n * Below `md`: a toggle, and a panel under the bar with its links (`NavBar.MobileLink`), grouped like the bar's menus\n * (`NavBar.MobileGroup`). A disclosure: Escape, a click on a link or a press outside close it; Escape returns the focus\n * to the toggle.\n */\nexport function NavBarMobile({ openLabel, closeLabel, className, children, ...props }: NavBarMobileProps) {\n const { label, open, setOpen, panelId } = useNavBar();\n const toggle = React.useRef<HTMLButtonElement>(null);\n React.useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n setOpen(false);\n toggle.current?.focus();\n };\n // A press outside the panel and its toggle closes it (the page under it stays usable).\n const onPress = (e: PointerEvent) => {\n const target = e.target as Node | null;\n if (!target || toggle.current?.contains(target) || document.getElementById(panelId)?.contains(target)) return;\n setOpen(false);\n };\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(\"pointerdown\", onPress);\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.removeEventListener(\"pointerdown\", onPress);\n };\n }, [open, setOpen, panelId]);\n return (\n <>\n <button ref={toggle} type=\"button\" aria-expanded={open} aria-controls={panelId} aria-label={open ? closeLabel : openLabel} onClick={() => setOpen(!open)} className={s.toggle()}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4.5 w-4.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n {open ? <path d=\"M18 6 6 18M6 6l12 12\" /> : <path d=\"M4 7h16M4 12h16M4 17h10\" />}\n </svg>\n </button>\n {open && (\n <nav\n id={panelId}\n aria-label={label}\n className={s.mobile({ className })}\n onClick={(e) => {\n if ((e.target as Element).closest(\"a\")) setOpen(false);\n }}\n {...props}\n >\n <MobileContext.Provider value>{children}</MobileContext.Provider>\n </nav>\n )}\n </>\n );\n}\n\nexport type NavBarMobileGroupProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The group's heading — the same words as the bar's menu (“Product”) — passed translated. */\n label: string;\n};\n\n/** A group of the mobile panel: the links of one of the bar's menus under its name, in the same order. */\nexport function NavBarMobileGroup({ label, className, children, ...props }: NavBarMobileGroupProps) {\n const id = React.useId();\n return (\n <div role=\"group\" aria-labelledby={id} className={s.mobileGroup({ className })} {...props}>\n <p id={id} className={s.mobileGroupTitle()}>\n {label}\n </p>\n {children}\n </div>\n );\n}\n\nexport type NavBarMobileLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the mobile panel. */\nexport function NavBarMobileLink({ active, asChild, className, ...props }: NavBarMobileLinkProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.mobileLink({ className })} {...props} />;\n}\n\n\nconst tagTone = {\n upcoming: \"bg-accent-soft text-fg ring-1 ring-inset ring-accent/40\",\n construction: \"bg-warning/15 text-fg ring-1 ring-inset ring-warning/40\",\n development: \"bg-surface-3 text-fg ring-1 ring-inset ring-border-strong\",\n current: \"bg-surface-3 text-fg-secondary\",\n};\n\n/** A site's name and its tags: status when not released, “You are here” on the current one. */\nfunction FamilyName({ site, current, labels }: { site: Site; current: boolean; labels: FamilyLabels }) {\n return (\n <span className={s.familyName()}>\n {site.name}\n {site.status !== \"released\" && <span className={cn(s.familyTag(), tagTone[site.status])}>{labels.status[site.status]}</span>}\n {current && <span className={cn(s.familyTag(), tagTone.current)}>{labels.current}</span>}\n </span>\n );\n}\n\nexport type NavBarFamilyProps = {\n /** The site this bar belongs to (`@krizaka/ui/sites`): marked in the family, `aria-current=\"true\"`. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** Opens the panel at first render (a story, a screenshot). */\n defaultOpen?: boolean;\n /** Classes of the switcher (or, inside `NavBar.Mobile`, of the family's group). */\n className?: string;\n};\n\n/**\n * @deprecated No site carries the family switcher any more (2026-10-22): krizaka.com is the only way back between the Krizaka sites, through the footer's « A Krizaka project » line. Removed in the next minor; `krizaka/no-family-switcher` refuses it.\n *\n * The family switcher, attached to the brand (place it right after `NavBar.Brand`): a chevron that opens every site of\n * Krizaka grouped — Krizaka · Products · Open source · GitHub — the current one marked. It opens on click, Enter, Space\n * or ↓ (never on hover); ↑ ↓ walk the sites, Escape closes and returns the focus. Hidden below `md`: place a second\n * `NavBar.Family` as the last child of `NavBar.Mobile`, where it renders as the panel's last group.\n */\nexport function NavBarFamily({ current, labels = familyLabels.en, defaultOpen, className }: NavBarFamilyProps) {\n const inMobile = React.useContext(MobileContext);\n const id = React.useId();\n const groups = sitesByGroup();\n if (inMobile) {\n return (\n <div role=\"group\" aria-labelledby={`${id}-family`} className={s.mobileFamily({ className })}>\n <p id={`${id}-family`} className={s.familyGroupTitle()}>\n {labels.family}\n </p>\n {groups.map(({ group, sites }) => (\n <div key={group}>\n {/* The company's own group is named like the family itself: its heading would repeat the panel's. */}\n {group !== \"krizaka\" && (\n <p id={`${id}-${group}`} className={s.familyGroupTitle()}>\n {labels.groups[group]}\n </p>\n )}\n <ul aria-labelledby={group !== \"krizaka\" ? `${id}-${group}` : `${id}-family`} className=\"grid gap-0.5\">\n {sites.map((site) => (\n <li key={site.id}>\n <a href={site.url} data-current={site.id === current ? \"\" : undefined} aria-current={site.id === current ? \"true\" : undefined} className={s.mobileFamilyLink()}>\n <span className={s.familyMark()}>\n <FamilyMark mark={site.mark} size={24} />\n </span>\n <FamilyName site={site} current={site.id === current} labels={labels} />\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n );\n }\n // Click only: a pointer passing over the brand never opens the family (Radix opens its menus on hover by default).\n const noHover = (e: React.PointerEvent) => e.preventDefault();\n const columns = [groups.filter((g) => g.group === \"krizaka\" || g.group === \"products\"), groups.filter((g) => g.group === \"open-source\" || g.group === \"github\")];\n return (\n <Nav.Root aria-label={labels.family} defaultValue={defaultOpen ? \"family\" : undefined} className={s.family({ className })}>\n <Nav.List className=\"flex\">\n <Nav.Item value=\"family\">\n <Nav.Trigger aria-label={labels.family} onPointerMove={noHover} onPointerLeave={noHover} className={s.familyTrigger()}>\n <svg viewBox=\"0 0 24 24\" className={s.chevron()} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </Nav.Trigger>\n <Nav.Content onPointerLeave={noHover} className={s.familyPanel()}>\n {columns.map((column, i) => (\n <div key={i} className=\"grid content-start gap-3\">\n {column.map(({ group, sites }) => (\n <div key={group}>\n <p id={`${id}-${group}`} className={s.familyGroupTitle()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className=\"grid gap-0.5\">\n {sites.map((site) => (\n <li key={site.id}>\n <Nav.Link href={site.url} data-current={site.id === current ? \"\" : undefined} aria-current={site.id === current ? \"true\" : undefined} className={s.familyLink()}>\n <span className={s.familyMark()}>\n <FamilyMark mark={site.mark} size={28} />\n </span>\n <span className=\"min-w-0\">\n <FamilyName site={site} current={site.id === current} labels={labels} />\n <span className={s.familyText()}>{labels.descriptions[site.id]}</span>\n </span>\n </Nav.Link>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n ))}\n </Nav.Content>\n </Nav.Item>\n </Nav.List>\n <Nav.Viewport onPointerLeave={noHover} className={s.familyViewport()} />\n </Nav.Root>\n );\n}\n\nexport type NavBarBadgeProps = React.ComponentProps<\"span\"> & {\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n};\n\n/** A small mono badge beside the brand: the environment and the version (`DEV · v1.2.3`). Hidden below `sm`. */\nexport function NavBarBadge({ env, version, className, children, ...props }: NavBarBadgeProps) {\n const parts = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean);\n return (\n <span className={s.badge({ className })} {...props}>\n {parts.join(\" · \")}\n {children}\n </span>\n );\n}\n\nexport type NavBarLanguageProps = Omit<LanguageSwitchProps, \"variant\">;\n\n/**\n * The language switch, the same on every site: in the bar a globe and the current code (FR) opening a short menu of\n * the languages by their own names; inside `NavBar.Mobile` the same languages as a row in the preferences.\n */\nexport function NavBarLanguage(props: NavBarLanguageProps) {\n const inMobile = React.useContext(MobileContext);\n return <LanguageSwitch variant={inMobile ? \"inline\" : \"menu\"} {...props} />;\n}\n\nexport type NavBarMobilePreferencesProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The group's heading (“Preferences”) — passed translated. */\n label: string;\n};\n\n/** The last group of the mobile panel: the preferences (theme, `NavBar.Language`), in a row under their heading. */\nexport function NavBarMobilePreferences({ label, className, children, ...props }: NavBarMobilePreferencesProps) {\n const id = React.useId();\n return (\n <div role=\"group\" aria-labelledby={id} className={s.mobileGroup({ className })} {...props}>\n <p id={id} className={s.mobileGroupTitle()}>\n {label}\n </p>\n <div className=\"flex flex-wrap items-center gap-2 px-3 py-1\">{children}</div>\n </div>\n );\n}\n\nexport type NavBarRepoProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The repository the site is built from. */\n href: string;\n /** The link's accessible name (“Source on GitHub”) — passed translated. */\n label: string;\n};\n\n/** The site's repository on GitHub, an icon link of `NavBar.Actions`. */\nexport function NavBarRepo({ label, className, ...props }: NavBarRepoProps) {\n return (\n <a aria-label={label} className={s.repo({ className })} {...props}>\n <GitHubGlyph size={18} />\n </a>\n );\n}\n\n/**\n * `NavBar.Root/Brand/Family/Badge/Items/Link/Menu/MenuLink/Actions/Repo/Language/Mobile/MobileGroup/MobilePreferences/MobileLink` — the Krizaka navigation bar,\n * the same on every site of the family: floating, tightening on scroll, the family switcher on the brand, one light\n * gliding between its items, accessible menus, a mobile panel.\n */\nexport const NavBar = {\n Root: NavBarRoot,\n Brand: NavBarBrand,\n Family: NavBarFamily,\n Badge: NavBarBadge,\n Items: NavBarItems,\n Link: NavBarLink,\n Menu: NavBarMenu,\n MenuLink: NavBarMenuLink,\n Actions: NavBarActions,\n Repo: NavBarRepo,\n Language: NavBarLanguage,\n Mobile: NavBarMobile,\n MobilePreferences: NavBarMobilePreferences,\n MobileGroup: NavBarMobileGroup,\n MobileLink: NavBarMobileLink,\n};\n","/**\n * Where a menu panel of the bar sits: its left edge under its trigger's, pushed back inside the page when it would run\n * past the right edge, never closer to the left edge than the gutter. All values are pixels of the page (a bounding\n * rect's `left`, a width), the result is the panel's `left` relative to the bar's navigation (`root`). Pure, so a\n * viewport of 360 px and one of 1280 px are tested without a browser.\n */\nexport interface PlacePanel {\n /** The trigger's left edge. */\n trigger: number;\n /** The navigation's left edge (the panel is positioned inside it). */\n root: number;\n /** The panel's width. */\n panel: number;\n /** The window's width. */\n window: number;\n /**\n * The space kept between the panel and the window's edges.\n * @default 16\n */\n gutter?: number;\n}\n\nexport function placePanel({ trigger, root, panel, window, gutter = 16 }: PlacePanel): number {\n const wanted = trigger - root;\n const farthest = window - gutter - panel - root;\n const nearest = gutter - root;\n return Math.round(Math.max(nearest, Math.min(wanted, farthest)));\n}\n","// Client (the Button). The right side of a product's bar, decided once for every product (« the objective is to use the app,\n// not to talk to us »): the primary action is using the app — « Sign in » while sign-up is closed, « Try » once it opens —\n// never a duplicate « Sign in » beside it, never « Contact » (that is a plain link in the footer).\nimport type * as React from \"react\";\n\nimport { Button } from \"../button/button\";\n\n/** The two ways into a product. */\nexport const ProductBarAction = { SignIn: \"sign-in\", Try: \"try\" } as const;\nexport type ProductBarAction = (typeof ProductBarAction)[keyof typeof ProductBarAction];\n\nexport interface ProductBarState {\n /** Whether the product accepts new accounts (its `signupOpen` setting). */\n signupOpen: boolean;\n /** Whether the product has a « try it » action (a free first audit, a founder offer). */\n hasTry: boolean;\n}\n\n/** What the bar shows: one primary, and « Sign in » beside it only when it is not the primary. */\nexport function productBarActions({ signupOpen, hasTry }: ProductBarState): { primary: ProductBarAction; secondary: ProductBarAction | null } {\n return signupOpen && hasTry ? { primary: ProductBarAction.Try, secondary: ProductBarAction.SignIn } : { primary: ProductBarAction.SignIn, secondary: null };\n}\n\nexport interface ProductBarLink {\n href: string;\n /** Passed translated. */\n label: string;\n}\n\nexport type ProductBarActionsProps = {\n /** Where « Sign in » leads, and its words. */\n signIn: ProductBarLink;\n /** « Try for free » (the first audit is free), the founder offer: absent when the product has none. */\n tryIt?: ProductBarLink;\n /** Whether the product accepts new accounts (its `signupOpen` setting): « Try » is the primary action only then. */\n signupOpen: boolean;\n /** The app's link component (Next's `Link`); an `<a>` otherwise. */\n linkAs?: React.ElementType;\n /**\n * `bar` (from `md`, the buttons of the bar) or `panel` (the mobile panel: full-width, the primary last).\n * @default \"bar\"\n */\n placement?: \"bar\" | \"panel\";\n};\n\n/** The product bar's actions: use the app. Put it in `NavBar.Actions` (`placement=\"bar\"`) or in `NavBar.Mobile` (`placement=\"panel\"`). */\nexport function ProductBarActions({ signIn, tryIt, signupOpen, linkAs: Link = \"a\", placement = \"bar\" }: ProductBarActionsProps) {\n const { primary, secondary } = productBarActions({ signupOpen, hasTry: Boolean(tryIt) });\n const link = (kind: ProductBarAction) => (kind === ProductBarAction.Try && tryIt ? tryIt : signIn);\n const panel = placement === \"panel\";\n const button = (kind: ProductBarAction, variant: \"primary\" | \"ghost\") => (\n <Button key={kind} asChild variant={variant} size={panel ? \"md\" : \"sm\"} className={panel ? (variant === \"primary\" ? \"mt-2 w-full font-bold\" : \"w-full\") : variant === \"primary\" ? \"ml-1 hidden font-bold md:inline-flex\" : \"hidden md:inline-flex\"}>\n <Link href={link(kind).href}>{link(kind).label}</Link>\n </Button>\n );\n return (\n <>\n {secondary ? button(secondary, \"ghost\") : null}\n {button(primary, \"primary\")}\n </>\n );\n}\n"],"mappings":"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","names":["window","Fragment","jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/nav-bar/me.ts","../src/nav-bar/nav-bar.tsx","../src/nav-bar/placement.ts","../src/nav-bar/session.tsx","../src/nav-bar/product-actions.tsx"],"sourcesContent":["// The « who is here » contract, the same for every product: `GET /api/me` answers 200 `{ signedIn, signupOpen, account? }`\n// with `Cache-Control: private, no-store` and `Vary: Cookie`. A public page asking who is there is not an error: signed\n// out is a 200 with `signedIn: false`, never a 401.\n\n/** The body of `GET /api/me`. `account` is the product's own shape, present only when `signedIn`. */\nexport interface MeResponse<TAccount = unknown> {\n signedIn: boolean;\n /** Whether the product accepts new accounts (its `signupOpen` setting). */\n signupOpen: boolean;\n account?: TAccount;\n}\n\n/** The headers of the answer: per-visitor, never cached, varying with the session cookie. */\nexport const meHeaders = { \"Cache-Control\": \"private, no-store\", Vary: \"Cookie\" } as const;\n\n/** The 200 answer of `GET /api/me` for a route handler. A signed-out visitor never gets an `account`. */\nexport function meResponse<TAccount>({ signedIn, signupOpen, account }: MeResponse<TAccount>): Response {\n const body: MeResponse<TAccount> = signedIn && account !== undefined ? { signedIn, signupOpen, account } : { signedIn: false, signupOpen };\n return new Response(JSON.stringify(body), { status: 200, headers: { ...meHeaders, \"Content-Type\": \"application/json\" } });\n}\n\n/** A Standard Schema of the body, for `krizakaFetch`: refuses anything that is not the contract. */\nexport const meSchema = {\n \"~standard\": {\n version: 1,\n vendor: \"krizaka\",\n validate(value: unknown) {\n const v = value as Partial<MeResponse> | null;\n if (v && typeof v === \"object\" && typeof v.signedIn === \"boolean\" && typeof v.signupOpen === \"boolean\" && (v.signedIn || !(\"account\" in v))) return { value: v as MeResponse };\n return { issues: [{ message: \"Expected { signedIn: boolean, signupOpen: boolean, account?: … }.\" }] };\n },\n },\n} as const;\n","// Client (scroll, a sliding indicator, menus). Radix NavigationMenu does the menus' semantics and keyboard (Enter, Space\n// and ↓ open; ↑ ↓ Home End walk; Escape closes and returns the focus; Tab out closes); this file draws the Krizaka bar:\n// a floating pill that tightens once the page scrolls, one light that glides to the item under the pointer or the\n// focus and rests on the current page, and a mobile panel that is a plain disclosure (no focus trap, Escape closes).\nimport { NavigationMenu as Nav, Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { FamilyMark, GitHubGlyph } from \"../family-mark\";\nimport { LanguageSwitch, type LanguageSwitchProps } from \"../language-switch/language-switch\";\nimport { type FamilyLabels, familyLabels, type Site, type SiteId, sitesByGroup } from \"../sites/sites\";\nimport { useSlidingIndicator } from \"../sliding-indicator\";\nimport { placePanel } from \"./placement\";\nimport { NavBarSession } from \"./session\";\n\nexport const navBar = tv({\n slots: {\n root:\n \"group/nav relative z-40 mx-auto flex h-14 w-full items-center gap-2 border-border-subtle bg-surface-1 \" +\n \"transition-[height,background-color,border-color,box-shadow] duration-300 motion-reduce:transition-none \" +\n \"data-compact:h-12 data-compact:border-border-default data-compact:bg-surface-1 data-compact:shadow-lg\",\n brand:\n \"mr-2 inline-flex shrink-0 items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg no-underline \" +\n \"rounded-md focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n items: \"relative hidden md:block\",\n list:\n \"group/list relative isolate flex items-center gap-0.5 \" +\n // The ink rule (Cahier, ADR-004): a pen line under the item that is pointed at or focused, resting on the current page.\n \"before:absolute before:left-0 before:top-0 before:-z-10 before:h-0.5 before:w-(--kz-ind-w) before:translate-x-(--kz-ind-x) before:translate-y-[calc(var(--kz-ind-y)+var(--kz-ind-h)-6px)] \" +\n \"before:scale-x-[0.72] before:bg-fg before:opacity-0 before:transition-[translate,width,opacity] before:duration-300 motion-reduce:before:transition-none \" +\n \"data-[indicator=on]:before:opacity-100\",\n item:\n \"inline-flex h-9 select-none items-center gap-1 rounded-sm px-3.5 text-sm font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:text-fg data-active:text-fg data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n // Before the light is ready (server render), the current page carries its own tint.\n \"group-not-data-[indicator=on]/list:data-active:underline group-not-data-[indicator=on]/list:data-active:decoration-2 group-not-data-[indicator=on]/list:data-active:underline-offset-8\",\n chevron: \"h-3.5 w-3.5 transition-transform duration-300 group-data-[state=open]/trigger:rotate-180 motion-reduce:transition-none\",\n viewport:\n // `left` is set by NavBarItems (--kz-menu-left): the panel's edge under its trigger, kept inside the page.\n \"kz-pop absolute left-[var(--kz-menu-left,0px)] top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden \" +\n \"rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[left,width,height] duration-300 motion-reduce:transition-none\",\n // Icon · title · a description of two lines at most. 28 rem (40 rem in two columns), never wider than the page\n // between its gutters, and never taller than the screen.\n panel: \"grid w-[min(28rem,calc(100vw-2rem))] max-h-[calc(100dvh-6rem)] gap-0.5 overflow-y-auto p-1.5\",\n panelWide: \"w-[min(40rem,calc(100vw-2rem))] md:grid-cols-2\",\n menuLink:\n \"group/link flex items-start gap-3 rounded-lg px-2.5 py-2 text-left no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring data-active:bg-accent-soft\",\n menuIcon:\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-border-default bg-surface-2 text-fg-accent \" +\n \"transition-[transform,border-color] duration-300 group-hover/link:-translate-y-0.5 group-hover/link:border-accent [&>svg]:h-4 [&>svg]:w-4 motion-reduce:transform-none\",\n menuTitle: \"block line-clamp-2 wrap-break-word text-sm font-semibold leading-5 text-fg\",\n // Two lines at most, wrapped at word boundaries — a longer one ends in an ellipsis, never cut mid-sentence.\n menuText: \"mt-0.5 block line-clamp-2 wrap-break-word text-xs leading-4 text-fg-secondary\",\n actions: \"ml-auto flex items-center gap-2\",\n toggle:\n \"inline-flex h-9 w-9 items-center justify-center rounded-sm border border-border-subtle bg-surface-2 text-fg md:hidden \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n mobile: \"kz-pop absolute inset-x-0 top-full mt-2 grid gap-1 rounded-2xl border border-border-default bg-surface-1 p-2 shadow-lg md:hidden\",\n mobileGroup: \"grid gap-0.5 [&+&]:mt-1 [&+&]:border-t [&+&]:border-border-subtle [&+&]:pt-2\",\n mobileGroupTitle: \"px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary\",\n mobileLink:\n \"flex items-center justify-between rounded-xl px-3 py-3 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg-accent\",\n // The family switcher: a chevron attached to the brand, its panel aligned on the bar's left edge.\n family: \"hidden md:block\",\n familyTrigger:\n \"group/trigger -ml-2 mr-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-sm text-fg-secondary transition-colors \" +\n \"hover:bg-surface-3 hover:text-fg data-[state=open]:bg-surface-3 data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n familyViewport:\n \"kz-pop absolute left-0 top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden \" +\n \"rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[width,height] duration-300 motion-reduce:transition-none\",\n familyPanel: \"grid w-[min(92vw,42rem)] gap-x-2 gap-y-3 p-3 sm:grid-cols-2\",\n familyGroupTitle: \"px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary\",\n familyLink:\n \"group/link flex items-start gap-3 rounded-xl px-3 py-2.5 text-left no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft\",\n familyMark: \"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-fg\",\n familyName: \"flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm font-semibold text-fg\",\n familyText: \"mt-0.5 block text-xs leading-relaxed text-fg-secondary\",\n familyTag: \"rounded-sm px-1.5 py-px text-[10px] font-semibold\",\n mobileFamily: \"mt-1 grid gap-2 border-t border-border-subtle px-1 pb-1 pt-3\",\n mobileFamilyLink:\n \"flex min-h-11 items-center gap-3 rounded-xl px-2 py-2 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft\",\n badge:\n \"hidden h-6 shrink-0 items-center gap-1 rounded-sm border border-border-subtle bg-surface-2 px-2 font-mono text-[11px] font-medium text-fg-secondary sm:inline-flex\",\n repo:\n \"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-sm text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n variants: {\n floating: {\n true: { root: \"max-w-5xl rounded-sm border pl-5 pr-2 data-compact:max-w-4xl\" },\n false: { root: \"border-b px-4 md:px-6\" },\n },\n },\n defaultVariants: { floating: true },\n});\nconst s = navBar();\n\ninterface NavBarContext {\n label: string;\n open: boolean;\n setOpen: (open: boolean) => void;\n panelId: string;\n}\nconst Context = React.createContext<NavBarContext | null>(null);\n/** The open menu of `NavBar.Items` (`\"\"`: none), so a plain link can close it when the pointer moves on to it. */\nconst ItemsContext = React.createContext<{ close: () => void }>({ close: () => {} });\n/** True inside `NavBar.Mobile`: the family renders as the panel's last group instead of a switcher. */\nconst MobileContext = React.createContext(false);\nconst useNavBar = () => {\n const ctx = React.useContext(Context);\n if (!ctx) throw new Error(\"NavBar parts must be inside <NavBar.Root>.\");\n return ctx;\n};\n\nexport type NavBarRootProps = React.ComponentProps<\"header\"> & {\n /** The accessible name of the navigation (“Main”) — passed translated. */\n label: string;\n /**\n * Pixels of scroll after which the bar tightens (denser, lower, lifted). `false`: never.\n * @default 24\n */\n compactAfter?: number | false;\n /**\n * A floating pill (the Krizaka bar) or a full-width bar with a hairline under it.\n * @default true\n */\n floating?: boolean;\n};\n\n/** The bar. Place it in a `sticky top-3` (floating) or `sticky top-0` wrapper — or let it scroll. */\nexport function NavBarRoot({ label, compactAfter = 24, floating = true, className, children, ...props }: NavBarRootProps) {\n const [compact, setCompact] = React.useState(false);\n const [open, setOpen] = React.useState(false);\n const panelId = React.useId();\n React.useEffect(() => {\n if (compactAfter === false) return;\n const onScroll = () => setCompact(window.scrollY > compactAfter);\n onScroll();\n window.addEventListener(\"scroll\", onScroll, { passive: true });\n return () => window.removeEventListener(\"scroll\", onScroll);\n }, [compactAfter]);\n const ctx = React.useMemo(() => ({ label, open, setOpen, panelId }), [label, open, panelId]);\n return (\n <Context.Provider value={ctx}>\n <header data-compact={compact ? \"\" : undefined} data-floating={floating} className={navBar({ floating }).root({ className })} {...props}>\n {children}\n </header>\n </Context.Provider>\n );\n}\n\nexport type NavBarBrandProps = React.ComponentProps<\"a\"> & {\n /** Renders your link (a router `<Link>`) with the brand's look. */\n asChild?: boolean;\n};\n\n/** The brand: a mark and a name, linking home. */\nexport function NavBarBrand({ asChild, className, ...props }: NavBarBrandProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp className={s.brand({ className })} {...props} />;\n}\n\nexport type NavBarItemsProps = Omit<React.ComponentProps<typeof Nav.Root>, \"orientation\">;\n\n/**\n * The desktop navigation: links and menus, with the light that glides between them. Hidden below `md` (see\n * `NavBar.Mobile`). A menu opens on click, Enter, Space or ↓ — or when the pointer rests on its trigger (hover intent,\n * `delayDuration`, 200 ms): passing over the bar opens nothing. While a menu is open the light stays on its trigger;\n * moving on to a plain link closes the menu, so the bar never shows two current items. A click outside or Escape closes.\n */\nexport function NavBarItems({ className, children, value: valueProp, defaultValue, onValueChange, delayDuration = 200, ...props }: NavBarItemsProps) {\n const { label } = useNavBar();\n const [inner, setInner] = React.useState(defaultValue ?? \"\");\n const value = valueProp ?? inner;\n const setValue = React.useCallback(\n (next: string) => {\n setInner(next);\n onValueChange?.(next);\n },\n [onValueChange],\n );\n const items = React.useMemo(() => ({ close: () => setValue(\"\") }), [setValue]);\n const { ref, handlers } = useSlidingIndicator<HTMLUListElement>({\n item: \"[data-nav-item]\",\n active: \"[data-nav-item][data-active]\",\n prefer: \"[data-nav-item][data-state=open]\",\n follow: true,\n });\n const root = React.useRef<HTMLElement>(null);\n const viewport = React.useRef<HTMLDivElement>(null);\n // The open panel sits under its trigger and stays inside the page (collision): measured when a menu opens, when\n // the panel changes size (another menu) and when the window does.\n React.useLayoutEffect(() => {\n const panel = viewport.current;\n const nav = root.current;\n if (!panel || !nav || !value) return;\n const place = () => {\n const trigger = nav.querySelector<HTMLElement>(\"[data-nav-item][data-state=open]\");\n const width = Number.parseFloat(panel.style.getPropertyValue(\"--radix-navigation-menu-viewport-width\"));\n if (!trigger || !Number.isFinite(width)) return;\n const left = `${placePanel({ trigger: trigger.getBoundingClientRect().left, root: nav.getBoundingClientRect().left, panel: width, window: document.documentElement.clientWidth })}px`;\n if (panel.style.getPropertyValue(\"--kz-menu-left\") !== left) panel.style.setProperty(\"--kz-menu-left\", left);\n };\n place();\n const watch = new MutationObserver(place);\n watch.observe(panel, { attributes: true, attributeFilter: [\"style\"] });\n window.addEventListener(\"resize\", place);\n return () => {\n watch.disconnect();\n window.removeEventListener(\"resize\", place);\n };\n }, [value]);\n return (\n <ItemsContext.Provider value={items}>\n <Nav.Root ref={root} aria-label={label} className={s.items({ className })} value={value} onValueChange={setValue} delayDuration={delayDuration} {...props}>\n <Nav.List ref={ref} className={s.list()} {...handlers}>\n {children}\n </Nav.List>\n <Nav.Viewport ref={viewport} className={s.viewport()} />\n </Nav.Root>\n </ItemsContext.Provider>\n );\n}\n\nexport type NavBarLinkProps = Omit<React.ComponentProps<typeof Nav.Link>, \"active\"> & {\n /** The current page: `aria-current=\"page\"`, and the light rests on it. */\n active?: boolean;\n /** Classes on the list item around the link (to show it from a breakpoint only). */\n itemClassName?: string;\n};\n\n/** A link of the bar. `asChild` renders your router's `<Link>`. */\nexport function NavBarLink({ active, className, itemClassName, onPointerEnter, ...props }: NavBarLinkProps) {\n const { close } = React.useContext(ItemsContext);\n return (\n <Nav.Item className={itemClassName}>\n <Nav.Link\n data-nav-item=\"\"\n data-active={active ? \"\" : undefined}\n active={active}\n aria-current={active ? \"page\" : undefined}\n className={s.item({ className })}\n onPointerEnter={(e) => {\n onPointerEnter?.(e);\n close();\n }}\n {...props}\n />\n </Nav.Item>\n );\n}\n\nexport type NavBarMenuProps = Omit<React.ComponentProps<typeof Nav.Item>, \"children\"> & {\n /** The trigger's words (“Products”) — passed translated. */\n label: string;\n /** The current page is inside this menu: the light rests on its trigger. */\n active?: boolean;\n /** The menu's links (`NavBar.MenuLink`), laid out in a panel; `columns` sets the grid. */\n children: React.ReactNode;\n /**\n * Columns of the panel.\n * @default 1\n */\n columns?: 1 | 2;\n /**\n * A section with this many links or fewer needs no hidden list: they sit in the bar as plain links (the active one\n * marked, no dropdown, `label` unused on the desktop). Above it, a dropdown. `0` always makes a dropdown.\n * @default 3\n */\n inlineUpTo?: number;\n /**\n * From which breakpoint the inline links stand in the bar. Below it (between the phone panel at `md` and this\n * breakpoint) the section is the dropdown, so long labels never overflow a tablet-width bar. `md` inlines as soon as\n * the bar is shown.\n * @default \"lg\"\n */\n inlineFrom?: \"md\" | \"lg\" | \"xl\";\n};\n\n// Static class names (Tailwind reads them at build time).\nconst INLINE_HIDE = { md: \"\", lg: \"max-lg:hidden\", xl: \"max-xl:hidden\" } as const;\nconst DROPDOWN_HIDE = { md: \"\", lg: \"lg:hidden\", xl: \"xl:hidden\" } as const;\n\n/**\n * A menu of the bar: its trigger, and its links in a panel that opens under the bar. A menu of `inlineUpTo` links or\n * fewer (3 by default) is not a menu at all: its links stand in the bar, each with its active state — a hidden list of\n * three is one click more for nothing. The phone's panel groups them as usual (`NavBar.MobileGroup`).\n */\nexport function NavBarMenu({ label, active, columns = 1, inlineUpTo = 3, inlineFrom = \"lg\", children, className, ...props }: NavBarMenuProps) {\n const links = React.Children.toArray(children);\n const dropdown = (hide: string) => (\n <Nav.Item className={cn(hide, className)} {...props}>\n <Nav.Trigger data-nav-item=\"\" data-active={active ? \"\" : undefined} className={cn(s.item(), \"group/trigger\")}>\n {label}\n <svg viewBox=\"0 0 24 24\" className={s.chevron()} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </Nav.Trigger>\n <Nav.Content className={cn(s.panel(), columns === 2 && s.panelWide())}>{children}</Nav.Content>\n </Nav.Item>\n );\n const inline = links.length > 0 && links.length <= inlineUpTo && links.every((c) => React.isValidElement(c) && c.type === NavBarMenuLink);\n if (inline) {\n return (\n <>\n {inlineFrom !== \"md\" && dropdown(DROPDOWN_HIDE[inlineFrom])}\n {links.map((link) => {\n const { title, href, active: here, asChild, children: child, icon: _icon, description: _description, className: linkClass, ...rest } = (link as React.ReactElement<NavBarMenuLinkProps>).props;\n return (\n <NavBarLink key={(link as React.ReactElement).key} asChild={asChild} href={asChild ? undefined : href} active={here} className={linkClass} itemClassName={INLINE_HIDE[inlineFrom]} {...rest}>\n {asChild && React.isValidElement<{ children?: React.ReactNode }>(child) ? React.cloneElement(child, undefined, title) : title}\n </NavBarLink>\n );\n })}\n </>\n );\n }\n return dropdown(\"\");\n}\n\nexport type NavBarMenuLinkProps = Omit<React.ComponentProps<typeof Nav.Link>, \"title\" | \"active\"> & {\n /** The link's name — passed translated. */\n title: string;\n /** One line under it — passed translated. */\n description?: string;\n /** An icon (a signature icon of `@krizaka/icons`: its node lights up on hover). */\n icon?: React.ReactNode;\n /** The current page. */\n active?: boolean;\n};\n\n/** A link inside a menu: an icon, a name and a line of text. */\nexport function NavBarMenuLink({ title, description, icon, active, href, className, asChild, children, ...props }: NavBarMenuLinkProps) {\n const body = (\n <>\n {icon && <span className={s.menuIcon()}>{icon}</span>}\n <span className=\"min-w-0 flex-1\">\n <span className={s.menuTitle()}>{title}</span>\n {description && <span className={s.menuText()}>{description}</span>}\n </span>\n </>\n );\n return (\n <Nav.Link asChild={asChild} href={asChild ? undefined : href} active={active} aria-current={active ? \"page\" : undefined} data-active={active ? \"\" : undefined} className={s.menuLink({ className })} {...props}>\n {asChild && React.isValidElement<{ children?: React.ReactNode }>(children) ? React.cloneElement(children, undefined, body) : body}\n </Nav.Link>\n );\n}\n\n/** The right side: search, theme, language, the call to action. */\nexport function NavBarActions({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.actions({ className })} {...props} />;\n}\n\nexport type NavBarMobileProps = React.ComponentProps<\"nav\"> & {\n /** The toggle's name when closed (“Open the menu”) — passed translated. */\n openLabel: string;\n /** The toggle's name when open (“Close the menu”) — passed translated. */\n closeLabel: string;\n};\n\n/**\n * Below `md`: a toggle, and a panel under the bar with its links (`NavBar.MobileLink`), grouped like the bar's menus\n * (`NavBar.MobileGroup`). A disclosure: Escape, a click on a link or a press outside close it; Escape returns the focus\n * to the toggle.\n */\nexport function NavBarMobile({ openLabel, closeLabel, className, children, ...props }: NavBarMobileProps) {\n const { label, open, setOpen, panelId } = useNavBar();\n const toggle = React.useRef<HTMLButtonElement>(null);\n React.useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n setOpen(false);\n toggle.current?.focus();\n };\n // A press outside the panel and its toggle closes it (the page under it stays usable).\n const onPress = (e: PointerEvent) => {\n const target = e.target as Node | null;\n if (!target || toggle.current?.contains(target) || document.getElementById(panelId)?.contains(target)) return;\n setOpen(false);\n };\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(\"pointerdown\", onPress);\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.removeEventListener(\"pointerdown\", onPress);\n };\n }, [open, setOpen, panelId]);\n return (\n <>\n <button ref={toggle} type=\"button\" aria-expanded={open} aria-controls={panelId} aria-label={open ? closeLabel : openLabel} onClick={() => setOpen(!open)} className={s.toggle()}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4.5 w-4.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n {open ? <path d=\"M18 6 6 18M6 6l12 12\" /> : <path d=\"M4 7h16M4 12h16M4 17h10\" />}\n </svg>\n </button>\n {open && (\n <nav\n id={panelId}\n aria-label={label}\n className={s.mobile({ className })}\n onClick={(e) => {\n if ((e.target as Element).closest(\"a\")) setOpen(false);\n }}\n {...props}\n >\n <MobileContext.Provider value>{children}</MobileContext.Provider>\n </nav>\n )}\n </>\n );\n}\n\nexport type NavBarMobileGroupProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The group's heading — the same words as the bar's menu (“Product”) — passed translated. */\n label: string;\n};\n\n/** A group of the mobile panel: the links of one of the bar's menus under its name, in the same order. */\nexport function NavBarMobileGroup({ label, className, children, ...props }: NavBarMobileGroupProps) {\n const id = React.useId();\n return (\n <div role=\"group\" aria-labelledby={id} className={s.mobileGroup({ className })} {...props}>\n <p id={id} className={s.mobileGroupTitle()}>\n {label}\n </p>\n {children}\n </div>\n );\n}\n\nexport type NavBarMobileLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the mobile panel. */\nexport function NavBarMobileLink({ active, asChild, className, ...props }: NavBarMobileLinkProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.mobileLink({ className })} {...props} />;\n}\n\n\nconst tagTone = {\n upcoming: \"bg-accent-soft text-fg ring-1 ring-inset ring-accent/40\",\n construction: \"bg-warning/15 text-fg ring-1 ring-inset ring-warning/40\",\n development: \"bg-surface-3 text-fg ring-1 ring-inset ring-border-strong\",\n current: \"bg-surface-3 text-fg-secondary\",\n};\n\n/** A site's name and its tags: status when not released, “You are here” on the current one. */\nfunction FamilyName({ site, current, labels }: { site: Site; current: boolean; labels: FamilyLabels }) {\n return (\n <span className={s.familyName()}>\n {site.name}\n {site.status !== \"released\" && <span className={cn(s.familyTag(), tagTone[site.status])}>{labels.status[site.status]}</span>}\n {current && <span className={cn(s.familyTag(), tagTone.current)}>{labels.current}</span>}\n </span>\n );\n}\n\nexport type NavBarFamilyProps = {\n /** The site this bar belongs to (`@krizaka/ui/sites`): marked in the family, `aria-current=\"true\"`. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** Opens the panel at first render (a story, a screenshot). */\n defaultOpen?: boolean;\n /** Classes of the switcher (or, inside `NavBar.Mobile`, of the family's group). */\n className?: string;\n};\n\n/**\n * @deprecated No site carries the family switcher any more (2026-10-22): krizaka.com is the only way back between the Krizaka sites, through the footer's « A Krizaka project » line. Removed in the next minor; `krizaka/no-family-switcher` refuses it.\n *\n * The family switcher, attached to the brand (place it right after `NavBar.Brand`): a chevron that opens every site of\n * Krizaka grouped — Krizaka · Products · Open source · GitHub — the current one marked. It opens on click, Enter, Space\n * or ↓ (never on hover); ↑ ↓ walk the sites, Escape closes and returns the focus. Hidden below `md`: place a second\n * `NavBar.Family` as the last child of `NavBar.Mobile`, where it renders as the panel's last group.\n */\nexport function NavBarFamily({ current, labels = familyLabels.en, defaultOpen, className }: NavBarFamilyProps) {\n const inMobile = React.useContext(MobileContext);\n const id = React.useId();\n const groups = sitesByGroup();\n if (inMobile) {\n return (\n <div role=\"group\" aria-labelledby={`${id}-family`} className={s.mobileFamily({ className })}>\n <p id={`${id}-family`} className={s.familyGroupTitle()}>\n {labels.family}\n </p>\n {groups.map(({ group, sites }) => (\n <div key={group}>\n {/* The company's own group is named like the family itself: its heading would repeat the panel's. */}\n {group !== \"krizaka\" && (\n <p id={`${id}-${group}`} className={s.familyGroupTitle()}>\n {labels.groups[group]}\n </p>\n )}\n <ul aria-labelledby={group !== \"krizaka\" ? `${id}-${group}` : `${id}-family`} className=\"grid gap-0.5\">\n {sites.map((site) => (\n <li key={site.id}>\n <a href={site.url} data-current={site.id === current ? \"\" : undefined} aria-current={site.id === current ? \"true\" : undefined} className={s.mobileFamilyLink()}>\n <span className={s.familyMark()}>\n <FamilyMark mark={site.mark} size={24} />\n </span>\n <FamilyName site={site} current={site.id === current} labels={labels} />\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n );\n }\n // Click only: a pointer passing over the brand never opens the family (Radix opens its menus on hover by default).\n const noHover = (e: React.PointerEvent) => e.preventDefault();\n const columns = [groups.filter((g) => g.group === \"krizaka\" || g.group === \"products\"), groups.filter((g) => g.group === \"open-source\" || g.group === \"github\")];\n return (\n <Nav.Root aria-label={labels.family} defaultValue={defaultOpen ? \"family\" : undefined} className={s.family({ className })}>\n <Nav.List className=\"flex\">\n <Nav.Item value=\"family\">\n <Nav.Trigger aria-label={labels.family} onPointerMove={noHover} onPointerLeave={noHover} className={s.familyTrigger()}>\n <svg viewBox=\"0 0 24 24\" className={s.chevron()} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </Nav.Trigger>\n <Nav.Content onPointerLeave={noHover} className={s.familyPanel()}>\n {columns.map((column, i) => (\n <div key={i} className=\"grid content-start gap-3\">\n {column.map(({ group, sites }) => (\n <div key={group}>\n <p id={`${id}-${group}`} className={s.familyGroupTitle()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className=\"grid gap-0.5\">\n {sites.map((site) => (\n <li key={site.id}>\n <Nav.Link href={site.url} data-current={site.id === current ? \"\" : undefined} aria-current={site.id === current ? \"true\" : undefined} className={s.familyLink()}>\n <span className={s.familyMark()}>\n <FamilyMark mark={site.mark} size={28} />\n </span>\n <span className=\"min-w-0\">\n <FamilyName site={site} current={site.id === current} labels={labels} />\n <span className={s.familyText()}>{labels.descriptions[site.id]}</span>\n </span>\n </Nav.Link>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n ))}\n </Nav.Content>\n </Nav.Item>\n </Nav.List>\n <Nav.Viewport onPointerLeave={noHover} className={s.familyViewport()} />\n </Nav.Root>\n );\n}\n\nexport type NavBarBadgeProps = React.ComponentProps<\"span\"> & {\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n};\n\n/** A small mono badge beside the brand: the environment and the version (`DEV · v1.2.3`). Hidden below `sm`. */\nexport function NavBarBadge({ env, version, className, children, ...props }: NavBarBadgeProps) {\n const parts = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean);\n return (\n <span className={s.badge({ className })} {...props}>\n {parts.join(\" · \")}\n {children}\n </span>\n );\n}\n\nexport type NavBarLanguageProps = Omit<LanguageSwitchProps, \"variant\">;\n\n/**\n * The language switch, the same on every site: in the bar a globe and the current code (FR) opening a short menu of\n * the languages by their own names; inside `NavBar.Mobile` the same languages as a row in the preferences.\n */\nexport function NavBarLanguage(props: NavBarLanguageProps) {\n const inMobile = React.useContext(MobileContext);\n return <LanguageSwitch variant={inMobile ? \"inline\" : \"menu\"} {...props} />;\n}\n\nexport type NavBarMobilePreferencesProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The group's heading (“Preferences”) — passed translated. */\n label: string;\n};\n\n/** The last group of the mobile panel: the preferences (theme, `NavBar.Language`), in a row under their heading. */\nexport function NavBarMobilePreferences({ label, className, children, ...props }: NavBarMobilePreferencesProps) {\n const id = React.useId();\n return (\n <div role=\"group\" aria-labelledby={id} className={s.mobileGroup({ className })} {...props}>\n <p id={id} className={s.mobileGroupTitle()}>\n {label}\n </p>\n <div className=\"flex flex-wrap items-center gap-2 px-3 py-1\">{children}</div>\n </div>\n );\n}\n\nexport type NavBarRepoProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The repository the site is built from. */\n href: string;\n /** The link's accessible name (“Source on GitHub”) — passed translated. */\n label: string;\n};\n\n/** The site's repository on GitHub, an icon link of `NavBar.Actions`. */\nexport function NavBarRepo({ label, className, ...props }: NavBarRepoProps) {\n return (\n <a aria-label={label} className={s.repo({ className })} {...props}>\n <GitHubGlyph size={18} />\n </a>\n );\n}\n\n/**\n * `NavBar.Root/Brand/Family/Badge/Items/Link/Menu/MenuLink/Actions/Repo/Session/Language/Mobile/MobileGroup/MobilePreferences/MobileLink` — the Krizaka navigation bar,\n * the same on every site of the family: floating, tightening on scroll, the family switcher on the brand, one light\n * gliding between its items, accessible menus, a mobile panel.\n */\nexport const NavBar = {\n Root: NavBarRoot,\n Brand: NavBarBrand,\n Family: NavBarFamily,\n Badge: NavBarBadge,\n Items: NavBarItems,\n Link: NavBarLink,\n Menu: NavBarMenu,\n MenuLink: NavBarMenuLink,\n Actions: NavBarActions,\n Repo: NavBarRepo,\n Session: NavBarSession,\n Language: NavBarLanguage,\n Mobile: NavBarMobile,\n MobilePreferences: NavBarMobilePreferences,\n MobileGroup: NavBarMobileGroup,\n MobileLink: NavBarMobileLink,\n};\n","/**\n * Where a menu panel of the bar sits: its left edge under its trigger's, pushed back inside the page when it would run\n * past the right edge, never closer to the left edge than the gutter. All values are pixels of the page (a bounding\n * rect's `left`, a width), the result is the panel's `left` relative to the bar's navigation (`root`). Pure, so a\n * viewport of 360 px and one of 1280 px are tested without a browser.\n */\nexport interface PlacePanel {\n /** The trigger's left edge. */\n trigger: number;\n /** The navigation's left edge (the panel is positioned inside it). */\n root: number;\n /** The panel's width. */\n panel: number;\n /** The window's width. */\n window: number;\n /**\n * The space kept between the panel and the window's edges.\n * @default 16\n */\n gutter?: number;\n}\n\nexport function placePanel({ trigger, root, panel, window, gutter = 16 }: PlacePanel): number {\n const wanted = trigger - root;\n const farthest = window - gutter - panel - root;\n const nearest = gutter - root;\n return Math.round(Math.max(nearest, Math.min(wanted, farthest)));\n}\n","// Client. The bar's « who is here » island, the same for every product: it asks `GET /api/me` (the contract of ./me)\n// through @krizaka/query and shows the product's account menu or its sign-in actions. It needs a QueryClient above it.\nimport { krizakaFetch, useQuery } from \"@krizaka/query\";\nimport type * as React from \"react\";\n\nimport { type MeResponse, meSchema } from \"./me\";\n\nexport type NavBarSessionProps<TAccount = unknown> = {\n /**\n * Where the contract is served.\n * @default \"/api/me\"\n */\n endpoint?: string;\n /** Signed out: the product's `ProductBarActions`, told whether sign-up is open. */\n signedOut: (state: { signupOpen: boolean }) => React.ReactNode;\n /** Signed in: the product's `AccountMenu`, given the account. */\n signedIn: (account: TAccount, state: { signupOpen: boolean }) => React.ReactNode;\n /** The hint's words while the answer is on its way (“Checking your session…”) — passed translated. */\n hint: string;\n /** Classes of the loading placeholder. */\n className?: string;\n};\n\nexport const sessionKey = (endpoint: string) => [\"krizaka\", \"session\", endpoint] as const;\n\n/**\n * The bar's session island: put it in `NavBar.Actions`. While the answer is on its way it reserves the place and says\n * `hint` politely; if the request fails it shows the signed-out actions (the visitor can still sign in).\n */\nexport function NavBarSession<TAccount = unknown>({ endpoint = \"/api/me\", signedOut, signedIn, hint, className }: NavBarSessionProps<TAccount>) {\n const { data, isPending, isError } = useQuery({\n queryKey: sessionKey(endpoint),\n queryFn: ({ signal }) => krizakaFetch(endpoint, { schema: meSchema, signal, cache: \"no-store\" }),\n staleTime: 30_000,\n retry: false,\n throwOnError: false,\n });\n if (isPending) {\n return (\n <span role=\"status\" aria-live=\"polite\" data-state=\"loading\" className={className}>\n <span className=\"sr-only\">{hint}</span>\n </span>\n );\n }\n const me = (!isError && data ? data : { signedIn: false, signupOpen: false }) as MeResponse<TAccount>;\n const state = { signupOpen: me.signupOpen };\n return <>{me.signedIn && me.account !== undefined ? signedIn(me.account, state) : signedOut(state)}</>;\n}\n","// Client (the Button). The right side of a product's bar, decided once for every product (« the objective is to use the app,\n// not to talk to us »): the primary action is using the app — « Sign in » while sign-up is closed, « Try » once it opens —\n// never a duplicate « Sign in » beside it, never « Contact » (that is a plain link in the footer).\nimport type * as React from \"react\";\n\nimport { Button } from \"../button/button\";\n\n/** The two ways into a product. */\nexport const ProductBarAction = { SignIn: \"sign-in\", Try: \"try\" } as const;\nexport type ProductBarAction = (typeof ProductBarAction)[keyof typeof ProductBarAction];\n\nexport interface ProductBarState {\n /** Whether the product accepts new accounts (its `signupOpen` setting). */\n signupOpen: boolean;\n /** Whether the product has a « try it » action (a free first audit, a founder offer). */\n hasTry: boolean;\n}\n\n/** What the bar shows: one primary, and « Sign in » beside it only when it is not the primary. */\nexport function productBarActions({ signupOpen, hasTry }: ProductBarState): { primary: ProductBarAction; secondary: ProductBarAction | null } {\n return signupOpen && hasTry ? { primary: ProductBarAction.Try, secondary: ProductBarAction.SignIn } : { primary: ProductBarAction.SignIn, secondary: null };\n}\n\nexport interface ProductBarLink {\n href: string;\n /** Passed translated. */\n label: string;\n}\n\nexport type ProductBarActionsProps = {\n /** Where « Sign in » leads, and its words. */\n signIn: ProductBarLink;\n /** « Try for free » (the first audit is free), the founder offer: absent when the product has none. */\n tryIt?: ProductBarLink;\n /** Whether the product accepts new accounts (its `signupOpen` setting): « Try » is the primary action only then. */\n signupOpen: boolean;\n /** The app's link component (Next's `Link`); an `<a>` otherwise. */\n linkAs?: React.ElementType;\n /**\n * `bar` (from `md`, the buttons of the bar) or `panel` (the mobile panel: full-width, the primary last).\n * @default \"bar\"\n */\n placement?: \"bar\" | \"panel\";\n};\n\n/** The product bar's actions: use the app. Put it in `NavBar.Actions` (`placement=\"bar\"`) or in `NavBar.Mobile` (`placement=\"panel\"`). */\nexport function ProductBarActions({ signIn, tryIt, signupOpen, linkAs: Link = \"a\", placement = \"bar\" }: ProductBarActionsProps) {\n const { primary, secondary } = productBarActions({ signupOpen, hasTry: Boolean(tryIt) });\n const link = (kind: ProductBarAction) => (kind === ProductBarAction.Try && tryIt ? tryIt : signIn);\n const panel = placement === \"panel\";\n const button = (kind: ProductBarAction, variant: \"primary\" | \"ghost\") => (\n <Button key={kind} asChild variant={variant} size={panel ? \"md\" : \"sm\"} className={panel ? (variant === \"primary\" ? \"mt-2 w-full font-bold\" : \"w-full\") : variant === \"primary\" ? \"ml-1 hidden font-bold md:inline-flex\" : \"hidden md:inline-flex\"}>\n <Link href={link(kind).href}>{link(kind).label}</Link>\n </Button>\n );\n return (\n <>\n {secondary ? button(secondary, \"ghost\") : null}\n {button(primary, \"primary\")}\n </>\n );\n}\n"],"mappings":"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","names":["window","Fragment","jsx","Fragment","jsx","jsxs"]}
@@ -0,0 +1,151 @@
1
+ import * as tailwind_variants from 'tailwind-variants';
2
+ import * as React from 'react';
3
+
4
+ declare const notificationPreferences: tailwind_variants.TVReturnType<{
5
+ [key: string]: {
6
+ [key: string]: tailwind_variants.ClassValue | {
7
+ head?: tailwind_variants.ClassValue;
8
+ table?: tailwind_variants.ClassValue;
9
+ name?: tailwind_variants.ClassValue;
10
+ cell?: tailwind_variants.ClassValue;
11
+ note?: tailwind_variants.ClassValue;
12
+ row?: tailwind_variants.ClassValue;
13
+ hint?: tailwind_variants.ClassValue;
14
+ root?: tailwind_variants.ClassValue;
15
+ channelCell?: tailwind_variants.ClassValue;
16
+ cornerCell?: tailwind_variants.ClassValue;
17
+ category?: tailwind_variants.ClassValue;
18
+ };
19
+ };
20
+ } | {
21
+ [x: string]: {
22
+ [x: string]: tailwind_variants.ClassValue | {
23
+ head?: tailwind_variants.ClassValue;
24
+ table?: tailwind_variants.ClassValue;
25
+ name?: tailwind_variants.ClassValue;
26
+ cell?: tailwind_variants.ClassValue;
27
+ note?: tailwind_variants.ClassValue;
28
+ row?: tailwind_variants.ClassValue;
29
+ hint?: tailwind_variants.ClassValue;
30
+ root?: tailwind_variants.ClassValue;
31
+ channelCell?: tailwind_variants.ClassValue;
32
+ cornerCell?: tailwind_variants.ClassValue;
33
+ category?: tailwind_variants.ClassValue;
34
+ };
35
+ };
36
+ } | {}, {
37
+ root: string;
38
+ hint: string;
39
+ table: string;
40
+ head: string;
41
+ channelCell: string;
42
+ cornerCell: string;
43
+ row: string;
44
+ category: string;
45
+ name: string;
46
+ note: string;
47
+ cell: string;
48
+ }, undefined, {
49
+ [key: string]: {
50
+ [key: string]: tailwind_variants.ClassValue | {
51
+ head?: tailwind_variants.ClassValue;
52
+ table?: tailwind_variants.ClassValue;
53
+ name?: tailwind_variants.ClassValue;
54
+ cell?: tailwind_variants.ClassValue;
55
+ note?: tailwind_variants.ClassValue;
56
+ row?: tailwind_variants.ClassValue;
57
+ hint?: tailwind_variants.ClassValue;
58
+ root?: tailwind_variants.ClassValue;
59
+ channelCell?: tailwind_variants.ClassValue;
60
+ cornerCell?: tailwind_variants.ClassValue;
61
+ category?: tailwind_variants.ClassValue;
62
+ };
63
+ };
64
+ } | {}, {
65
+ root: string;
66
+ hint: string;
67
+ table: string;
68
+ head: string;
69
+ channelCell: string;
70
+ cornerCell: string;
71
+ row: string;
72
+ category: string;
73
+ name: string;
74
+ note: string;
75
+ cell: string;
76
+ }, tailwind_variants.TVReturnTypeLike<unknown, {
77
+ root: string;
78
+ hint: string;
79
+ table: string;
80
+ head: string;
81
+ channelCell: string;
82
+ cornerCell: string;
83
+ row: string;
84
+ category: string;
85
+ name: string;
86
+ note: string;
87
+ cell: string;
88
+ }>>;
89
+ /** Category id → channel id → on. A missing entry is off; a crossing a category does not use (see `channels`) is never written. */
90
+ type NotificationMatrix = Record<string, Record<string, boolean>>;
91
+ type NotificationChannel = {
92
+ /** Its key in the matrix (`app`, `email`). */
93
+ id: string;
94
+ /** The column's name (`In the app`, `By e-mail`). */
95
+ label: string;
96
+ /** The whole column is inert (e-mail is off for the account). */
97
+ disabled?: boolean;
98
+ };
99
+ type NotificationCategory = {
100
+ /** Its key in the matrix (`social`, `security`). */
101
+ id: string;
102
+ /** The row's name. */
103
+ label: string;
104
+ /** What these notifications are, one line. */
105
+ description?: string;
106
+ /** The channels this category can use (ids); left out, every channel. Other crossings show no switch. */
107
+ channels?: readonly string[];
108
+ /** Always on, and shown so (security): the switches are inert and `lockedNote` replaces the description. */
109
+ locked?: boolean;
110
+ lockedNote?: string;
111
+ };
112
+ type NotificationPreset = {
113
+ /** Its key (`everything`, `essentials`). */
114
+ id: string;
115
+ /** The chip's words. */
116
+ label: string;
117
+ /** What the preset does, one sentence, shown while it is the one in force. */
118
+ hint: string;
119
+ /** The matrix it sets (locked categories stay on and inert channels keep their value, whatever it says). */
120
+ value: NotificationMatrix;
121
+ };
122
+ type NotificationPreferencesProps = {
123
+ /** The group's accessible name (`Notification settings`). */
124
+ label: string;
125
+ /** The columns: where a notification can go. */
126
+ channels: readonly NotificationChannel[];
127
+ /** The rows: what can be sent. */
128
+ categories: readonly NotificationCategory[];
129
+ /** What is on, by category then channel (controlled). */
130
+ value: NotificationMatrix;
131
+ /** Called with the whole matrix after a switch or a preset — normalised: locked rows on, inert channels unchanged, unused crossings absent. */
132
+ onValueChange: (next: NotificationMatrix) => void;
133
+ /** Quick settings above the matrix (`Everything`, `Essentials`, `Nothing`). */
134
+ presets?: readonly NotificationPreset[];
135
+ /** The presets' own accessible name (`Presets`). Required with `presets`. */
136
+ presetsLabel?: string;
137
+ /** Said under the presets when the matrix matches none (`Custom`). */
138
+ customHint?: string;
139
+ /** Classes merged on the root. */
140
+ className?: string;
141
+ };
142
+ /** The preset in force, or null for a custom matrix. */
143
+ declare function presetInForce(value: NotificationMatrix, presets: readonly NotificationPreset[], categories: readonly NotificationCategory[], channels: readonly NotificationChannel[]): string | null;
144
+ /**
145
+ * The matrix the controls can show: every crossing a category uses, locked rows on, an inert channel keeping its
146
+ * `current` value whatever `next` says, and nothing for the crossings a category does not use.
147
+ */
148
+ declare function normalizeMatrix(next: NotificationMatrix, current: NotificationMatrix, categories: readonly NotificationCategory[], channels: readonly NotificationChannel[]): NotificationMatrix;
149
+ declare function NotificationPreferences({ label, channels, categories, value, onValueChange, presets, presetsLabel, customHint, className }: NotificationPreferencesProps): React.JSX.Element;
150
+
151
+ export { type NotificationCategory, type NotificationChannel, type NotificationMatrix, NotificationPreferences, type NotificationPreferencesProps, type NotificationPreset, normalizeMatrix, notificationPreferences, presetInForce };
@@ -0,0 +1,77 @@
1
+ "use client";
2
+ import {
3
+ Chip
4
+ } from "./chunk-7U5TXA5Q.js";
5
+ import {
6
+ Switch
7
+ } from "./chunk-CSRKYZ53.js";
8
+ import "./chunk-D3T54RSL.js";
9
+
10
+ // src/notification-preferences/notification-preferences.tsx
11
+ import { tv } from "tailwind-variants";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ var notificationPreferences = tv({
14
+ slots: {
15
+ root: "flex flex-col gap-3",
16
+ hint: "text-xs text-fg-secondary",
17
+ table: "w-full overflow-hidden rounded-2xl border border-border-default text-left",
18
+ head: "bg-surface-2 text-xs font-semibold text-fg-secondary",
19
+ channelCell: "w-16 px-2 py-2.5 text-center sm:w-24",
20
+ cornerCell: "px-4 py-2.5",
21
+ row: "border-t border-border-subtle",
22
+ category: "px-4 py-3 text-left font-normal",
23
+ name: "block text-sm font-semibold text-fg",
24
+ note: "block text-xs text-fg-secondary",
25
+ cell: "px-2 py-3 text-center"
26
+ }
27
+ });
28
+ var uses = (c, channel) => !c.channels || c.channels.includes(channel);
29
+ var same = (a, b, categories, channels) => categories.every((c) => c.locked || channels.every((ch) => ch.disabled || !uses(c, ch.id) || Boolean(a[c.id]?.[ch.id]) === Boolean(b[c.id]?.[ch.id])));
30
+ function presetInForce(value, presets, categories, channels) {
31
+ return presets.find((p) => same(value, p.value, categories, channels))?.id ?? null;
32
+ }
33
+ function normalizeMatrix(next, current, categories, channels) {
34
+ return Object.fromEntries(
35
+ categories.map((c) => [
36
+ c.id,
37
+ Object.fromEntries(
38
+ channels.filter((ch) => uses(c, ch.id)).map((ch) => [ch.id, c.locked ? true : Boolean((ch.disabled ? current : next)[c.id]?.[ch.id])])
39
+ )
40
+ ])
41
+ );
42
+ }
43
+ function NotificationPreferences({ label, channels, categories, value, onValueChange, presets, presetsLabel, customHint, className }) {
44
+ const s = notificationPreferences();
45
+ const inForce = presets ? presetInForce(value, presets, categories, channels) : null;
46
+ const emit = (next) => onValueChange(normalizeMatrix(next, value, categories, channels));
47
+ const set = (category, channel, on) => emit({ ...value, [category]: { ...value[category], [channel]: on } });
48
+ return /* @__PURE__ */ jsxs("div", { className: s.root({ className }), role: "group", "aria-label": label, children: [
49
+ presets && presets.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
50
+ /* @__PURE__ */ jsx(Chip.Group, { type: "single", required: true, label: presetsLabel ?? label, value: inForce ?? "", onValueChange: (id) => {
51
+ const p = presets.find((x) => x.id === id);
52
+ if (p) emit(p.value);
53
+ }, children: presets.map((p) => /* @__PURE__ */ jsx(Chip, { value: p.id, children: p.label }, p.id)) }),
54
+ /* @__PURE__ */ jsx("p", { className: s.hint({ className: "mt-2" }), children: inForce ? presets.find((p) => p.id === inForce)?.hint : customHint })
55
+ ] }),
56
+ /* @__PURE__ */ jsxs("table", { className: s.table(), children: [
57
+ /* @__PURE__ */ jsx("thead", { className: s.head(), children: /* @__PURE__ */ jsxs("tr", { children: [
58
+ /* @__PURE__ */ jsx("td", { className: s.cornerCell() }),
59
+ channels.map((ch) => /* @__PURE__ */ jsx("th", { scope: "col", className: s.channelCell(), children: ch.label }, ch.id))
60
+ ] }) }),
61
+ /* @__PURE__ */ jsx("tbody", { children: categories.map((c) => /* @__PURE__ */ jsxs("tr", { className: s.row(), children: [
62
+ /* @__PURE__ */ jsxs("th", { scope: "row", className: s.category(), children: [
63
+ /* @__PURE__ */ jsx("span", { className: s.name(), children: c.label }),
64
+ (c.locked ? c.lockedNote : c.description) && /* @__PURE__ */ jsx("span", { className: s.note(), children: c.locked ? c.lockedNote : c.description })
65
+ ] }),
66
+ channels.map((ch) => /* @__PURE__ */ jsx("td", { className: s.cell(), children: uses(c, ch.id) ? /* @__PURE__ */ jsx(Switch, { label: `${c.label} \u2014 ${ch.label}`, checked: c.locked || Boolean(value[c.id]?.[ch.id]), disabled: c.locked || ch.disabled, onCheckedChange: (on) => set(c.id, ch.id, on) }) : /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: s.note(), children: "\u2013" }) }, ch.id))
67
+ ] }, c.id)) })
68
+ ] })
69
+ ] });
70
+ }
71
+ export {
72
+ NotificationPreferences,
73
+ normalizeMatrix,
74
+ notificationPreferences,
75
+ presetInForce
76
+ };
77
+ //# sourceMappingURL=notification-preferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/notification-preferences/notification-preferences.tsx"],"sourcesContent":["\"use client\";\n// Client (switches and chips). What reaches a person: categories down, channels across, a switch at each crossing, and\n// presets that set the whole matrix at once. The value is controlled and plain data; the words are props.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { Chip } from \"../chip\";\nimport { Switch } from \"../switch\";\n\nexport const notificationPreferences = tv({\n slots: {\n root: \"flex flex-col gap-3\",\n hint: \"text-xs text-fg-secondary\",\n table: \"w-full overflow-hidden rounded-2xl border border-border-default text-left\",\n head: \"bg-surface-2 text-xs font-semibold text-fg-secondary\",\n channelCell: \"w-16 px-2 py-2.5 text-center sm:w-24\",\n cornerCell: \"px-4 py-2.5\",\n row: \"border-t border-border-subtle\",\n category: \"px-4 py-3 text-left font-normal\",\n name: \"block text-sm font-semibold text-fg\",\n note: \"block text-xs text-fg-secondary\",\n cell: \"px-2 py-3 text-center\",\n },\n});\n\n/** Category id → channel id → on. A missing entry is off; a crossing a category does not use (see `channels`) is never written. */\nexport type NotificationMatrix = Record<string, Record<string, boolean>>;\n\nexport type NotificationChannel = {\n /** Its key in the matrix (`app`, `email`). */\n id: string;\n /** The column's name (`In the app`, `By e-mail`). */\n label: string;\n /** The whole column is inert (e-mail is off for the account). */\n disabled?: boolean;\n};\n\nexport type NotificationCategory = {\n /** Its key in the matrix (`social`, `security`). */\n id: string;\n /** The row's name. */\n label: string;\n /** What these notifications are, one line. */\n description?: string;\n /** The channels this category can use (ids); left out, every channel. Other crossings show no switch. */\n channels?: readonly string[];\n /** Always on, and shown so (security): the switches are inert and `lockedNote` replaces the description. */\n locked?: boolean;\n lockedNote?: string;\n};\n\nexport type NotificationPreset = {\n /** Its key (`everything`, `essentials`). */\n id: string;\n /** The chip's words. */\n label: string;\n /** What the preset does, one sentence, shown while it is the one in force. */\n hint: string;\n /** The matrix it sets (locked categories stay on and inert channels keep their value, whatever it says). */\n value: NotificationMatrix;\n};\n\nexport type NotificationPreferencesProps = {\n /** The group's accessible name (`Notification settings`). */\n label: string;\n /** The columns: where a notification can go. */\n channels: readonly NotificationChannel[];\n /** The rows: what can be sent. */\n categories: readonly NotificationCategory[];\n /** What is on, by category then channel (controlled). */\n value: NotificationMatrix;\n /** Called with the whole matrix after a switch or a preset — normalised: locked rows on, inert channels unchanged, unused crossings absent. */\n onValueChange: (next: NotificationMatrix) => void;\n /** Quick settings above the matrix (`Everything`, `Essentials`, `Nothing`). */\n presets?: readonly NotificationPreset[];\n /** The presets' own accessible name (`Presets`). Required with `presets`. */\n presetsLabel?: string;\n /** Said under the presets when the matrix matches none (`Custom`). */\n customHint?: string;\n /** Classes merged on the root. */\n className?: string;\n};\n\nconst uses = (c: NotificationCategory, channel: string) => !c.channels || c.channels.includes(channel);\n\n// Only what a preset can change counts: not the locked rows, the inert channels, or the crossings a category does not use.\nconst same = (a: NotificationMatrix, b: NotificationMatrix, categories: readonly NotificationCategory[], channels: readonly NotificationChannel[]) =>\n categories.every((c) => c.locked || channels.every((ch) => ch.disabled || !uses(c, ch.id) || Boolean(a[c.id]?.[ch.id]) === Boolean(b[c.id]?.[ch.id])));\n\n/** The preset in force, or null for a custom matrix. */\nexport function presetInForce(value: NotificationMatrix, presets: readonly NotificationPreset[], categories: readonly NotificationCategory[], channels: readonly NotificationChannel[]): string | null {\n return presets.find((p) => same(value, p.value, categories, channels))?.id ?? null;\n}\n\n/**\n * The matrix the controls can show: every crossing a category uses, locked rows on, an inert channel keeping its\n * `current` value whatever `next` says, and nothing for the crossings a category does not use.\n */\nexport function normalizeMatrix(next: NotificationMatrix, current: NotificationMatrix, categories: readonly NotificationCategory[], channels: readonly NotificationChannel[]): NotificationMatrix {\n return Object.fromEntries(\n categories.map((c) => [\n c.id,\n Object.fromEntries(\n channels.filter((ch) => uses(c, ch.id)).map((ch) => [ch.id, c.locked ? true : Boolean((ch.disabled ? current : next)[c.id]?.[ch.id])]),\n ),\n ]),\n );\n}\n\nexport function NotificationPreferences({ label, channels, categories, value, onValueChange, presets, presetsLabel, customHint, className }: NotificationPreferencesProps) {\n const s = notificationPreferences();\n const inForce = presets ? presetInForce(value, presets, categories, channels) : null;\n const emit = (next: NotificationMatrix) => onValueChange(normalizeMatrix(next, value, categories, channels));\n const set = (category: string, channel: string, on: boolean) => emit({ ...value, [category]: { ...value[category], [channel]: on } });\n return (\n <div className={s.root({ className })} role=\"group\" aria-label={label}>\n {presets && presets.length > 0 && (\n <div>\n <Chip.Group type=\"single\" required label={presetsLabel ?? label} value={inForce ?? \"\"} onValueChange={(id) => { const p = presets.find((x) => x.id === id); if (p) emit(p.value); }}>\n {presets.map((p) => (\n <Chip key={p.id} value={p.id}>\n {p.label}\n </Chip>\n ))}\n </Chip.Group>\n <p className={s.hint({ className: \"mt-2\" })}>{inForce ? presets.find((p) => p.id === inForce)?.hint : customHint}</p>\n </div>\n )}\n <table className={s.table()}>\n <thead className={s.head()}>\n <tr>\n <td className={s.cornerCell()} />\n {channels.map((ch) => (\n <th key={ch.id} scope=\"col\" className={s.channelCell()}>\n {ch.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {categories.map((c) => (\n <tr key={c.id} className={s.row()}>\n <th scope=\"row\" className={s.category()}>\n <span className={s.name()}>{c.label}</span>\n {(c.locked ? c.lockedNote : c.description) && <span className={s.note()}>{c.locked ? c.lockedNote : c.description}</span>}\n </th>\n {channels.map((ch) => (\n <td key={ch.id} className={s.cell()}>\n {uses(c, ch.id) ? (\n <Switch label={`${c.label} — ${ch.label}`} checked={c.locked || Boolean(value[c.id]?.[ch.id])} disabled={c.locked || ch.disabled} onCheckedChange={(on) => set(c.id, ch.id, on)} />\n ) : (\n <span aria-hidden className={s.note()}>\n –\n </span>\n )}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -7,7 +7,7 @@ var pageHeader = tv({
7
7
  breadcrumb: "text-xs text-fg-secondary",
8
8
  row: "flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between",
9
9
  text: "flex min-w-0 flex-col gap-1.5",
10
- title: "font-display text-2xl font-black tracking-tight text-fg sm:text-3xl",
10
+ title: "kz-page-title font-display text-2xl font-black tracking-tight text-fg sm:text-3xl",
11
11
  description: "max-w-2xl text-sm text-fg-secondary",
12
12
  actions: "flex shrink-0 flex-wrap items-center gap-2"
13
13
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/page-header/page-header.tsx"],"sourcesContent":["// Server-safe. The top of a page: an optional breadcrumb, the title (h1), a description and the page's actions.\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const pageHeader = tv({\n slots: {\n root: \"flex flex-col gap-3 border-b border-border-subtle pb-6\",\n breadcrumb: \"text-xs text-fg-secondary\",\n row: \"flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between\",\n text: \"flex min-w-0 flex-col gap-1.5\",\n title: \"font-display text-2xl font-black tracking-tight text-fg sm:text-3xl\",\n description: \"max-w-2xl text-sm text-fg-secondary\",\n actions: \"flex shrink-0 flex-wrap items-center gap-2\",\n },\n});\nconst s = pageHeader();\n\nexport type PageHeaderProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The title of the page (an `h1`, or `as=\"h2\"`). */\n title: React.ReactNode;\n /** A sentence under the title. */\n description?: React.ReactNode;\n /** The page's actions: Buttons, a DropdownMenu. */\n actions?: React.ReactNode;\n /** A breadcrumb (the product's own <nav aria-label>), shown above the title. */\n breadcrumb?: React.ReactNode;\n /** The heading level of the title: `h1` for a page, `h2` for a section that looks like one. */\n as?: \"h1\" | \"h2\";\n};\n\nexport function PageHeader({ title, description, actions, breadcrumb, as: Heading = \"h1\", className, ...props }: PageHeaderProps) {\n return (\n <div className={s.root({ className })} {...props}>\n {breadcrumb && <div className={s.breadcrumb()}>{breadcrumb}</div>}\n <div className={s.row()}>\n <div className={s.text()}>\n <Heading className={s.title()}>{title}</Heading>\n {description && <p className={s.description()}>{description}</p>}\n </div>\n {actions && <div className={s.actions()}>{actions}</div>}\n </div>\n </div>\n );\n}\n"],"mappings":";AAEA,SAAS,UAAU;AA+BE,cAEb,YAFa;AA7Bd,IAAM,aAAa,GAAG;AAAA,EAC3B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AACF,CAAC;AACD,IAAM,IAAI,WAAW;AAed,SAAS,WAAW,EAAE,OAAO,aAAa,SAAS,YAAY,IAAI,UAAU,MAAM,WAAW,GAAG,MAAM,GAAoB;AAChI,SACE,qBAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACxC;AAAA,kBAAc,oBAAC,SAAI,WAAW,EAAE,WAAW,GAAI,sBAAW;AAAA,IAC3D,qBAAC,SAAI,WAAW,EAAE,IAAI,GACpB;AAAA,2BAAC,SAAI,WAAW,EAAE,KAAK,GACrB;AAAA,4BAAC,WAAQ,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,QACrC,eAAe,oBAAC,OAAE,WAAW,EAAE,YAAY,GAAI,uBAAY;AAAA,SAC9D;AAAA,MACC,WAAW,oBAAC,SAAI,WAAW,EAAE,QAAQ,GAAI,mBAAQ;AAAA,OACpD;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/page-header/page-header.tsx"],"sourcesContent":["// Server-safe. The top of a page: an optional breadcrumb, the title (h1), a description and the page's actions.\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const pageHeader = tv({\n slots: {\n root: \"flex flex-col gap-3 border-b border-border-subtle pb-6\",\n breadcrumb: \"text-xs text-fg-secondary\",\n row: \"flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between\",\n text: \"flex min-w-0 flex-col gap-1.5\",\n title: \"kz-page-title font-display text-2xl font-black tracking-tight text-fg sm:text-3xl\",\n description: \"max-w-2xl text-sm text-fg-secondary\",\n actions: \"flex shrink-0 flex-wrap items-center gap-2\",\n },\n});\nconst s = pageHeader();\n\nexport type PageHeaderProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The title of the page (an `h1`, or `as=\"h2\"`). */\n title: React.ReactNode;\n /** A sentence under the title. */\n description?: React.ReactNode;\n /** The page's actions: Buttons, a DropdownMenu. */\n actions?: React.ReactNode;\n /** A breadcrumb (the product's own <nav aria-label>), shown above the title. */\n breadcrumb?: React.ReactNode;\n /** The heading level of the title: `h1` for a page, `h2` for a section that looks like one. */\n as?: \"h1\" | \"h2\";\n};\n\nexport function PageHeader({ title, description, actions, breadcrumb, as: Heading = \"h1\", className, ...props }: PageHeaderProps) {\n return (\n <div className={s.root({ className })} {...props}>\n {breadcrumb && <div className={s.breadcrumb()}>{breadcrumb}</div>}\n <div className={s.row()}>\n <div className={s.text()}>\n <Heading className={s.title()}>{title}</Heading>\n {description && <p className={s.description()}>{description}</p>}\n </div>\n {actions && <div className={s.actions()}>{actions}</div>}\n </div>\n </div>\n );\n}\n"],"mappings":";AAEA,SAAS,UAAU;AA+BE,cAEb,YAFa;AA7Bd,IAAM,aAAa,GAAG;AAAA,EAC3B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,SAAS;AAAA,EACX;AACF,CAAC;AACD,IAAM,IAAI,WAAW;AAed,SAAS,WAAW,EAAE,OAAO,aAAa,SAAS,YAAY,IAAI,UAAU,MAAM,WAAW,GAAG,MAAM,GAAoB;AAChI,SACE,qBAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACxC;AAAA,kBAAc,oBAAC,SAAI,WAAW,EAAE,WAAW,GAAI,sBAAW;AAAA,IAC3D,qBAAC,SAAI,WAAW,EAAE,IAAI,GACpB;AAAA,2BAAC,SAAI,WAAW,EAAE,KAAK,GACrB;AAAA,4BAAC,WAAQ,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,QACrC,eAAe,oBAAC,OAAE,WAAW,EAAE,YAAY,GAAI,uBAAY;AAAA,SAC9D;AAAA,MACC,WAAW,oBAAC,SAAI,WAAW,EAAE,QAAQ,GAAI,mBAAQ;AAAA,OACpD;AAAA,KACF;AAEJ;","names":[]}
@@ -1,11 +1,16 @@
1
1
  "use client";
2
+ import {
3
+ warnDeprecated
4
+ } from "./chunk-BDIU5LZB.js";
2
5
 
3
6
  // src/pointer-light/pointer-light.tsx
4
7
  import { jsx } from "react/jsx-runtime";
5
8
  var POINTER_LIGHT_TARGET = "[data-kz-light]";
6
9
  function usePointerLight(_ref, _target = POINTER_LIGHT_TARGET) {
10
+ warnDeprecated("pointer-light", "3.31.0");
7
11
  }
8
12
  function PointerLight(_props) {
13
+ warnDeprecated("pointer-light", "3.31.0");
9
14
  return /* @__PURE__ */ jsx("span", { hidden: true });
10
15
  }
11
16
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/pointer-light/pointer-light.tsx"],"sourcesContent":["// Deprecated (krizaka-ui#393): the light that followed the pointer over the cards is retired — the family's hover is\n// quiet (a border and a surface step, no movement, no light). The exports stay so nothing breaks; they do nothing.\nimport type * as React from \"react\";\n\n/** @deprecated Since 3.31: no card carries it any more. */\nexport const POINTER_LIGHT_TARGET = \"[data-kz-light]\";\n\n/** @deprecated Since 3.31 (krizaka-ui#393): does nothing. Removed in 4.0. */\nexport function usePointerLight(_ref: React.RefObject<HTMLElement | null>, _target: string = POINTER_LIGHT_TARGET): void {}\n\nexport type PointerLightProps = {\n /**\n * Ignored.\n * @default \"[data-kz-light]\"\n */\n target?: string;\n};\n\n/** @deprecated Since 3.31 (krizaka-ui#393): renders an empty hidden span and nothing else. Remove it. Removed in 4.0. */\nexport function PointerLight(_props: PointerLightProps) {\n return <span hidden />;\n}\n"],"mappings":";;;AAoBS;AAfF,IAAM,uBAAuB;AAG7B,SAAS,gBAAgB,MAA2C,UAAkB,sBAA4B;AAAC;AAWnH,SAAS,aAAa,QAA2B;AACtD,SAAO,oBAAC,UAAK,QAAM,MAAC;AACtB;","names":[]}
1
+ {"version":3,"sources":["../src/pointer-light/pointer-light.tsx"],"sourcesContent":["// Deprecated (krizaka-ui#393): the light that followed the pointer over the cards is retired — the family's hover is\n// quiet (a border and a surface step, no movement, no light). The exports stay so nothing breaks; they do nothing.\nimport type * as React from \"react\";\n\nimport { warnDeprecated } from \"../deprecated\";\n\n/** @deprecated Since 3.31: no card carries it any more. */\nexport const POINTER_LIGHT_TARGET = \"[data-kz-light]\";\n\n/** @deprecated Since 3.31 (krizaka-ui#393): does nothing. Removed in 4.0. */\nexport function usePointerLight(_ref: React.RefObject<HTMLElement | null>, _target: string = POINTER_LIGHT_TARGET): void {\n warnDeprecated(\"pointer-light\", \"3.31.0\");\n}\n\nexport type PointerLightProps = {\n /**\n * Ignored.\n * @default \"[data-kz-light]\"\n */\n target?: string;\n};\n\n/** @deprecated Since 3.31 (krizaka-ui#393): renders an empty hidden span and nothing else. Remove it. Removed in 4.0. */\nexport function PointerLight(_props: PointerLightProps) {\n warnDeprecated(\"pointer-light\", \"3.31.0\");\n return <span hidden />;\n}\n"],"mappings":";;;;;;AAyBS;AAlBF,IAAM,uBAAuB;AAG7B,SAAS,gBAAgB,MAA2C,UAAkB,sBAA4B;AACvH,iBAAe,iBAAiB,QAAQ;AAC1C;AAWO,SAAS,aAAa,QAA2B;AACtD,iBAAe,iBAAiB,QAAQ;AACxC,SAAO,oBAAC,UAAK,QAAM,MAAC;AACtB;","names":[]}
@@ -77,7 +77,10 @@ type ProductPageProps = Omit<React.HTMLAttributes<HTMLElement>, "title"> & {
77
77
  /** The app's link component (Next's `Link`). */
78
78
  linkAs?: LinkComponent;
79
79
  };
80
- /** A product's overview: split hero, traps as compact cards, decisions with their cost, the bird's promise, closing call. */
80
+ /**
81
+ * A product's overview: split hero, traps as compact cards, decisions with their cost, the bird's promise, closing call.
82
+ * @deprecated Since 3.55 (ADR-006, krizaka-ui#674): no product uses it. Removed in 4.0.
83
+ */
81
84
  declare function ProductPage({ brand, mark, title, lead, facts, actions, visual, visualLabel, reasonsHeading, reasonLabels, reasons, decisions, promise, closing, linkAs, className, children, ...props }: ProductPageProps): React.JSX.Element;
82
85
 
83
86
  export { ProductPage, type ProductPageProps, type ProductReason };
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  cn
3
3
  } from "./chunk-KH3JOEPY.js";
4
+ import {
5
+ warnDeprecated
6
+ } from "./chunk-KGLRZMCY.js";
4
7
 
5
8
  // src/product-page/product-page.tsx
6
9
  import { ArgumentCard } from "@krizaka/ui/argument-card";
@@ -12,6 +15,7 @@ import { Facts, Page, Section } from "@krizaka/ui/page";
12
15
  import { SectionBackdrop } from "@krizaka/ui/section-backdrop";
13
16
  import { jsx, jsxs } from "react/jsx-runtime";
14
17
  function ProductPage({ brand, mark, title, lead, facts, actions, visual, visualLabel, reasonsHeading, reasonLabels, reasons, decisions, promise, closing, linkAs, className, children, ...props }) {
18
+ warnDeprecated("product-page");
15
19
  return /* @__PURE__ */ jsxs("div", { className: cn(brand && "brand-" + brand, className), ...props, children: [
16
20
  /* @__PURE__ */ jsx(SectionBackdrop, { as: "header", grid: true, className: "kz-hero", children: /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsxs("div", { className: visual ? "kz-tpl-split" : void 0, children: [
17
21
  /* @__PURE__ */ jsxs("div", { className: "kz-hero-text", children: [