@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
@@ -2,8 +2,8 @@
2
2
  "name": "profile-card",
3
3
  "type": "primitive",
4
4
  "title": "Profile card",
5
- "summary": "A profile at a glance — a portrait, a name, a headline gauge, a few stats with their values in words, a line and actions: a creator, a match, a member, a plan.",
6
- "description": "A profile at a glance — a portrait, a name, a headline gauge, a few stats with their values in words, a line and actions: a creator, a match, a member, a plan.",
5
+ "summary": "A profile at a glance — a portrait, a name, a headline gauge, a few stats with their values in words, a line and actions: a creator, a match, a member, a plan. `ProfileBanner` is the top of a person's or a place's page: a cover, the avatar overlapping it, the name, its facts, the actions.",
6
+ "description": "A profile at a glance — a portrait, a name, a headline gauge, a few stats with their values in words, a line and actions: a creator, a match, a member, a plan. `ProfileBanner` is the top of a person's or a place's page: a cover, the avatar overlapping it, the name, its facts, the actions.",
7
7
  "status": "beta",
8
8
  "deprecated": null,
9
9
  "category": "data-display",
@@ -22,6 +22,7 @@
22
22
  "whenToUse": [
23
23
  "A creator's card in a directory or beside their content (profile completeness, challenges met, response time).",
24
24
  "A match in a dating app: what two people share, said in words.",
25
+ "`ProfileBanner`: the top of a client's, a shop's, a creator's or a building's page — or `DetailLayout` with `cover`, the same banner as its header.",
25
26
  "A team member, a product, a plan presented with a few measured strengths — and, on a told page, a character (`variant=\"arcade\"`)."
26
27
  ],
27
28
  "whenNotToUse": [
@@ -42,6 +43,7 @@
42
43
  "Two to four stats, each with `valueText` in the person's words (“12 of 15”, “replies within a day”): a bar alone says nothing.",
43
44
  "Never reduce a person to a score: in a dating or social product, show what is shared, not a ranking.",
44
45
  "One or two actions under the card, the main one first.",
46
+ "`ProfileBanner`: give it the family's default avatar (`defaultAvatar: { brand, seed }`) when there is no photo, never initials on grey; the cover is decorative (`alt=\"\"`), a tint of the brand's accent by default; one or two actions.",
45
47
  "`nameAs` follows the page's outline: `h3` in a list under an `h2`, `p` when a heading follows the card."
46
48
  ],
47
49
  "accessibility": {
@@ -49,6 +51,7 @@
49
51
  "notes": [
50
52
  "An `article` headed by the name; each gauge is a `meter` named by its label, with `aria-valuetext`.",
51
53
  "The portrait is decorative: the name carries the meaning.",
54
+ "`ProfileBanner` is a `section` headed by the name (`h1` by default, `titleAs`); no word is ever drawn on the cover, so a photo never costs the text its contrast, and a scrim fades the photo into the page.",
52
55
  "In a stage, the card arrives and its gauges fill once; under `prefers-reduced-motion` they are drawn full at once."
53
56
  ]
54
57
  },
@@ -60,8 +63,77 @@
60
63
  ],
61
64
  "web": {
62
65
  "entry": "@krizaka/ui/profile-card",
63
- "import": "import { ProfileCard, StatGauge } from \"@krizaka/ui/profile-card\";",
66
+ "import": "import { ProfileCard, ProfileBanner, StatGauge } from \"@krizaka/ui/profile-card\";",
64
67
  "props": [
68
+ {
69
+ "component": "ProfileBanner",
70
+ "description": "A person's or a place's banner: cover, overlapping avatar, eyebrow, name (h1), facts and actions — the words never on the cover.",
71
+ "props": [
72
+ {
73
+ "name": "avatar",
74
+ "type": "ReactNode",
75
+ "default": null,
76
+ "description": "The avatar overlapping the cover: `Avatar` with the family's default (`defaultAvatar: { brand, seed }`, #598) when there is no photo.",
77
+ "required": true
78
+ },
79
+ {
80
+ "name": "title",
81
+ "type": "ReactNode",
82
+ "default": null,
83
+ "description": "The name: the page's heading.",
84
+ "required": true
85
+ },
86
+ {
87
+ "name": "actions",
88
+ "type": "ReactNode",
89
+ "default": null,
90
+ "description": "The actions (message, book, edit): at the right from `sm`, under the name on a phone.",
91
+ "required": false
92
+ },
93
+ {
94
+ "name": "banner",
95
+ "type": "ReactNode",
96
+ "default": null,
97
+ "description": "The cover: an `<img alt=\"\">` (decorative) or your framework's image. Absent: a tint of the brand's accent.",
98
+ "required": false
99
+ },
100
+ {
101
+ "name": "brand",
102
+ "type": "string",
103
+ "default": null,
104
+ "description": "A brand scope (`akinaza` → `.brand-akinaza`): the default cover takes that brand's accent.",
105
+ "required": false
106
+ },
107
+ {
108
+ "name": "eyebrow",
109
+ "type": "ReactNode",
110
+ "default": null,
111
+ "description": "A mono line above the name: what it is (« Client », « Shop »), an id.",
112
+ "required": false
113
+ },
114
+ {
115
+ "name": "meta",
116
+ "type": "ReactNode",
117
+ "default": null,
118
+ "description": "Under the name: its facts (a handle, a city, « client since 2024 »).",
119
+ "required": false
120
+ },
121
+ {
122
+ "name": "status",
123
+ "type": "ReactNode",
124
+ "default": null,
125
+ "description": "Beside the name: a status (`Badge`), a verified mark.",
126
+ "required": false
127
+ },
128
+ {
129
+ "name": "titleAs",
130
+ "type": "\"h1\" | \"h2\"",
131
+ "default": "h1",
132
+ "description": "The level of the name.",
133
+ "required": false
134
+ }
135
+ ]
136
+ },
65
137
  {
66
138
  "component": "ProfileCard",
67
139
  "description": "A profile at a glance: portrait, name, a headline gauge, stats with their values in words, a line and actions.",
@@ -225,6 +297,14 @@
225
297
  "module": "@krizaka/ui/registry/examples/profile-card/match",
226
298
  "code": "import { Avatar } from \"@krizaka/ui/avatar\";\nimport { ProfileCard } from \"@krizaka/ui/profile-card\";\n\n// A match in a dating app: what you share, in words — never a score alone.\nexport default function ProfileCardMatch() {\n return (\n <ProfileCard\n brand=\"yasakia\"\n visual={<Avatar src=\"https://krizaka-assets.b-cdn.net/site/people/ui/camille-256.dc2943029a.webp\" alt=\"Camille Roy\" fallback=\"CR\" size=\"xl\" />}\n visualSize={88}\n name=\"Camille, 29\"\n stats={[\n { label: \"Interests in common\", value: 4, max: 6, valueText: \"4 of 6\" },\n { label: \"Answers that match\", value: 7, max: 10, valueText: \"7 of 10\" },\n ]}\n caption=\"You both answered “a slow Sunday market” first.\"\n />\n );\n}\n"
227
299
  },
300
+ {
301
+ "name": "banner",
302
+ "title": "Profile banner",
303
+ "description": "A client's page: the brand's tinted cover, the family's default avatar overlapping it, the name, a status, its facts and two actions.",
304
+ "path": "examples/profile-card/banner.tsx",
305
+ "module": "@krizaka/ui/registry/examples/profile-card/banner",
306
+ "code": "import { Avatar } from \"@krizaka/ui/avatar\";\nimport { Badge } from \"@krizaka/ui/badge\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { ProfileBanner } from \"@krizaka/ui/profile-card\";\n\n// A client's page: the brand's tinted cover, the family's default avatar overlapping it, the name (h1), its facts, the actions.\nexport default function ProfileCardBanner() {\n return (\n <ProfileBanner\n brand=\"akinaza\"\n avatar={<Avatar defaultAvatar={{ brand: \"akinaza\", seed: \"eric\" }} alt=\"\" fallback=\"E\" size=\"xl\" />}\n eyebrow=\"Client\"\n title=\"Eric Tremblay\"\n status={<Badge tone=\"success\" size=\"sm\">Regular</Badge>}\n meta=\"Client since 2024 · 14 visits\"\n actions={\n <>\n <Button size=\"sm\" variant=\"primary\">Book</Button>\n <Button size=\"sm\">Message</Button>\n </>\n }\n />\n );\n}\n"
307
+ },
228
308
  {
229
309
  "name": "arcade",
230
310
  "title": "Arcade flavour",
@@ -237,12 +317,14 @@
237
317
  },
238
318
  "native": {
239
319
  "entry": "@krizaka/ui/native",
240
- "import": "import { ProfileCard } from \"@krizaka/ui/native\";",
320
+ "import": "import { ProfileCard, ProfileBanner } from \"@krizaka/ui/native\";",
241
321
  "differences": [
242
322
  "`name` and `caption` are strings; no `nameAs`, no `icon`.",
323
+ "`ProfileBanner`: `title`, `eyebrow` and `meta` are strings; the cover is an `Image` or a tint of the brand's accent.",
243
324
  "One look: no arcade flavour on mobile.",
244
325
  "The gauges fill once on mount (`animated`), not on scroll."
245
326
  ],
327
+ "deprecated": null,
246
328
  "props": [
247
329
  {
248
330
  "component": "ProfileCard",
@@ -312,6 +394,61 @@
312
394
  "required": false
313
395
  }
314
396
  ]
397
+ },
398
+ {
399
+ "component": "ProfileBanner",
400
+ "description": "The top of a person's or a place's screen — the web's `ProfileBanner`: a slim cover, the avatar overlapping its lower\nedge, then the name (the screen's heading), its facts and the actions. No text on the cover.",
401
+ "props": [
402
+ {
403
+ "name": "avatar",
404
+ "type": "ReactNode",
405
+ "default": null,
406
+ "description": "The avatar overlapping the cover (`Avatar` with the family's default).",
407
+ "required": true
408
+ },
409
+ {
410
+ "name": "title",
411
+ "type": "string",
412
+ "default": null,
413
+ "description": "The name: the screen's heading.",
414
+ "required": true
415
+ },
416
+ {
417
+ "name": "actions",
418
+ "type": "ReactNode",
419
+ "default": null,
420
+ "description": "The actions, under the name.",
421
+ "required": false
422
+ },
423
+ {
424
+ "name": "banner",
425
+ "type": "ReactNode",
426
+ "default": null,
427
+ "description": "The cover: an `Image` (decorative). Absent: a tint of the brand's accent.",
428
+ "required": false
429
+ },
430
+ {
431
+ "name": "eyebrow",
432
+ "type": "string",
433
+ "default": null,
434
+ "description": "A line above the name: what it is (« Client »).",
435
+ "required": false
436
+ },
437
+ {
438
+ "name": "meta",
439
+ "type": "string",
440
+ "default": null,
441
+ "description": "Under the name: its facts.",
442
+ "required": false
443
+ },
444
+ {
445
+ "name": "status",
446
+ "type": "ReactNode",
447
+ "default": null,
448
+ "description": "Beside the name: a `Badge`.",
449
+ "required": false
450
+ }
451
+ ]
315
452
  }
316
453
  ],
317
454
  "examples": [
@@ -326,21 +463,37 @@
326
463
  "dark": "examples/profile-card/native/default.dark.png",
327
464
  "light": "examples/profile-card/native/default.light.png"
328
465
  }
466
+ },
467
+ {
468
+ "name": "banner",
469
+ "title": "Profile banner",
470
+ "description": "A client's screen: the brand's tinted cover, the avatar over its edge, the name, its facts, one action.",
471
+ "path": "examples/profile-card/native/banner.tsx",
472
+ "module": "@krizaka/ui/registry/examples/profile-card/native/banner",
473
+ "code": "import { Avatar, Badge, Button, ProfileBanner } from \"@krizaka/ui/native\";\nimport { View } from \"react-native\";\n\n// A client's screen on a phone: the brand's cover, the avatar over its edge, the name, its facts, the actions.\nexport default function NativeProfileCardBanner() {\n return (\n <View style={{ width: 340 }}>\n <ProfileBanner\n avatar={<Avatar defaultAvatar={{ brand: \"akinaza\", seed: \"eric\" }} fallback=\"E\" size=\"xl\" />}\n eyebrow=\"Client\"\n title=\"Eric Tremblay\"\n status={<Badge tone=\"success\">Regular</Badge>}\n meta=\"Client since 2024 · 14 visits\"\n actions={<Button variant=\"primary\" size=\"sm\" label=\"Book\" />}\n />\n </View>\n );\n}\n",
474
+ "screenshots": {
475
+ "dark": "examples/profile-card/native/banner.dark.png",
476
+ "light": "examples/profile-card/native/banner.light.png"
477
+ }
329
478
  }
330
479
  ]
331
480
  },
332
481
  "files": [
333
482
  {
334
483
  "path": "meta.ts",
335
- "content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which ui.krizaka.com (apps/site) renders as\n// ui.krizaka.com/components/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"agenda\"\n | \"account-settings\"\n | \"drop-overlay\"\n | \"upload-queue\"\n | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"taped-photo\"\n | \"text-style\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\n | \"chapter\"\n | \"specimen-tag\"\n | \"action-bar\"\n | \"action-sheet\"\n | \"activity-feed\"\n | \"alert\"\n | \"app-header\"\n | \"app-shell\"\n | \"argument-card\"\n | \"audio-player\"\n | \"auth-layout\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"captcha\"\n | \"card\"\n | \"card-grid\"\n | \"catalogue-page\"\n | \"changelog-page\"\n | \"chat\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"chip-row\"\n | \"choice-grid\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"comparison-table\"\n | \"command\"\n | \"component-page\"\n | \"confirm-button\"\n | \"contact-page\"\n | \"continue-prompt\"\n | \"countdown\"\n | \"cover-hero\"\n | \"cta-panel\"\n | \"dashboard-layout\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"description-list\"\n | \"detail-layout\"\n | \"dialog\"\n | \"docs-article-page\"\n | \"docs-hub-page\"\n | \"docs-layout\"\n | \"docs-nav\"\n | \"document-viewer\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"engine-flow\"\n | \"error-page\"\n | \"fab\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"force-update-screen\"\n | \"form\"\n | \"gallery-page\"\n | \"genui\"\n | \"glossary\"\n | \"glossary-term\"\n | \"glow-card\"\n | \"goal-gauge\"\n | \"header\"\n | \"how-it-works-page\"\n | \"image-cropper\"\n | \"image-viewer\"\n | \"iso\"\n | \"kanban\"\n | \"kbd\"\n | \"kpi-explained\"\n | \"landing-page\"\n | \"landscape\"\n | \"legal-page\"\n | \"link-card\"\n | \"list\"\n | \"loader\"\n | \"longform-page\"\n | \"maintenance-screen\"\n | \"map\"\n | \"markdown\"\n | \"meta-row\"\n | \"waveform\"\n | \"marketing-layout\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascot-state\"\n | \"mascots\"\n | \"match-dialog\"\n | \"media-capture\"\n | \"media-grid\"\n | \"language-switch\"\n | \"media-gallery\"\n | \"media-picker\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"onboarding\"\n | \"opening-hours\"\n | \"otp-input\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"permission-prompt\"\n | \"photo-grid\"\n | \"pointer-light\"\n | \"popover\"\n | \"pricing-page\"\n | \"product-page\"\n | \"profile-card\"\n | \"progress\"\n | \"promise-card\"\n | \"pull-to-refresh\"\n | \"radio-group\"\n | \"router\"\n | \"rail-nav\"\n | \"recipes\"\n | \"screen\"\n | \"scroll-stage\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"service-card\"\n | \"settings-layout\"\n | \"account-menu\"\n | \"showcase\"\n | \"step-showcase\"\n | \"site-footer\"\n | \"sites\"\n | \"skeleton\"\n | \"skip-link\"\n | \"slider\"\n | \"slot-picker\"\n | \"slot\"\n | \"spinner\"\n | \"sticky-action\"\n | \"splash-handoff\"\n | \"split-view\"\n | \"stage-banner\"\n | \"stat\"\n | \"status-page\"\n | \"step-progress\"\n | \"stepper\"\n | \"swipe-deck\"\n | \"swipeable-row\"\n | \"switch\"\n | \"tab-bar\"\n | \"tabs\"\n | \"tag-input\"\n | \"tag-selector\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"tree-view\"\n | \"txt\"\n | \"update-prompt\"\n | \"verified-badge\"\n | \"vertical-video\"\n | \"video-player\"\n | \"video-trimmer\"\n | \"virtual\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/**\n * Why a component is not on a platform — a decision, never a silence (the parity matrix of ui.krizaka.com/platforms):\n * - `gap` (✗): it belongs there and is not built yet; `issue` is the issue that tracks it (`krizaka/krizaka-ui#275`);\n * - `n/a`: it is not meant for that platform (a site's page block on a phone, a swipe on a desktop); `use` names the\n * component that answers there, when one does.\n */\nexport type Absence =\n | { readonly status: \"gap\"; readonly issue: string; readonly reason: string; readonly use?: undefined }\n | { readonly status: \"n/a\"; readonly reason: string; readonly use?: ComponentName; readonly issue?: undefined };\n\n/**\n * Desktop is the Orazaka Mac app (Tauri 2: the system WebView renders the web components — ADR-002). `web`: the web\n * component runs there as it is; `desktop`: it also has a desktop form (a window's title bar, a denser layout…), said in\n * its documentation; otherwise the absence and why.\n */\nexport type DesktopSupport = \"web\" | \"desktop\" | Absence;\n\n/**\n * The three platforms of Krizaka UI — web · native (React Native, Expo) · desktop — for one component. The side a\n * component has is `platforms`; the side it lacks says why here: `native` is required for (and only for) a web-only\n * component, `web` for a native-only one; `desktop` always. `scripts/registry.test.mjs` fails on a missing decision.\n */\nexport interface Parity {\n readonly web?: Absence;\n readonly native?: Absence;\n readonly desktop: DesktopSupport;\n}\n\n/**\n * `stable`: its API only changes in a major. `beta`: it may still change in a minor. `deprecated`: no product uses it and\n * no work plans to — it still works, says what replaces it, and goes in the major named by `deprecated.removedIn`.\n */\nexport type Status = \"stable\" | \"beta\" | \"deprecated\";\n\n/** What a deprecated component says (required when `status` is `deprecated`, absent otherwise). */\nexport interface Deprecation {\n /** The version that deprecated it (`3.6.0`). */\n readonly since: string;\n /** The major that removes it (`4.0.0`). */\n readonly removedIn: string;\n /** What replaces it, when a component does. */\n readonly use?: ComponentName;\n /** Why it goes: no product uses it, no planned work needs it. */\n readonly reason: string;\n}\n\n/**\n * The group of the catalogue. `media`: video, sound, camera, files, cropping. `blocks`: the page blocks — the frame,\n * the hero, sections, cards that lead or argue, decisions, code, calls to act — that every page of a site is made of.\n * `layouts`: the shells of whole screens — an application, a dashboard, settings, sign-in, an object, a list and its\n * item, a site's page, a documentation page — each with its screens. `templates`: the page templates — whole pages of a\n * site (a landing, a product, a docs hub, a long read, a changelog, pricing, status, an error…), each a distinct\n * composition of the blocks, words and content as props.\n */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layouts\" | \"templates\" | \"layout\" | \"foundations\";\n\n/** Why a reader needs a template: the seven intents the templates are grouped by (sidebar sub-headings, catalogue filter). */\nexport type TemplatePurpose = \"convince\" | \"explain\" | \"show\" | \"act\" | \"operate\" | \"converse\" | \"recover\";\n\n/** The groups of templates, in reading order: the title, and the one line that says when to come to that group. */\nexport const templatePurposes = {\n convince: { title: \"Convince\", useWhen: \"You come here when a visitor must decide: a landing, a product, a price, a comparison, a proof.\" },\n explain: { title: \"Explain\", useWhen: \"You come here when a reader must understand: how it works, a documentation hub or article, a changelog, a FAQ, a policy.\" },\n show: { title: \"Show\", useWhen: \"You come here when the work itself is the argument: a gallery, a story, a case study, an object and its details.\" },\n act: { title: \"Act\", useWhen: \"You come here when a person must do something once: reach the team, sign in or up, set up, pay.\" },\n operate: { title: \"Operate\", useWhen: \"You come here when a person works every day: a dashboard, a console with a table, settings, an app shell.\" },\n converse: { title: \"Converse\", useWhen: \"You come here when people talk: an inbox, a chat, comments, a notifications centre.\" },\n recover: { title: \"Recover\", useWhen: \"You come here when the way is blocked: an empty list, an error, a missing page, maintenance, a product still being built.\" },\n} as const satisfies Record<TemplatePurpose, { readonly title: string; readonly useWhen: string }>;\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\ninterface ExampleBase {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** A plain example, or a template: a whole screen with its intent (`purpose`) and the user goal its layout serves (`why`). */\nexport type Example =\n | (ExampleBase & { readonly template?: false; readonly purpose?: undefined; readonly why?: undefined })\n | (ExampleBase & {\n /**\n * A template: a whole screen of a product composed from the platform (a layout and its blocks, real words, its\n * phone version thought out), copied as a starting point — at most 160 lines, listed on ui.krizaka.com/templates.\n */\n readonly template: true;\n /** The intent that groups it: why you need this block. */\n readonly purpose: TemplatePurpose;\n /** Why this layout: the user goal it serves, in one sentence. */\n readonly why: string;\n });\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n /** Required for, and only for, a `deprecated` component. */\n readonly deprecated?: Deprecation;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** The platforms it is not on, and why; and its desktop form (see `Parity`). */\n readonly parity: Parity;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
484
+ "content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which ui.krizaka.com (apps/site) renders as\n// ui.krizaka.com/components/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"notification-preferences\"\n | \"quota-meter\"\n | \"agenda\"\n | \"account-settings\"\n | \"drop-overlay\"\n | \"upload-queue\"\n | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"taped-photo\"\n | \"stuck\"\n | \"doodle\"\n | \"signature\"\n | \"text-style\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\n | \"chapter\"\n | \"specimen-tag\"\n | \"action-bar\"\n | \"action-sheet\"\n | \"activity-feed\"\n | \"alert\"\n | \"app-header\"\n | \"app-shell\"\n | \"argument-card\"\n | \"audio-player\"\n | \"auth-layout\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"captcha\"\n | \"card\"\n | \"card-grid\"\n | \"catalogue-page\"\n | \"changelog-page\"\n | \"chat\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"chip-row\"\n | \"choice-grid\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"comparison-table\"\n | \"command\"\n | \"component-page\"\n | \"confirm-button\"\n | \"contact-page\"\n | \"continue-prompt\"\n | \"countdown\"\n | \"cover-hero\"\n | \"cta-panel\"\n | \"dashboard-layout\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"description-list\"\n | \"detail-layout\"\n | \"dialog\"\n | \"docs-article-page\"\n | \"docs-hub-page\"\n | \"docs-layout\"\n | \"docs-nav\"\n | \"document-viewer\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"engine-flow\"\n | \"error-page\"\n | \"fab\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"force-update-screen\"\n | \"form\"\n | \"gallery-page\"\n | \"genui\"\n | \"glossary\"\n | \"glossary-term\"\n | \"glow-card\"\n | \"goal-gauge\"\n | \"header\"\n | \"how-it-works-page\"\n | \"image-cropper\"\n | \"image-viewer\"\n | \"iso\"\n | \"kanban\"\n | \"kbd\"\n | \"kpi-explained\"\n | \"landing-page\"\n | \"landscape\"\n | \"legal-page\"\n | \"link-card\"\n | \"list\"\n | \"loader\"\n | \"longform-page\"\n | \"maintenance-screen\"\n | \"map\"\n | \"markdown\"\n | \"meta-row\"\n | \"waveform\"\n | \"marketing-layout\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascot-state\"\n | \"mascots\"\n | \"match-dialog\"\n | \"media-capture\"\n | \"media-grid\"\n | \"language-switch\"\n | \"media-gallery\"\n | \"media-picker\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"onboarding\"\n | \"opening-hours\"\n | \"otp-input\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"permission-prompt\"\n | \"photo-grid\"\n | \"pointer-light\"\n | \"popover\"\n | \"pricing-page\"\n | \"product-page\"\n | \"profile-card\"\n | \"progress\"\n | \"promise-card\"\n | \"pull-to-refresh\"\n | \"retro-tv\"\n | \"radio-group\"\n | \"router\"\n | \"rail-nav\"\n | \"recipes\"\n | \"screen\"\n | \"scroll-stage\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"service-card\"\n | \"settings-layout\"\n | \"account-menu\"\n | \"showcase\"\n | \"step-showcase\"\n | \"site-footer\"\n | \"sites\"\n | \"skeleton\"\n | \"skip-link\"\n | \"slider\"\n | \"slot-picker\"\n | \"slot\"\n | \"spinner\"\n | \"sticky-action\"\n | \"splash-handoff\"\n | \"split-view\"\n | \"stage-banner\"\n | \"stat\"\n | \"status-page\"\n | \"step-progress\"\n | \"stepper\"\n | \"swipe-deck\"\n | \"swipeable-row\"\n | \"switch\"\n | \"tab-bar\"\n | \"tabs\"\n | \"tag-input\"\n | \"tag-selector\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"tree-view\"\n | \"txt\"\n | \"update-prompt\"\n | \"verified-badge\"\n | \"vertical-video\"\n | \"video-player\"\n | \"video-trimmer\"\n | \"virtual\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/**\n * Why a component is not on a platform — a decision, never a silence (the parity matrix of ui.krizaka.com/platforms):\n * - `gap` (✗): it belongs there and is not built yet; `issue` is the issue that tracks it (`krizaka/krizaka-ui#275`);\n * - `n/a`: it is not meant for that platform (a site's page block on a phone, a swipe on a desktop); `use` names the\n * component that answers there, when one does.\n */\nexport type Absence =\n | { readonly status: \"gap\"; readonly issue: string; readonly reason: string; readonly use?: undefined }\n | { readonly status: \"n/a\"; readonly reason: string; readonly use?: ComponentName; readonly issue?: undefined };\n\n/**\n * Desktop is the Orazaka Mac app (Tauri 2: the system WebView renders the web components — ADR-002). `web`: the web\n * component runs there as it is; `desktop`: it also has a desktop form (a window's title bar, a denser layout…), said in\n * its documentation; otherwise the absence and why.\n */\nexport type DesktopSupport = \"web\" | \"desktop\" | Absence;\n\n/**\n * The three platforms of Krizaka UI — web · native (React Native, Expo) · desktop — for one component. The side a\n * component has is `platforms`; the side it lacks says why here: `native` is required for (and only for) a web-only\n * component, `web` for a native-only one; `desktop` always. `scripts/registry.test.mjs` fails on a missing decision.\n */\nexport interface Parity {\n readonly web?: Absence;\n readonly native?: Absence;\n readonly desktop: DesktopSupport;\n}\n\n/**\n * `stable`: its API only changes in a major. `beta`: it may still change in a minor. `deprecated`: no product uses it and\n * no work plans to — it still works, says what replaces it, and goes in the major named by `deprecated.removedIn`.\n */\nexport type Status = \"stable\" | \"beta\" | \"deprecated\";\n\n/** What a deprecated component says (required when `status` is `deprecated`, absent otherwise). */\nexport interface Deprecation {\n /** The version that deprecated it (`3.6.0`). */\n readonly since: string;\n /** The major that removes it (`4.0.0`). */\n readonly removedIn: string;\n /** What replaces it, when a component does. */\n readonly use?: ComponentName;\n /** Why it goes: no product uses it, no planned work needs it. */\n readonly reason: string;\n}\n\n/**\n * The group of the catalogue. `media`: video, sound, camera, files, cropping. `blocks`: the page blocks — the frame,\n * the hero, sections, cards that lead or argue, decisions, code, calls to act — that every page of a site is made of.\n * `layouts`: the shells of whole screens — an application, a dashboard, settings, sign-in, an object, a list and its\n * item, a site's page, a documentation page — each with its screens. `templates`: the page templates — whole pages of a\n * site (a landing, a product, a docs hub, a long read, a changelog, pricing, status, an error…), each a distinct\n * composition of the blocks, words and content as props.\n */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layouts\" | \"templates\" | \"layout\" | \"foundations\";\n\n/** Why a reader needs a template: the seven intents the templates are grouped by (sidebar sub-headings, catalogue filter). */\nexport type TemplatePurpose = \"convince\" | \"explain\" | \"show\" | \"act\" | \"operate\" | \"converse\" | \"recover\";\n\n/** The groups of templates, in reading order: the title, and the one line that says when to come to that group. */\nexport const templatePurposes = {\n convince: { title: \"Convince\", useWhen: \"You come here when a visitor must decide: a landing, a product, a price, a comparison, a proof.\" },\n explain: { title: \"Explain\", useWhen: \"You come here when a reader must understand: how it works, a documentation hub or article, a changelog, a FAQ, a policy.\" },\n show: { title: \"Show\", useWhen: \"You come here when the work itself is the argument: a gallery, a story, a case study, an object and its details.\" },\n act: { title: \"Act\", useWhen: \"You come here when a person must do something once: reach the team, sign in or up, set up, pay.\" },\n operate: { title: \"Operate\", useWhen: \"You come here when a person works every day: a dashboard, a console with a table, settings, an app shell.\" },\n converse: { title: \"Converse\", useWhen: \"You come here when people talk: an inbox, a chat, comments, a notifications centre.\" },\n recover: { title: \"Recover\", useWhen: \"You come here when the way is blocked: an empty list, an error, a missing page, maintenance, a product still being built.\" },\n} as const satisfies Record<TemplatePurpose, { readonly title: string; readonly useWhen: string }>;\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\ninterface ExampleBase {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** A plain example, or a template: a whole screen with its intent (`purpose`) and the user goal its layout serves (`why`). */\nexport type Example =\n | (ExampleBase & { readonly template?: false; readonly purpose?: undefined; readonly why?: undefined })\n | (ExampleBase & {\n /**\n * A template: a whole screen of a product composed from the platform (a layout and its blocks, real words, its\n * phone version thought out), copied as a starting point — at most 160 lines, listed on ui.krizaka.com/templates.\n */\n readonly template: true;\n /** The intent that groups it: why you need this block. */\n readonly purpose: TemplatePurpose;\n /** Why this layout: the user goal it serves, in one sentence. */\n readonly why: string;\n });\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n /** The React Native entry alone is deprecated while the web one stays (ADR-006 §7); a deprecated component says it once, above. */\n readonly deprecated?: Deprecation;\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n /** Required for, and only for, a `deprecated` component. */\n readonly deprecated?: Deprecation;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** The platforms it is not on, and why; and its desktop form (see `Parity`). */\n readonly parity: Parity;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
485
+ },
486
+ {
487
+ "path": "profile-card/banner.tsx",
488
+ "content": "// Server-safe: no hook. The top of a page about one person or place — a client, a shop, a creator, a building\n// (extracted from Orochia's ProfileHero, #650, #515): a slim cover, the avatar overlapping its lower edge, then the\n// eyebrow, the name (the page's h1), its facts and the actions. No text ever sits on the cover: the words are under it,\n// so a photo never costs their contrast (a scrim fades the photo's foot into the page all the same).\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { brandClass } from \"../story-variant\";\n\nexport const profileBanner = tv({\n slots: {\n root: \"relative flex w-full min-w-0 flex-col\",\n // The brand's accent, as a calm tint, when there is no picture; a picture fills it (`object-cover`).\n cover:\n \"relative h-28 w-full overflow-hidden rounded-xl bg-accent-soft bg-linear-to-br from-accent/30 via-accent-soft to-surface-2 sm:h-44 \" +\n \"[&>img]:block [&>img]:h-full [&>img]:w-full [&>img]:object-cover\",\n scrim: \"pointer-events-none absolute inset-0 bg-linear-to-t from-surface-0/70 via-transparent to-transparent\",\n body: \"relative flex min-w-0 flex-col gap-3 px-1 sm:flex-row sm:items-end sm:justify-between sm:px-2\",\n identity: \"flex min-w-0 items-end gap-4\",\n // The avatar overlaps the cover's lower edge by the same share at every width; the ring is the page's colour.\n avatar:\n \"relative -mt-10 h-20 w-20 shrink-0 overflow-hidden rounded-2xl bg-surface-3 ring-4 ring-surface-0 sm:-mt-14 sm:h-28 sm:w-28 \" +\n \"[&>*]:h-full! [&>*]:w-full! [&_img]:h-full [&_img]:w-full [&_img]:object-cover\",\n text: \"flex min-w-0 flex-1 flex-col gap-1 pb-1\",\n eyebrow: \"font-mono text-[11px] font-semibold text-fg-accent\",\n titleRow: \"flex min-w-0 flex-wrap items-center gap-2\",\n title: \"min-w-0 font-display text-xl font-extrabold tracking-tight break-words text-fg sm:text-3xl\",\n meta: \"flex flex-wrap items-center gap-x-3 gap-y-1 text-sm text-fg-secondary\",\n actions: \"flex shrink-0 flex-wrap items-center gap-2 sm:justify-end sm:pb-1\",\n },\n});\nconst s = profileBanner();\n\nexport type ProfileBannerProps = Omit<React.ComponentProps<\"section\">, \"title\"> & {\n /** The cover: an `<img alt=\"\">` (decorative) or your framework's image. Absent: a tint of the brand's accent. */\n banner?: React.ReactNode;\n /** The avatar overlapping the cover: `Avatar` with the family's default (`defaultAvatar: { brand, seed }`, #598) when there is no photo. */\n avatar: React.ReactNode;\n /** A mono line above the name: what it is (« Client », « Shop »), an id. */\n eyebrow?: React.ReactNode;\n /** The name: the page's heading. */\n title: React.ReactNode;\n /**\n * The level of the name.\n * @default \"h1\"\n */\n titleAs?: \"h1\" | \"h2\";\n /** Beside the name: a status (`Badge`), a verified mark. */\n status?: React.ReactNode;\n /** Under the name: its facts (a handle, a city, « client since 2024 »). */\n meta?: React.ReactNode;\n /** The actions (message, book, edit): at the right from `sm`, under the name on a phone. */\n actions?: React.ReactNode;\n /** A brand scope (`akinaza` → `.brand-akinaza`): the default cover takes that brand's accent. */\n brand?: string;\n};\n\n/** A person's or a place's banner: cover, overlapping avatar, eyebrow, name (h1), facts and actions — the words never on the cover. */\nexport function ProfileBanner({ banner, avatar, eyebrow, title, titleAs: Title = \"h1\", status, meta, actions, brand, className, ...props }: ProfileBannerProps) {\n return (\n <section className={s.root({ className: cn(brandClass(brand), className) })} {...props}>\n <div data-cover=\"\" className={s.cover()}>\n {banner}\n {banner ? <span aria-hidden className={s.scrim()} /> : null}\n </div>\n <div className={s.body()}>\n <div className={s.identity()}>\n <div data-avatar=\"\" className={s.avatar()}>\n {avatar}\n </div>\n <div className={s.text()}>\n {eyebrow && <p className={s.eyebrow()}>{eyebrow}</p>}\n <div className={s.titleRow()}>\n <Title className={s.title()}>{title}</Title>\n {status}\n </div>\n {meta && <div className={s.meta()}>{meta}</div>}\n </div>\n </div>\n {actions && <div className={s.actions()}>{actions}</div>}\n </div>\n </section>\n );\n}\n"
336
489
  },
337
490
  {
338
491
  "path": "profile-card/index.ts",
339
- "content": "/** @krizaka/ui/profile-card — `ProfileCard`, a profile at a glance, and `StatGauge`, one measured strength. Server-safe. Styles: story.css. */\nexport { ProfileCard, type ProfileCardProps, type ProfileStat } from \"./profile-card\";\nexport { StatGauge, type StatGaugeProps } from \"./stat-gauge\";\n"
492
+ "content": "/** @krizaka/ui/profile-card — `ProfileCard`, a profile at a glance, `ProfileBanner`, the top of a person's or a place's page (cover, overlapping avatar, name, actions), and `StatGauge`, one measured strength. Server-safe. Styles: story.css (the card). */\nexport { ProfileBanner, profileBanner, type ProfileBannerProps } from \"./banner\";\nexport { ProfileCard, type ProfileCardProps, type ProfileStat } from \"./profile-card\";\nexport { StatGauge, type StatGaugeProps } from \"./stat-gauge\";\n"
340
493
  },
341
494
  {
342
495
  "path": "profile-card/meta.ts",
343
- "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Profile card\",\n summary:\n \"A profile at a glance — a portrait, a name, a headline gauge, a few stats with their values in words, a line and actions: a creator, a match, a member, a plan.\",\n status: \"beta\",\n category: \"data-display\",\n platforms: \"both\",\n parity: { desktop: \"web\" },\n whenToUse: [\n \"A creator's card in a directory or beside their content (profile completeness, challenges met, response time).\",\n \"A match in a dating app: what two people share, said in words.\",\n \"A team member, a product, a plan presented with a few measured strengths — and, on a told page, a character (`variant=\\\"arcade\\\"`).\",\n ],\n whenNotToUse: [\n { when: \"A single figure with its trend.\", use: \"stat\" },\n { when: \"A usage against a limit with thresholds.\", use: \"meter\" },\n { when: \"A plain avatar and a name in a list row.\", use: \"avatar\" },\n ],\n bestPractices: [\n \"Two to four stats, each with `valueText` in the person's words (“12 of 15”, “replies within a day”): a bar alone says nothing.\",\n \"Never reduce a person to a score: in a dating or social product, show what is shared, not a ranking.\",\n \"One or two actions under the card, the main one first.\",\n \"`nameAs` follows the page's outline: `h3` in a list under an `h2`, `p` when a heading follows the card.\",\n ],\n accessibility: {\n keyboard: [],\n notes: [\n \"An `article` headed by the name; each gauge is a `meter` named by its label, with `aria-valuetext`.\",\n \"The portrait is decorative: the name carries the meaning.\",\n \"In a stage, the card arrives and its gauges fill once; under `prefers-reduced-motion` they are drawn full at once.\",\n ],\n },\n related: [\"avatar\", \"meter\", \"stat\", \"goal-gauge\"],\n web: {\n imports: [\"ProfileCard\", \"StatGauge\"],\n examples: [\n { name: \"creator\", title: \"A creator\", description: \"A creator's card: profile completeness, two stats in words, follow and message.\" },\n { name: \"match\", title: \"A match\", description: \"In a dating app's brand: what two people share, never a score alone.\" },\n { name: \"arcade\", title: \"Arcade flavour\", description: \"The fighter card of a told page: the brand's gradient, a breathing aura, a skewed gauge.\" },\n ],\n },\n native: {\n imports: [\"ProfileCard\"],\n differences: [\"`name` and `caption` are strings; no `nameAs`, no `icon`.\", \"One look: no arcade flavour on mobile.\", \"The gauges fill once on mount (`animated`), not on scroll.\"],\n examples: [{ name: \"default\", title: \"Default\", description: \"A creator's card on mobile: the headline gauge, two stats in words, one action.\" }],\n },\n} satisfies ComponentMeta;\n"
496
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Profile card\",\n summary:\n \"A profile at a glance — a portrait, a name, a headline gauge, a few stats with their values in words, a line and actions: a creator, a match, a member, a plan. `ProfileBanner` is the top of a person's or a place's page: a cover, the avatar overlapping it, the name, its facts, the actions.\",\n status: \"beta\",\n category: \"data-display\",\n platforms: \"both\",\n parity: { desktop: \"web\" },\n whenToUse: [\n \"A creator's card in a directory or beside their content (profile completeness, challenges met, response time).\",\n \"A match in a dating app: what two people share, said in words.\",\n \"`ProfileBanner`: the top of a client's, a shop's, a creator's or a building's page — or `DetailLayout` with `cover`, the same banner as its header.\",\n \"A team member, a product, a plan presented with a few measured strengths — and, on a told page, a character (`variant=\\\"arcade\\\"`).\",\n ],\n whenNotToUse: [\n { when: \"A single figure with its trend.\", use: \"stat\" },\n { when: \"A usage against a limit with thresholds.\", use: \"meter\" },\n { when: \"A plain avatar and a name in a list row.\", use: \"avatar\" },\n ],\n bestPractices: [\n \"Two to four stats, each with `valueText` in the person's words (“12 of 15”, “replies within a day”): a bar alone says nothing.\",\n \"Never reduce a person to a score: in a dating or social product, show what is shared, not a ranking.\",\n \"One or two actions under the card, the main one first.\",\n \"`ProfileBanner`: give it the family's default avatar (`defaultAvatar: { brand, seed }`) when there is no photo, never initials on grey; the cover is decorative (`alt=\\\"\\\"`), a tint of the brand's accent by default; one or two actions.\",\n \"`nameAs` follows the page's outline: `h3` in a list under an `h2`, `p` when a heading follows the card.\",\n ],\n accessibility: {\n keyboard: [],\n notes: [\n \"An `article` headed by the name; each gauge is a `meter` named by its label, with `aria-valuetext`.\",\n \"The portrait is decorative: the name carries the meaning.\",\n \"`ProfileBanner` is a `section` headed by the name (`h1` by default, `titleAs`); no word is ever drawn on the cover, so a photo never costs the text its contrast, and a scrim fades the photo into the page.\",\n \"In a stage, the card arrives and its gauges fill once; under `prefers-reduced-motion` they are drawn full at once.\",\n ],\n },\n related: [\"avatar\", \"meter\", \"stat\", \"goal-gauge\"],\n web: {\n imports: [\"ProfileCard\", \"ProfileBanner\", \"StatGauge\"],\n examples: [\n { name: \"creator\", title: \"A creator\", description: \"A creator's card: profile completeness, two stats in words, follow and message.\" },\n { name: \"match\", title: \"A match\", description: \"In a dating app's brand: what two people share, never a score alone.\" },\n { name: \"banner\", title: \"Profile banner\", description: \"A client's page: the brand's tinted cover, the family's default avatar overlapping it, the name, a status, its facts and two actions.\" },\n { name: \"arcade\", title: \"Arcade flavour\", description: \"The fighter card of a told page: the brand's gradient, a breathing aura, a skewed gauge.\" },\n ],\n },\n native: {\n imports: [\"ProfileCard\", \"ProfileBanner\"],\n differences: [\"`name` and `caption` are strings; no `nameAs`, no `icon`.\", \"`ProfileBanner`: `title`, `eyebrow` and `meta` are strings; the cover is an `Image` or a tint of the brand's accent.\", \"One look: no arcade flavour on mobile.\", \"The gauges fill once on mount (`animated`), not on scroll.\"],\n examples: [\n { name: \"default\", title: \"Default\", description: \"A creator's card on mobile: the headline gauge, two stats in words, one action.\" },\n { name: \"banner\", title: \"Profile banner\", description: \"A client's screen: the brand's tinted cover, the avatar over its edge, the name, its facts, one action.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
344
497
  },
345
498
  {
346
499
  "path": "profile-card/profile-card.tsx",
@@ -355,7 +508,9 @@
355
508
  "content": "// The two looks of the storytelling kit (story.css), shared by its entries. Server-safe.\n\n/** The look of the storytelling kit: `default` (sober, for any app) or `arcade` (the opt-in cabinet flavour). */\nexport type StoryVariant = \"default\" | \"arcade\";\n\n/** The class a storytelling component adds for its look (`kzs-arcade` for the arcade flavour). */\nexport const storyVariantClass = (variant: StoryVariant | undefined) => (variant === \"arcade\" ? \"kzs-arcade\" : undefined);\n\n/** The class of a brand scope (`brand-orochia`): the accent and the gradient become that brand's. */\nexport const brandClass = (brand: string | undefined) => (brand ? `brand-${brand}` : undefined);\n"
356
509
  }
357
510
  ],
358
- "dependencies": [],
511
+ "dependencies": [
512
+ "tailwind-variants@^3.3.1"
513
+ ],
359
514
  "registryDependencies": [
360
515
  "cn"
361
516
  ],
@@ -364,6 +519,75 @@
364
519
  "content": "import { Avatar } from \"@krizaka/ui/avatar\";\nimport { Button } from \"@krizaka/ui/button\";\nimport { ProfileCard } from \"@krizaka/ui/profile-card\";\n\n// A creator at a glance: the headline gauge, the stats with their values in words, the actions under them.\nexport default function ProfileCardCreator() {\n return (\n <ProfileCard\n visual={<Avatar src=\"https://krizaka-assets.b-cdn.net/site/people/ui/noor-256.c340c41421.webp\" alt=\"Noor Haddad\" fallback=\"NH\" size=\"xl\" />}\n visualSize={96}\n name=\"Noor Haddad\"\n statLabel=\"Profile complete\"\n value={80}\n stats={[\n { label: \"Challenges met\", value: 12, max: 15, valueText: \"12 of 15\" },\n { label: \"Replies within a day\", value: 94 },\n ]}\n caption=\"Dance and street fashion · Montréal\"\n >\n <Button variant=\"primary\" size=\"sm\">\n Follow\n </Button>\n <Button size=\"sm\">Message</Button>\n </ProfileCard>\n );\n}\n"
365
520
  },
366
521
  "props": [
522
+ {
523
+ "component": "ProfileBanner",
524
+ "description": "A person's or a place's banner: cover, overlapping avatar, eyebrow, name (h1), facts and actions — the words never on the cover.",
525
+ "props": [
526
+ {
527
+ "name": "avatar",
528
+ "type": "ReactNode",
529
+ "default": null,
530
+ "description": "The avatar overlapping the cover: `Avatar` with the family's default (`defaultAvatar: { brand, seed }`, #598) when there is no photo.",
531
+ "required": true
532
+ },
533
+ {
534
+ "name": "title",
535
+ "type": "ReactNode",
536
+ "default": null,
537
+ "description": "The name: the page's heading.",
538
+ "required": true
539
+ },
540
+ {
541
+ "name": "actions",
542
+ "type": "ReactNode",
543
+ "default": null,
544
+ "description": "The actions (message, book, edit): at the right from `sm`, under the name on a phone.",
545
+ "required": false
546
+ },
547
+ {
548
+ "name": "banner",
549
+ "type": "ReactNode",
550
+ "default": null,
551
+ "description": "The cover: an `<img alt=\"\">` (decorative) or your framework's image. Absent: a tint of the brand's accent.",
552
+ "required": false
553
+ },
554
+ {
555
+ "name": "brand",
556
+ "type": "string",
557
+ "default": null,
558
+ "description": "A brand scope (`akinaza` → `.brand-akinaza`): the default cover takes that brand's accent.",
559
+ "required": false
560
+ },
561
+ {
562
+ "name": "eyebrow",
563
+ "type": "ReactNode",
564
+ "default": null,
565
+ "description": "A mono line above the name: what it is (« Client », « Shop »), an id.",
566
+ "required": false
567
+ },
568
+ {
569
+ "name": "meta",
570
+ "type": "ReactNode",
571
+ "default": null,
572
+ "description": "Under the name: its facts (a handle, a city, « client since 2024 »).",
573
+ "required": false
574
+ },
575
+ {
576
+ "name": "status",
577
+ "type": "ReactNode",
578
+ "default": null,
579
+ "description": "Beside the name: a status (`Badge`), a verified mark.",
580
+ "required": false
581
+ },
582
+ {
583
+ "name": "titleAs",
584
+ "type": "\"h1\" | \"h2\"",
585
+ "default": "h1",
586
+ "description": "The level of the name.",
587
+ "required": false
588
+ }
589
+ ]
590
+ },
367
591
  {
368
592
  "component": "ProfileCard",
369
593
  "description": "A profile at a glance: portrait, name, a headline gauge, stats with their values in words, a line and actions.",
@@ -117,7 +117,7 @@
117
117
  },
118
118
  {
119
119
  "name": "size",
120
- "type": "\"sm\" | \"md\" | \"lg\"",
120
+ "type": "\"sm\" | \"lg\" | \"md\"",
121
121
  "default": "md",
122
122
  "description": "sm · md · lg: the bar's thickness, the ring's diameter.",
123
123
  "required": false
@@ -235,6 +235,7 @@
235
235
  "The ring's centre is native text (`Txt`).",
236
236
  "Style with `style`, not `className`."
237
237
  ],
238
+ "deprecated": null,
238
239
  "props": [
239
240
  {
240
241
  "component": "Progress",
@@ -341,7 +342,7 @@
341
342
  "files": [
342
343
  {
343
344
  "path": "meta.ts",
344
- "content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which ui.krizaka.com (apps/site) renders as\n// ui.krizaka.com/components/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"agenda\"\n | \"account-settings\"\n | \"drop-overlay\"\n | \"upload-queue\"\n | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"taped-photo\"\n | \"text-style\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\n | \"chapter\"\n | \"specimen-tag\"\n | \"action-bar\"\n | \"action-sheet\"\n | \"activity-feed\"\n | \"alert\"\n | \"app-header\"\n | \"app-shell\"\n | \"argument-card\"\n | \"audio-player\"\n | \"auth-layout\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"captcha\"\n | \"card\"\n | \"card-grid\"\n | \"catalogue-page\"\n | \"changelog-page\"\n | \"chat\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"chip-row\"\n | \"choice-grid\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"comparison-table\"\n | \"command\"\n | \"component-page\"\n | \"confirm-button\"\n | \"contact-page\"\n | \"continue-prompt\"\n | \"countdown\"\n | \"cover-hero\"\n | \"cta-panel\"\n | \"dashboard-layout\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"description-list\"\n | \"detail-layout\"\n | \"dialog\"\n | \"docs-article-page\"\n | \"docs-hub-page\"\n | \"docs-layout\"\n | \"docs-nav\"\n | \"document-viewer\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"engine-flow\"\n | \"error-page\"\n | \"fab\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"force-update-screen\"\n | \"form\"\n | \"gallery-page\"\n | \"genui\"\n | \"glossary\"\n | \"glossary-term\"\n | \"glow-card\"\n | \"goal-gauge\"\n | \"header\"\n | \"how-it-works-page\"\n | \"image-cropper\"\n | \"image-viewer\"\n | \"iso\"\n | \"kanban\"\n | \"kbd\"\n | \"kpi-explained\"\n | \"landing-page\"\n | \"landscape\"\n | \"legal-page\"\n | \"link-card\"\n | \"list\"\n | \"loader\"\n | \"longform-page\"\n | \"maintenance-screen\"\n | \"map\"\n | \"markdown\"\n | \"meta-row\"\n | \"waveform\"\n | \"marketing-layout\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascot-state\"\n | \"mascots\"\n | \"match-dialog\"\n | \"media-capture\"\n | \"media-grid\"\n | \"language-switch\"\n | \"media-gallery\"\n | \"media-picker\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"onboarding\"\n | \"opening-hours\"\n | \"otp-input\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"permission-prompt\"\n | \"photo-grid\"\n | \"pointer-light\"\n | \"popover\"\n | \"pricing-page\"\n | \"product-page\"\n | \"profile-card\"\n | \"progress\"\n | \"promise-card\"\n | \"pull-to-refresh\"\n | \"radio-group\"\n | \"router\"\n | \"rail-nav\"\n | \"recipes\"\n | \"screen\"\n | \"scroll-stage\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"service-card\"\n | \"settings-layout\"\n | \"account-menu\"\n | \"showcase\"\n | \"step-showcase\"\n | \"site-footer\"\n | \"sites\"\n | \"skeleton\"\n | \"skip-link\"\n | \"slider\"\n | \"slot-picker\"\n | \"slot\"\n | \"spinner\"\n | \"sticky-action\"\n | \"splash-handoff\"\n | \"split-view\"\n | \"stage-banner\"\n | \"stat\"\n | \"status-page\"\n | \"step-progress\"\n | \"stepper\"\n | \"swipe-deck\"\n | \"swipeable-row\"\n | \"switch\"\n | \"tab-bar\"\n | \"tabs\"\n | \"tag-input\"\n | \"tag-selector\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"tree-view\"\n | \"txt\"\n | \"update-prompt\"\n | \"verified-badge\"\n | \"vertical-video\"\n | \"video-player\"\n | \"video-trimmer\"\n | \"virtual\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/**\n * Why a component is not on a platform — a decision, never a silence (the parity matrix of ui.krizaka.com/platforms):\n * - `gap` (✗): it belongs there and is not built yet; `issue` is the issue that tracks it (`krizaka/krizaka-ui#275`);\n * - `n/a`: it is not meant for that platform (a site's page block on a phone, a swipe on a desktop); `use` names the\n * component that answers there, when one does.\n */\nexport type Absence =\n | { readonly status: \"gap\"; readonly issue: string; readonly reason: string; readonly use?: undefined }\n | { readonly status: \"n/a\"; readonly reason: string; readonly use?: ComponentName; readonly issue?: undefined };\n\n/**\n * Desktop is the Orazaka Mac app (Tauri 2: the system WebView renders the web components — ADR-002). `web`: the web\n * component runs there as it is; `desktop`: it also has a desktop form (a window's title bar, a denser layout…), said in\n * its documentation; otherwise the absence and why.\n */\nexport type DesktopSupport = \"web\" | \"desktop\" | Absence;\n\n/**\n * The three platforms of Krizaka UI — web · native (React Native, Expo) · desktop — for one component. The side a\n * component has is `platforms`; the side it lacks says why here: `native` is required for (and only for) a web-only\n * component, `web` for a native-only one; `desktop` always. `scripts/registry.test.mjs` fails on a missing decision.\n */\nexport interface Parity {\n readonly web?: Absence;\n readonly native?: Absence;\n readonly desktop: DesktopSupport;\n}\n\n/**\n * `stable`: its API only changes in a major. `beta`: it may still change in a minor. `deprecated`: no product uses it and\n * no work plans to — it still works, says what replaces it, and goes in the major named by `deprecated.removedIn`.\n */\nexport type Status = \"stable\" | \"beta\" | \"deprecated\";\n\n/** What a deprecated component says (required when `status` is `deprecated`, absent otherwise). */\nexport interface Deprecation {\n /** The version that deprecated it (`3.6.0`). */\n readonly since: string;\n /** The major that removes it (`4.0.0`). */\n readonly removedIn: string;\n /** What replaces it, when a component does. */\n readonly use?: ComponentName;\n /** Why it goes: no product uses it, no planned work needs it. */\n readonly reason: string;\n}\n\n/**\n * The group of the catalogue. `media`: video, sound, camera, files, cropping. `blocks`: the page blocks — the frame,\n * the hero, sections, cards that lead or argue, decisions, code, calls to act — that every page of a site is made of.\n * `layouts`: the shells of whole screens — an application, a dashboard, settings, sign-in, an object, a list and its\n * item, a site's page, a documentation page — each with its screens. `templates`: the page templates — whole pages of a\n * site (a landing, a product, a docs hub, a long read, a changelog, pricing, status, an error…), each a distinct\n * composition of the blocks, words and content as props.\n */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layouts\" | \"templates\" | \"layout\" | \"foundations\";\n\n/** Why a reader needs a template: the seven intents the templates are grouped by (sidebar sub-headings, catalogue filter). */\nexport type TemplatePurpose = \"convince\" | \"explain\" | \"show\" | \"act\" | \"operate\" | \"converse\" | \"recover\";\n\n/** The groups of templates, in reading order: the title, and the one line that says when to come to that group. */\nexport const templatePurposes = {\n convince: { title: \"Convince\", useWhen: \"You come here when a visitor must decide: a landing, a product, a price, a comparison, a proof.\" },\n explain: { title: \"Explain\", useWhen: \"You come here when a reader must understand: how it works, a documentation hub or article, a changelog, a FAQ, a policy.\" },\n show: { title: \"Show\", useWhen: \"You come here when the work itself is the argument: a gallery, a story, a case study, an object and its details.\" },\n act: { title: \"Act\", useWhen: \"You come here when a person must do something once: reach the team, sign in or up, set up, pay.\" },\n operate: { title: \"Operate\", useWhen: \"You come here when a person works every day: a dashboard, a console with a table, settings, an app shell.\" },\n converse: { title: \"Converse\", useWhen: \"You come here when people talk: an inbox, a chat, comments, a notifications centre.\" },\n recover: { title: \"Recover\", useWhen: \"You come here when the way is blocked: an empty list, an error, a missing page, maintenance, a product still being built.\" },\n} as const satisfies Record<TemplatePurpose, { readonly title: string; readonly useWhen: string }>;\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\ninterface ExampleBase {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** A plain example, or a template: a whole screen with its intent (`purpose`) and the user goal its layout serves (`why`). */\nexport type Example =\n | (ExampleBase & { readonly template?: false; readonly purpose?: undefined; readonly why?: undefined })\n | (ExampleBase & {\n /**\n * A template: a whole screen of a product composed from the platform (a layout and its blocks, real words, its\n * phone version thought out), copied as a starting point — at most 160 lines, listed on ui.krizaka.com/templates.\n */\n readonly template: true;\n /** The intent that groups it: why you need this block. */\n readonly purpose: TemplatePurpose;\n /** Why this layout: the user goal it serves, in one sentence. */\n readonly why: string;\n });\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n /** Required for, and only for, a `deprecated` component. */\n readonly deprecated?: Deprecation;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** The platforms it is not on, and why; and its desktop form (see `Parity`). */\n readonly parity: Parity;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
345
+ "content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which ui.krizaka.com (apps/site) renders as\n// ui.krizaka.com/components/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"notification-preferences\"\n | \"quota-meter\"\n | \"agenda\"\n | \"account-settings\"\n | \"drop-overlay\"\n | \"upload-queue\"\n | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"taped-photo\"\n | \"stuck\"\n | \"doodle\"\n | \"signature\"\n | \"text-style\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\n | \"chapter\"\n | \"specimen-tag\"\n | \"action-bar\"\n | \"action-sheet\"\n | \"activity-feed\"\n | \"alert\"\n | \"app-header\"\n | \"app-shell\"\n | \"argument-card\"\n | \"audio-player\"\n | \"auth-layout\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"captcha\"\n | \"card\"\n | \"card-grid\"\n | \"catalogue-page\"\n | \"changelog-page\"\n | \"chat\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"chip-row\"\n | \"choice-grid\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"comparison-table\"\n | \"command\"\n | \"component-page\"\n | \"confirm-button\"\n | \"contact-page\"\n | \"continue-prompt\"\n | \"countdown\"\n | \"cover-hero\"\n | \"cta-panel\"\n | \"dashboard-layout\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"description-list\"\n | \"detail-layout\"\n | \"dialog\"\n | \"docs-article-page\"\n | \"docs-hub-page\"\n | \"docs-layout\"\n | \"docs-nav\"\n | \"document-viewer\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"engine-flow\"\n | \"error-page\"\n | \"fab\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"force-update-screen\"\n | \"form\"\n | \"gallery-page\"\n | \"genui\"\n | \"glossary\"\n | \"glossary-term\"\n | \"glow-card\"\n | \"goal-gauge\"\n | \"header\"\n | \"how-it-works-page\"\n | \"image-cropper\"\n | \"image-viewer\"\n | \"iso\"\n | \"kanban\"\n | \"kbd\"\n | \"kpi-explained\"\n | \"landing-page\"\n | \"landscape\"\n | \"legal-page\"\n | \"link-card\"\n | \"list\"\n | \"loader\"\n | \"longform-page\"\n | \"maintenance-screen\"\n | \"map\"\n | \"markdown\"\n | \"meta-row\"\n | \"waveform\"\n | \"marketing-layout\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascot-state\"\n | \"mascots\"\n | \"match-dialog\"\n | \"media-capture\"\n | \"media-grid\"\n | \"language-switch\"\n | \"media-gallery\"\n | \"media-picker\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"onboarding\"\n | \"opening-hours\"\n | \"otp-input\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"permission-prompt\"\n | \"photo-grid\"\n | \"pointer-light\"\n | \"popover\"\n | \"pricing-page\"\n | \"product-page\"\n | \"profile-card\"\n | \"progress\"\n | \"promise-card\"\n | \"pull-to-refresh\"\n | \"retro-tv\"\n | \"radio-group\"\n | \"router\"\n | \"rail-nav\"\n | \"recipes\"\n | \"screen\"\n | \"scroll-stage\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"service-card\"\n | \"settings-layout\"\n | \"account-menu\"\n | \"showcase\"\n | \"step-showcase\"\n | \"site-footer\"\n | \"sites\"\n | \"skeleton\"\n | \"skip-link\"\n | \"slider\"\n | \"slot-picker\"\n | \"slot\"\n | \"spinner\"\n | \"sticky-action\"\n | \"splash-handoff\"\n | \"split-view\"\n | \"stage-banner\"\n | \"stat\"\n | \"status-page\"\n | \"step-progress\"\n | \"stepper\"\n | \"swipe-deck\"\n | \"swipeable-row\"\n | \"switch\"\n | \"tab-bar\"\n | \"tabs\"\n | \"tag-input\"\n | \"tag-selector\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"tree-view\"\n | \"txt\"\n | \"update-prompt\"\n | \"verified-badge\"\n | \"vertical-video\"\n | \"video-player\"\n | \"video-trimmer\"\n | \"virtual\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/**\n * Why a component is not on a platform — a decision, never a silence (the parity matrix of ui.krizaka.com/platforms):\n * - `gap` (✗): it belongs there and is not built yet; `issue` is the issue that tracks it (`krizaka/krizaka-ui#275`);\n * - `n/a`: it is not meant for that platform (a site's page block on a phone, a swipe on a desktop); `use` names the\n * component that answers there, when one does.\n */\nexport type Absence =\n | { readonly status: \"gap\"; readonly issue: string; readonly reason: string; readonly use?: undefined }\n | { readonly status: \"n/a\"; readonly reason: string; readonly use?: ComponentName; readonly issue?: undefined };\n\n/**\n * Desktop is the Orazaka Mac app (Tauri 2: the system WebView renders the web components — ADR-002). `web`: the web\n * component runs there as it is; `desktop`: it also has a desktop form (a window's title bar, a denser layout…), said in\n * its documentation; otherwise the absence and why.\n */\nexport type DesktopSupport = \"web\" | \"desktop\" | Absence;\n\n/**\n * The three platforms of Krizaka UI — web · native (React Native, Expo) · desktop — for one component. The side a\n * component has is `platforms`; the side it lacks says why here: `native` is required for (and only for) a web-only\n * component, `web` for a native-only one; `desktop` always. `scripts/registry.test.mjs` fails on a missing decision.\n */\nexport interface Parity {\n readonly web?: Absence;\n readonly native?: Absence;\n readonly desktop: DesktopSupport;\n}\n\n/**\n * `stable`: its API only changes in a major. `beta`: it may still change in a minor. `deprecated`: no product uses it and\n * no work plans to — it still works, says what replaces it, and goes in the major named by `deprecated.removedIn`.\n */\nexport type Status = \"stable\" | \"beta\" | \"deprecated\";\n\n/** What a deprecated component says (required when `status` is `deprecated`, absent otherwise). */\nexport interface Deprecation {\n /** The version that deprecated it (`3.6.0`). */\n readonly since: string;\n /** The major that removes it (`4.0.0`). */\n readonly removedIn: string;\n /** What replaces it, when a component does. */\n readonly use?: ComponentName;\n /** Why it goes: no product uses it, no planned work needs it. */\n readonly reason: string;\n}\n\n/**\n * The group of the catalogue. `media`: video, sound, camera, files, cropping. `blocks`: the page blocks — the frame,\n * the hero, sections, cards that lead or argue, decisions, code, calls to act — that every page of a site is made of.\n * `layouts`: the shells of whole screens — an application, a dashboard, settings, sign-in, an object, a list and its\n * item, a site's page, a documentation page — each with its screens. `templates`: the page templates — whole pages of a\n * site (a landing, a product, a docs hub, a long read, a changelog, pricing, status, an error…), each a distinct\n * composition of the blocks, words and content as props.\n */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layouts\" | \"templates\" | \"layout\" | \"foundations\";\n\n/** Why a reader needs a template: the seven intents the templates are grouped by (sidebar sub-headings, catalogue filter). */\nexport type TemplatePurpose = \"convince\" | \"explain\" | \"show\" | \"act\" | \"operate\" | \"converse\" | \"recover\";\n\n/** The groups of templates, in reading order: the title, and the one line that says when to come to that group. */\nexport const templatePurposes = {\n convince: { title: \"Convince\", useWhen: \"You come here when a visitor must decide: a landing, a product, a price, a comparison, a proof.\" },\n explain: { title: \"Explain\", useWhen: \"You come here when a reader must understand: how it works, a documentation hub or article, a changelog, a FAQ, a policy.\" },\n show: { title: \"Show\", useWhen: \"You come here when the work itself is the argument: a gallery, a story, a case study, an object and its details.\" },\n act: { title: \"Act\", useWhen: \"You come here when a person must do something once: reach the team, sign in or up, set up, pay.\" },\n operate: { title: \"Operate\", useWhen: \"You come here when a person works every day: a dashboard, a console with a table, settings, an app shell.\" },\n converse: { title: \"Converse\", useWhen: \"You come here when people talk: an inbox, a chat, comments, a notifications centre.\" },\n recover: { title: \"Recover\", useWhen: \"You come here when the way is blocked: an empty list, an error, a missing page, maintenance, a product still being built.\" },\n} as const satisfies Record<TemplatePurpose, { readonly title: string; readonly useWhen: string }>;\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\ninterface ExampleBase {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** A plain example, or a template: a whole screen with its intent (`purpose`) and the user goal its layout serves (`why`). */\nexport type Example =\n | (ExampleBase & { readonly template?: false; readonly purpose?: undefined; readonly why?: undefined })\n | (ExampleBase & {\n /**\n * A template: a whole screen of a product composed from the platform (a layout and its blocks, real words, its\n * phone version thought out), copied as a starting point — at most 160 lines, listed on ui.krizaka.com/templates.\n */\n readonly template: true;\n /** The intent that groups it: why you need this block. */\n readonly purpose: TemplatePurpose;\n /** Why this layout: the user goal it serves, in one sentence. */\n readonly why: string;\n });\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n /** The React Native entry alone is deprecated while the web one stays (ADR-006 §7); a deprecated component says it once, above. */\n readonly deprecated?: Deprecation;\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n /** Required for, and only for, a `deprecated` component. */\n readonly deprecated?: Deprecation;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** The platforms it is not on, and why; and its desktop form (see `Parity`). */\n readonly parity: Parity;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
345
346
  },
346
347
  {
347
348
  "path": "progress/index.ts",
@@ -420,7 +421,7 @@
420
421
  },
421
422
  {
422
423
  "name": "size",
423
- "type": "\"sm\" | \"md\" | \"lg\"",
424
+ "type": "\"sm\" | \"lg\" | \"md\"",
424
425
  "default": "md",
425
426
  "description": "sm · md · lg: the bar's thickness, the ring's diameter.",
426
427
  "required": false