@krizaka/ui 3.45.0 → 3.48.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 (219) hide show
  1. package/dist/account-menu.d.ts +2 -111
  2. package/dist/account-menu.js +39 -118
  3. package/dist/account-menu.js.map +1 -1
  4. package/dist/account-settings.d.ts +163 -0
  5. package/dist/account-settings.js +354 -0
  6. package/dist/account-settings.js.map +1 -0
  7. package/dist/agenda.d.ts +136 -0
  8. package/dist/agenda.js +90 -0
  9. package/dist/agenda.js.map +1 -0
  10. package/dist/avatar-iajODANU.d.ts +114 -0
  11. package/dist/chunk-3D2YI63L.js +27 -0
  12. package/dist/chunk-3D2YI63L.js.map +1 -0
  13. package/dist/chunk-3RVFD3UX.js +85 -0
  14. package/dist/chunk-3RVFD3UX.js.map +1 -0
  15. package/dist/chunk-S6NYGOJT.js +22 -0
  16. package/dist/chunk-S6NYGOJT.js.map +1 -0
  17. package/dist/docs-layout.js +13 -32
  18. package/dist/docs-layout.js.map +1 -1
  19. package/dist/docs-nav.js +1 -1
  20. package/dist/drop-overlay.d.ts +31 -0
  21. package/dist/drop-overlay.js +86 -0
  22. package/dist/drop-overlay.js.map +1 -0
  23. package/dist/motion.css +27 -0
  24. package/dist/nav-bar.d.ts +41 -1
  25. package/dist/nav-bar.js +26 -1
  26. package/dist/nav-bar.js.map +1 -1
  27. package/dist/settings-layout.d.ts +59 -4
  28. package/dist/settings-layout.js +229 -24
  29. package/dist/settings-layout.js.map +1 -1
  30. package/dist/upload-queue.d.ts +67 -0
  31. package/dist/upload-queue.js +76 -0
  32. package/dist/upload-queue.js.map +1 -0
  33. package/package.json +31 -5
  34. package/registry/account-menu.json +2 -2
  35. package/registry/account-settings.json +721 -0
  36. package/registry/achievement.json +1 -1
  37. package/registry/action-bar.json +1 -1
  38. package/registry/activity-feed.json +1 -1
  39. package/registry/agenda.json +293 -0
  40. package/registry/alert.json +1 -1
  41. package/registry/anatomy-plate.json +1 -1
  42. package/registry/app-header.json +1 -1
  43. package/registry/app-shell.json +1 -1
  44. package/registry/argument-card.json +1 -1
  45. package/registry/audio-player.json +1 -1
  46. package/registry/auth-layout.json +1 -1
  47. package/registry/avatar.json +1 -1
  48. package/registry/badge.json +1 -1
  49. package/registry/bird-plate.json +1 -1
  50. package/registry/button.json +1 -1
  51. package/registry/captcha.json +1 -1
  52. package/registry/card-grid.json +1 -1
  53. package/registry/card.json +1 -1
  54. package/registry/catalogue-page.json +1 -1
  55. package/registry/changelog-page.json +1 -1
  56. package/registry/chat.json +3 -3
  57. package/registry/checkbox.json +1 -1
  58. package/registry/chip-link.json +1 -1
  59. package/registry/chip-row.json +1 -1
  60. package/registry/chip.json +1 -1
  61. package/registry/choice-grid.json +1 -1
  62. package/registry/code-block.json +1 -1
  63. package/registry/combobox.json +1 -1
  64. package/registry/command.json +1 -1
  65. package/registry/comparison-table.json +1 -1
  66. package/registry/component-page.json +1 -1
  67. package/registry/confirm-button.json +1 -1
  68. package/registry/contact-page.json +1 -1
  69. package/registry/continue-prompt.json +1 -1
  70. package/registry/countdown.json +1 -1
  71. package/registry/cover-hero.json +1 -1
  72. package/registry/cta-panel.json +1 -1
  73. package/registry/dashboard-layout.json +1 -1
  74. package/registry/data-table.json +3 -3
  75. package/registry/date-picker.json +1 -1
  76. package/registry/decision-list.json +1 -1
  77. package/registry/description-list.json +1 -1
  78. package/registry/detail-layout.json +1 -1
  79. package/registry/dialog.json +1 -1
  80. package/registry/docs-article-page.json +1 -1
  81. package/registry/docs-hub-page.json +1 -1
  82. package/registry/docs-layout.json +1 -1
  83. package/registry/docs-nav.json +1 -1
  84. package/registry/document-viewer.json +1 -1
  85. package/registry/drop-overlay.json +182 -0
  86. package/registry/dropdown-menu.json +1 -1
  87. package/registry/elephant.json +2 -2
  88. package/registry/empty-state.json +1 -1
  89. package/registry/engine-flow.json +1 -1
  90. package/registry/error-page.json +1 -1
  91. package/registry/examples/account-settings/avatar-picker.d.ts +4 -0
  92. package/registry/examples/account-settings/avatar-picker.js +15 -0
  93. package/registry/examples/account-settings/avatar-picker.tsx +15 -0
  94. package/registry/examples/account-settings/choice-cards.d.ts +4 -0
  95. package/registry/examples/account-settings/choice-cards.js +24 -0
  96. package/registry/examples/account-settings/choice-cards.tsx +20 -0
  97. package/registry/examples/account-settings/language-picker.d.ts +4 -0
  98. package/registry/examples/account-settings/language-picker.js +25 -0
  99. package/registry/examples/account-settings/language-picker.tsx +21 -0
  100. package/registry/examples/account-settings/patterns.d.ts +4 -0
  101. package/registry/examples/account-settings/patterns.js +29 -0
  102. package/registry/examples/account-settings/patterns.tsx +39 -0
  103. package/registry/examples/account-settings/profile.d.ts +4 -0
  104. package/registry/examples/account-settings/profile.js +70 -0
  105. package/registry/examples/account-settings/profile.tsx +80 -0
  106. package/registry/examples/agenda/day.d.ts +4 -0
  107. package/registry/examples/agenda/day.js +43 -0
  108. package/registry/examples/agenda/day.tsx +35 -0
  109. package/registry/examples/drop-overlay/default.d.ts +4 -0
  110. package/registry/examples/drop-overlay/default.js +20 -0
  111. package/registry/examples/drop-overlay/default.tsx +18 -0
  112. package/registry/examples/upload-queue/default.d.ts +4 -0
  113. package/registry/examples/upload-queue/default.js +22 -0
  114. package/registry/examples/upload-queue/default.tsx +20 -0
  115. package/registry/examples/upload-queue/tray.d.ts +4 -0
  116. package/registry/examples/upload-queue/tray.js +21 -0
  117. package/registry/examples/upload-queue/tray.tsx +19 -0
  118. package/registry/field.json +1 -1
  119. package/registry/file-upload.json +1 -1
  120. package/registry/filter-bar.json +1 -1
  121. package/registry/flock.json +1 -1
  122. package/registry/footnote.json +1 -1
  123. package/registry/force-update-screen.json +1 -1
  124. package/registry/form.json +3 -3
  125. package/registry/gallery-page.json +1 -1
  126. package/registry/genui.json +1 -1
  127. package/registry/glow-card.json +1 -1
  128. package/registry/goal-gauge.json +1 -1
  129. package/registry/how-it-works-page.json +1 -1
  130. package/registry/image-cropper.json +1 -1
  131. package/registry/index.json +148 -7
  132. package/registry/iso.json +1 -1
  133. package/registry/kanban.json +1 -1
  134. package/registry/kbd.json +1 -1
  135. package/registry/landing-page.json +1 -1
  136. package/registry/landscape.json +1 -1
  137. package/registry/language-switch.json +1 -1
  138. package/registry/legal-page.json +1 -1
  139. package/registry/link-card.json +1 -1
  140. package/registry/list.json +3 -3
  141. package/registry/loader.json +1 -1
  142. package/registry/longform-page.json +1 -1
  143. package/registry/maintenance-screen.json +1 -1
  144. package/registry/map.json +2 -2
  145. package/registry/markdown.json +1 -1
  146. package/registry/marketing-layout.json +1 -1
  147. package/registry/marquee.json +1 -1
  148. package/registry/mascot-quote.json +3 -3
  149. package/registry/mascot-state.json +3 -3
  150. package/registry/mascots.json +3 -3
  151. package/registry/match-dialog.json +1 -1
  152. package/registry/media-capture.json +1 -1
  153. package/registry/media-gallery.json +1 -1
  154. package/registry/media-grid.json +1 -1
  155. package/registry/meta-row.json +1 -1
  156. package/registry/meter.json +1 -1
  157. package/registry/nav-bar.json +93 -5
  158. package/registry/number-ticker.json +1 -1
  159. package/registry/opening-hours.json +1 -1
  160. package/registry/page-header.json +1 -1
  161. package/registry/page-hero.json +1 -1
  162. package/registry/page-index.json +1 -1
  163. package/registry/page.json +1 -1
  164. package/registry/pagination.json +1 -1
  165. package/registry/photo-grid.json +1 -1
  166. package/registry/pointer-light.json +1 -1
  167. package/registry/popover.json +1 -1
  168. package/registry/pricing-page.json +1 -1
  169. package/registry/product-page.json +1 -1
  170. package/registry/profile-card.json +1 -1
  171. package/registry/progress.json +1 -1
  172. package/registry/promise-card.json +1 -1
  173. package/registry/radio-group.json +93 -5
  174. package/registry/rail-nav.json +2 -2
  175. package/registry/recipes.json +1 -1
  176. package/registry/router.json +1 -1
  177. package/registry/scroll-stage.json +1 -1
  178. package/registry/search-field.json +1 -1
  179. package/registry/section-backdrop.json +1 -1
  180. package/registry/separator.json +1 -1
  181. package/registry/service-card.json +1 -1
  182. package/registry/settings-layout.json +34 -4
  183. package/registry/showcase.json +1 -1
  184. package/registry/site-footer.json +2 -2
  185. package/registry/sites.json +1 -1
  186. package/registry/skeleton.json +1 -1
  187. package/registry/skip-link.json +1 -1
  188. package/registry/slider.json +1 -1
  189. package/registry/slot-picker.json +1 -1
  190. package/registry/slot.json +1 -1
  191. package/registry/specimen-tag.json +1 -1
  192. package/registry/spinner.json +1 -1
  193. package/registry/split-view.json +1 -1
  194. package/registry/stage-banner.json +1 -1
  195. package/registry/stat.json +1 -1
  196. package/registry/status-page.json +1 -1
  197. package/registry/step-progress.json +1 -1
  198. package/registry/step-showcase.json +1 -1
  199. package/registry/stepper.json +1 -1
  200. package/registry/sticky-action.json +1 -1
  201. package/registry/swipe-deck.json +1 -1
  202. package/registry/switch.json +1 -1
  203. package/registry/tabs.json +1 -1
  204. package/registry/tag-input.json +3 -3
  205. package/registry/tag-selector.json +1 -1
  206. package/registry/terminal-replay.json +1 -1
  207. package/registry/theme.json +1 -1
  208. package/registry/toast.json +1 -1
  209. package/registry/toc.json +1 -1
  210. package/registry/tooltip.json +1 -1
  211. package/registry/tree-view.json +1 -1
  212. package/registry/update-prompt.json +1 -1
  213. package/registry/upload-queue.json +243 -0
  214. package/registry/verified-badge.json +1 -1
  215. package/registry/vertical-video.json +1 -1
  216. package/registry/video-player.json +1 -1
  217. package/registry/video-trimmer.json +1 -1
  218. package/registry/virtual.json +1 -1
  219. package/registry/waveform.json +1 -1
@@ -134,7 +134,7 @@
134
134
  },
135
135
  {
136
136
  "path": "meta.ts",
137
- "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 | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\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 | \"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 | \"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"
137
+ "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 | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\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 | \"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 | \"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"
138
138
  }
139
139
  ],
140
140
  "dependencies": [],
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,15 @@
1
+ "use client";
2
+
3
+ // registry/examples/account-settings/avatar-picker.tsx
4
+ import { AvatarPicker } from "@krizaka/ui/account-settings";
5
+ import { Button } from "@krizaka/ui/button";
6
+ import * as React from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var OPTIONS = [1, 2, 3, 4, 5, 6].map((tone) => ({ id: `tone-${tone}`, label: `Teinte ${tone}`, defaultAvatar: { brand: "yomizaka", tone } }));
9
+ function AvatarPickerExample() {
10
+ const [value, setValue] = React.useState("tone-2");
11
+ return /* @__PURE__ */ jsx("div", { className: "w-full max-w-md", children: /* @__PURE__ */ jsx(AvatarPicker, { label: "Photo de profil", showLabel: true, options: OPTIONS, value, onValueChange: setValue, upload: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", children: "T\xE9l\xE9verser" }) }) });
12
+ }
13
+ export {
14
+ AvatarPickerExample as default
15
+ };
@@ -0,0 +1,15 @@
1
+ import { AvatarPicker } from "@krizaka/ui/account-settings";
2
+ import { Button } from "@krizaka/ui/button";
3
+ import * as React from "react";
4
+
5
+ const OPTIONS = [1, 2, 3, 4, 5, 6].map((tone) => ({ id: `tone-${tone}`, label: `Teinte ${tone}`, defaultAvatar: { brand: "yomizaka", tone } as const }));
6
+
7
+ // The family's default pictures as one radio group, and the upload beside them: no loose radios.
8
+ export default function AvatarPickerExample() {
9
+ const [value, setValue] = React.useState("tone-2");
10
+ return (
11
+ <div className="w-full max-w-md">
12
+ <AvatarPicker label="Photo de profil" showLabel options={OPTIONS} value={value} onValueChange={setValue} upload={<Button variant="secondary" size="sm">Téléverser</Button>} />
13
+ </div>
14
+ );
15
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+
3
+ // registry/examples/account-settings/choice-cards.tsx
4
+ import { ChoiceCards } from "@krizaka/ui/account-settings";
5
+ import * as React from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ function ChoiceCardsExample() {
8
+ const [value, setValue] = React.useState("tenant");
9
+ return /* @__PURE__ */ jsx("div", { className: "w-full max-w-xl", children: /* @__PURE__ */ jsx(
10
+ ChoiceCards,
11
+ {
12
+ label: "De quel c\xF4t\xE9 du bail \xEAtes-vous ?",
13
+ value,
14
+ onValueChange: setValue,
15
+ options: [
16
+ { id: "tenant", title: "Locataire", description: "Je loue mon logement : je veux savoir ce que je signe." },
17
+ { id: "landlord", title: "Propri\xE9taire", description: "Je loue \xE0 quelqu'un : je veux un bail en ordre." }
18
+ ]
19
+ }
20
+ ) });
21
+ }
22
+ export {
23
+ ChoiceCardsExample as default
24
+ };
@@ -0,0 +1,20 @@
1
+ import { ChoiceCards } from "@krizaka/ui/account-settings";
2
+ import * as React from "react";
3
+
4
+ // One question, two selectable cards: an icon, a title and a line each, instead of two radios under a heading.
5
+ export default function ChoiceCardsExample() {
6
+ const [value, setValue] = React.useState("tenant");
7
+ return (
8
+ <div className="w-full max-w-xl">
9
+ <ChoiceCards
10
+ label="De quel côté du bail êtes-vous ?"
11
+ value={value}
12
+ onValueChange={setValue}
13
+ options={[
14
+ { id: "tenant", title: "Locataire", description: "Je loue mon logement : je veux savoir ce que je signe." },
15
+ { id: "landlord", title: "Propriétaire", description: "Je loue à quelqu'un : je veux un bail en ordre." },
16
+ ]}
17
+ />
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,25 @@
1
+ "use client";
2
+
3
+ // registry/examples/account-settings/language-picker.tsx
4
+ import { LanguagePicker } from "@krizaka/ui/account-settings";
5
+ import * as React from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ function LanguagePickerExample() {
8
+ const [value, setValue] = React.useState("fr");
9
+ return /* @__PURE__ */ jsx("div", { className: "w-full max-w-sm", children: /* @__PURE__ */ jsx(
10
+ LanguagePicker,
11
+ {
12
+ label: "Langue",
13
+ description: "La langue de l'application et des courriels.",
14
+ value,
15
+ onValueChange: setValue,
16
+ languages: [
17
+ { code: "fr", name: "Fran\xE7ais" },
18
+ { code: "en", name: "English" }
19
+ ]
20
+ }
21
+ ) });
22
+ }
23
+ export {
24
+ LanguagePickerExample as default
25
+ };
@@ -0,0 +1,21 @@
1
+ import { LanguagePicker } from "@krizaka/ui/account-settings";
2
+ import * as React from "react";
3
+
4
+ // The account's language, labelled, each language in its own language.
5
+ export default function LanguagePickerExample() {
6
+ const [value, setValue] = React.useState("fr");
7
+ return (
8
+ <div className="w-full max-w-sm">
9
+ <LanguagePicker
10
+ label="Langue"
11
+ description="La langue de l'application et des courriels."
12
+ value={value}
13
+ onValueChange={setValue}
14
+ languages={[
15
+ { code: "fr", name: "Français" },
16
+ { code: "en", name: "English" },
17
+ ]}
18
+ />
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,29 @@
1
+ "use client";
2
+
3
+ // registry/examples/account-settings/patterns.tsx
4
+ import { Button } from "@krizaka/ui/button";
5
+ import { ConfirmButton } from "@krizaka/ui/confirm-button";
6
+ import { Meter } from "@krizaka/ui/meter";
7
+ import { SettingsRow, SettingsSection } from "@krizaka/ui/settings-layout";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ function AccountSectionPatterns() {
10
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full max-w-2xl flex-col gap-10", children: [
11
+ /* @__PURE__ */ jsxs(SettingsSection, { variant: "flat", title: "S\xE9curit\xE9", description: "Comment vous vous connectez.", children: [
12
+ /* @__PURE__ */ jsxs(SettingsRow, { label: "Courriel", description: "Un lien de confirmation est envoy\xE9 \xE0 la nouvelle adresse.", children: [
13
+ "eric@example.com ",
14
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", children: "Changer" })
15
+ ] }),
16
+ /* @__PURE__ */ jsx(SettingsRow, { label: "Mot de passe", description: "Modifi\xE9 il y a 3 mois.", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", children: "Changer" }) })
17
+ ] }),
18
+ /* @__PURE__ */ jsx(SettingsSection, { variant: "flat", title: "Abonnement", description: "Votre forfait et vos factures.", children: /* @__PURE__ */ jsx(SettingsRow, { label: "Forfait Solo", description: "Renouvel\xE9 le 1er novembre.", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", asChild: true, children: /* @__PURE__ */ jsx("a", { href: "https://billing.example.com/portal", children: "Ouvrir le portail de facturation" }) }) }) }),
19
+ /* @__PURE__ */ jsx(SettingsSection, { variant: "flat", title: "Stockage", description: "L'espace utilis\xE9 par vos documents.", children: /* @__PURE__ */ jsx(SettingsRow, { label: "Documents", children: /* @__PURE__ */ jsx(Meter, { className: "w-56", label: "Stockage", value: 18, max: 50, valueText: "18 Go sur 50 Go", showLabel: true }) }) }),
20
+ /* @__PURE__ */ jsxs(SettingsSection, { variant: "flat", title: "Mes donn\xE9es", description: "Ce que vous pouvez emporter ou effacer.", children: [
21
+ /* @__PURE__ */ jsx(SettingsRow, { label: "Exporter", description: "Une archive de tout ce que vous avez t\xE9l\xE9vers\xE9.", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", children: "Demander l'export" }) }),
22
+ /* @__PURE__ */ jsx(SettingsRow, { label: "Supprimer mon compte", description: "Vos documents et votre compte disparaissent, sans retour.", children: /* @__PURE__ */ jsx(ConfirmButton, { variant: "danger", size: "sm", confirmLabel: "Supprimer pour de bon ?", onConfirm: () => {
23
+ }, children: "Supprimer" }) })
24
+ ] })
25
+ ] });
26
+ }
27
+ export {
28
+ AccountSectionPatterns as default
29
+ };
@@ -0,0 +1,39 @@
1
+ import { Button } from "@krizaka/ui/button";
2
+ import { ConfirmButton } from "@krizaka/ui/confirm-button";
3
+ import { Meter } from "@krizaka/ui/meter";
4
+ import { SettingsRow, SettingsSection } from "@krizaka/ui/settings-layout";
5
+
6
+ // The four other sections of an account page, each a flat SettingsSection of rows: security, subscription (the billing
7
+ // portal is one link), storage (a Meter), « my data » (export, and a delete that asks twice).
8
+ export default function AccountSectionPatterns() {
9
+ return (
10
+ <div className="flex w-full max-w-2xl flex-col gap-10">
11
+ <SettingsSection variant="flat" title="Sécurité" description="Comment vous vous connectez.">
12
+ <SettingsRow label="Courriel" description="Un lien de confirmation est envoyé à la nouvelle adresse.">
13
+ eric@example.com <Button variant="secondary" size="sm">Changer</Button>
14
+ </SettingsRow>
15
+ <SettingsRow label="Mot de passe" description="Modifié il y a 3 mois.">
16
+ <Button variant="secondary" size="sm">Changer</Button>
17
+ </SettingsRow>
18
+ </SettingsSection>
19
+ <SettingsSection variant="flat" title="Abonnement" description="Votre forfait et vos factures.">
20
+ <SettingsRow label="Forfait Solo" description="Renouvelé le 1er novembre.">
21
+ <Button variant="secondary" size="sm" asChild><a href="https://billing.example.com/portal">Ouvrir le portail de facturation</a></Button>
22
+ </SettingsRow>
23
+ </SettingsSection>
24
+ <SettingsSection variant="flat" title="Stockage" description="L'espace utilisé par vos documents.">
25
+ <SettingsRow label="Documents">
26
+ <Meter className="w-56" label="Stockage" value={18} max={50} valueText="18 Go sur 50 Go" showLabel />
27
+ </SettingsRow>
28
+ </SettingsSection>
29
+ <SettingsSection variant="flat" title="Mes données" description="Ce que vous pouvez emporter ou effacer.">
30
+ <SettingsRow label="Exporter" description="Une archive de tout ce que vous avez téléversé.">
31
+ <Button variant="secondary" size="sm">Demander l'export</Button>
32
+ </SettingsRow>
33
+ <SettingsRow label="Supprimer mon compte" description="Vos documents et votre compte disparaissent, sans retour.">
34
+ <ConfirmButton variant="danger" size="sm" confirmLabel="Supprimer pour de bon ?" onConfirm={() => {}}>Supprimer</ConfirmButton>
35
+ </SettingsRow>
36
+ </SettingsSection>
37
+ </div>
38
+ );
39
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,70 @@
1
+ "use client";
2
+
3
+ // registry/examples/account-settings/profile.tsx
4
+ import { AccountProfileCard, AvatarPicker, ChoiceCards, LanguagePicker } from "@krizaka/ui/account-settings";
5
+ import { Field, Input } from "@krizaka/ui/field";
6
+ import { SettingsLayout, SettingsRow, SettingsSection, useSaveStatus } from "@krizaka/ui/settings-layout";
7
+ import * as React from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ var NAV = [
10
+ { id: "profile", label: "Profil", href: "/app/settings/profil", current: true },
11
+ { id: "security", label: "S\xE9curit\xE9", href: "/app/settings/securite" },
12
+ { id: "billing", label: "Abonnement", href: "/app/settings/facturation" },
13
+ { id: "storage", label: "Stockage", href: "/app/settings/stockage" },
14
+ { id: "data", label: "Mes donn\xE9es", href: "/app/settings/donnees" }
15
+ ];
16
+ var AVATARS = [1, 2, 3, 4, 5, 6].map((tone) => ({ id: `tone-${tone}`, label: `Teinte ${tone}`, defaultAvatar: { brand: "yomizaka", tone } }));
17
+ var LABELS = { save: "Enregistrer", saving: "Enregistrement\u2026", saved: "Enregistr\xE9", error: "Impossible d'enregistrer. R\xE9essayez.", undo: "Annuler", discard: "R\xE9tablir" };
18
+ function useDraft(saved) {
19
+ const [draft, setDraft] = React.useState(saved);
20
+ const [kept, setKept] = React.useState(saved);
21
+ const [before, setBefore] = React.useState(saved);
22
+ const status = useSaveStatus();
23
+ return {
24
+ draft,
25
+ set: (patch) => setDraft({ ...draft, ...patch }),
26
+ save: {
27
+ dirty: JSON.stringify(draft) !== JSON.stringify(kept),
28
+ status: status.status,
29
+ labels: LABELS,
30
+ onDiscard: () => setDraft(kept),
31
+ onSave: () => {
32
+ setBefore(kept);
33
+ setKept(draft);
34
+ void status.track(async () => void 0);
35
+ },
36
+ onUndo: () => {
37
+ setDraft(before);
38
+ setKept(before);
39
+ status.reset();
40
+ }
41
+ }
42
+ };
43
+ }
44
+ function AccountProfile() {
45
+ const profile = useDraft({ name: "\xC9ric Tremblay", avatar: "tone-2", language: "fr" });
46
+ const role = useDraft({ side: "tenant" });
47
+ return /* @__PURE__ */ jsxs(SettingsLayout, { variant: "flat", className: "w-full", title: "R\xE9glages", description: "Votre profil et la fa\xE7on dont l'application vous r\xE9pond.", nav: NAV, navLabel: "Sections des r\xE9glages", children: [
48
+ /* @__PURE__ */ jsxs(SettingsSection, { variant: "flat", title: "Profil", description: "Ce que l'application sait de vous.", save: profile.save, children: [
49
+ /* @__PURE__ */ jsx(SettingsRow, { label: /* @__PURE__ */ jsx(AccountProfileCard, { compact: true, name: profile.draft.name, email: "eric@example.com", verified: true, verifiedLabel: "Adresse v\xE9rifi\xE9e", unverifiedLabel: "Adresse non v\xE9rifi\xE9e", avatar: { defaultAvatar: { brand: "yomizaka", tone: Number(profile.draft.avatar.slice(5)) } } }) }),
50
+ /* @__PURE__ */ jsx(SettingsRow, { label: "Nom", description: "Affich\xE9 dans le menu du compte.", htmlFor: "profile-name", children: /* @__PURE__ */ jsx(Field.Root, { children: /* @__PURE__ */ jsx(Input, { id: "profile-name", value: profile.draft.name, onChange: (event) => profile.set({ name: event.target.value }) }) }) }),
51
+ /* @__PURE__ */ jsx(SettingsRow, { label: "Avatar", description: "Une des images par d\xE9faut.", children: /* @__PURE__ */ jsx(AvatarPicker, { dense: true, label: "Avatar", options: AVATARS, value: profile.draft.avatar, onValueChange: (avatar) => profile.set({ avatar }) }) }),
52
+ /* @__PURE__ */ jsx(SettingsRow, { label: "Langue", description: "La langue de l'application et des courriels.", children: /* @__PURE__ */ jsx(LanguagePicker, { showLabel: false, label: "Langue", value: profile.draft.language, onValueChange: (language) => profile.set({ language }), languages: [{ code: "fr", name: "Fran\xE7ais" }, { code: "en", name: "English" }] }) })
53
+ ] }),
54
+ /* @__PURE__ */ jsx(SettingsSection, { variant: "flat", title: "De quel c\xF4t\xE9 du bail \xEAtes-vous ?", description: "Cela change les v\xE9rifications propos\xE9es en premier, pas les r\xE8gles.", save: role.save, children: /* @__PURE__ */ jsx("div", { className: "py-4", children: /* @__PURE__ */ jsx(
55
+ ChoiceCards,
56
+ {
57
+ label: "De quel c\xF4t\xE9 du bail \xEAtes-vous ?",
58
+ value: role.draft.side,
59
+ onValueChange: (side) => role.set({ side }),
60
+ options: [
61
+ { id: "tenant", title: "Locataire", description: "Je v\xE9rifie mon bail avant de signer." },
62
+ { id: "landlord", title: "Propri\xE9taire", description: "Je v\xE9rifie mon mod\xE8le de bail." }
63
+ ]
64
+ }
65
+ ) }) })
66
+ ] });
67
+ }
68
+ export {
69
+ AccountProfile as default
70
+ };
@@ -0,0 +1,80 @@
1
+ import { AccountProfileCard, AvatarPicker, ChoiceCards, LanguagePicker } from "@krizaka/ui/account-settings";
2
+ import { Field, Input } from "@krizaka/ui/field";
3
+ import { SettingsLayout, SettingsRow, SettingsSection, useSaveStatus } from "@krizaka/ui/settings-layout";
4
+ import * as React from "react";
5
+
6
+ const NAV = [
7
+ { id: "profile", label: "Profil", href: "/app/settings/profil", current: true },
8
+ { id: "security", label: "Sécurité", href: "/app/settings/securite" },
9
+ { id: "billing", label: "Abonnement", href: "/app/settings/facturation" },
10
+ { id: "storage", label: "Stockage", href: "/app/settings/stockage" },
11
+ { id: "data", label: "Mes données", href: "/app/settings/donnees" },
12
+ ];
13
+ const AVATARS = [1, 2, 3, 4, 5, 6].map((tone) => ({ id: `tone-${tone}`, label: `Teinte ${tone}`, defaultAvatar: { brand: "yomizaka", tone } as const }));
14
+ const LABELS = { save: "Enregistrer", saving: "Enregistrement…", saved: "Enregistré", error: "Impossible d'enregistrer. Réessayez.", undo: "Annuler", discard: "Rétablir" };
15
+
16
+ /** One section's draft: dirty against what is saved, saved with one call, undone to what it was. */
17
+ function useDraft<T>(saved: T) {
18
+ const [draft, setDraft] = React.useState(saved);
19
+ const [kept, setKept] = React.useState(saved);
20
+ const [before, setBefore] = React.useState(saved);
21
+ const status = useSaveStatus();
22
+ return {
23
+ draft,
24
+ set: (patch: Partial<T>) => setDraft({ ...draft, ...patch }),
25
+ save: {
26
+ dirty: JSON.stringify(draft) !== JSON.stringify(kept),
27
+ status: status.status,
28
+ labels: LABELS,
29
+ onDiscard: () => setDraft(kept),
30
+ onSave: () => {
31
+ setBefore(kept);
32
+ setKept(draft);
33
+ void status.track(async () => undefined);
34
+ },
35
+ onUndo: () => {
36
+ setDraft(before);
37
+ setKept(before);
38
+ status.reset();
39
+ },
40
+ },
41
+ };
42
+ }
43
+
44
+ // TEMPLATE — an account's profile page, the Orazaka way: one calm column of rows (label and help left, control right), a
45
+ // section per subject with its own save (dirty → enabled, saved → Undo), the role question as cards in a section of its own.
46
+ export default function AccountProfile() {
47
+ const profile = useDraft({ name: "Éric Tremblay", avatar: "tone-2", language: "fr" });
48
+ const role = useDraft({ side: "tenant" });
49
+ return (
50
+ <SettingsLayout variant="flat" className="w-full" title="Réglages" description="Votre profil et la façon dont l'application vous répond." nav={NAV} navLabel="Sections des réglages">
51
+ <SettingsSection variant="flat" title="Profil" description="Ce que l'application sait de vous." save={profile.save}>
52
+ <SettingsRow label={<AccountProfileCard compact name={profile.draft.name} email="eric@example.com" verified verifiedLabel="Adresse vérifiée" unverifiedLabel="Adresse non vérifiée" avatar={{ defaultAvatar: { brand: "yomizaka", tone: Number(profile.draft.avatar.slice(5)) } }} />} />
53
+ <SettingsRow label="Nom" description="Affiché dans le menu du compte." htmlFor="profile-name">
54
+ <Field.Root>
55
+ <Input id="profile-name" value={profile.draft.name} onChange={(event) => profile.set({ name: event.target.value })} />
56
+ </Field.Root>
57
+ </SettingsRow>
58
+ <SettingsRow label="Avatar" description="Une des images par défaut.">
59
+ <AvatarPicker dense label="Avatar" options={AVATARS} value={profile.draft.avatar} onValueChange={(avatar) => profile.set({ avatar })} />
60
+ </SettingsRow>
61
+ <SettingsRow label="Langue" description="La langue de l'application et des courriels.">
62
+ <LanguagePicker showLabel={false} label="Langue" value={profile.draft.language} onValueChange={(language) => profile.set({ language })} languages={[{ code: "fr", name: "Français" }, { code: "en", name: "English" }]} />
63
+ </SettingsRow>
64
+ </SettingsSection>
65
+ <SettingsSection variant="flat" title="De quel côté du bail êtes-vous ?" description="Cela change les vérifications proposées en premier, pas les règles." save={role.save}>
66
+ <div className="py-4">
67
+ <ChoiceCards
68
+ label="De quel côté du bail êtes-vous ?"
69
+ value={role.draft.side}
70
+ onValueChange={(side) => role.set({ side })}
71
+ options={[
72
+ { id: "tenant", title: "Locataire", description: "Je vérifie mon bail avant de signer." },
73
+ { id: "landlord", title: "Propriétaire", description: "Je vérifie mon modèle de bail." },
74
+ ]}
75
+ />
76
+ </div>
77
+ </SettingsSection>
78
+ </SettingsLayout>
79
+ );
80
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,43 @@
1
+ "use client";
2
+
3
+ // registry/examples/agenda/day.tsx
4
+ import { Agenda } from "@krizaka/ui/agenda";
5
+ import { Avatar } from "@krizaka/ui/avatar";
6
+ import { Badge } from "@krizaka/ui/badge";
7
+ import { Button } from "@krizaka/ui/button";
8
+ import * as React from "react";
9
+ import { jsx } from "react/jsx-runtime";
10
+ var at = (id, hour, title, description, status) => ({
11
+ id,
12
+ title,
13
+ description,
14
+ status,
15
+ done: status === "Done",
16
+ start: `2026-10-22T${String(hour).padStart(2, "0")}:00:00Z`,
17
+ end: `2026-10-22T${String(hour).padStart(2, "0")}:45:00Z`
18
+ });
19
+ var items = [
20
+ at("a1", 9, "L\xE9a Tremblay", "Cut and colour \xB7 Camille", "Done"),
21
+ at("a2", 10, "Marc Gagnon", "Beard trim \xB7 Camille", "Done"),
22
+ at("a3", 11, "Sofia Rossi", "Cut \xB7 \xC9ric", "Booked"),
23
+ at("a4", 13, "Nadia Ben Ali", "Colour \xB7 Camille", "Booked")
24
+ ];
25
+ function AgendaDay() {
26
+ const [open, setOpen] = React.useState("a3");
27
+ return /* @__PURE__ */ jsx(
28
+ Agenda,
29
+ {
30
+ "aria-label": "Appointments of Thursday",
31
+ timeZone: "UTC",
32
+ now: /* @__PURE__ */ new Date("2026-10-22T10:50:00Z"),
33
+ selectedId: open,
34
+ onSelect: (item) => setOpen(item.id),
35
+ items: items.map((i) => ({ ...i, tone: i.done ? "success" : "accent", leading: /* @__PURE__ */ jsx(Avatar, { alt: "", fallback: i.title.charAt(0), size: "sm" }), status: /* @__PURE__ */ jsx(Badge, { tone: i.done ? "success" : "accent", children: i.status }) })),
36
+ action: (i) => i.done ? null : /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", children: "Start" }),
37
+ className: "max-w-xl"
38
+ }
39
+ );
40
+ }
41
+ export {
42
+ AgendaDay as default
43
+ };
@@ -0,0 +1,35 @@
1
+ "use client";
2
+ import { Agenda } from "@krizaka/ui/agenda";
3
+ import { Avatar } from "@krizaka/ui/avatar";
4
+ import { Badge } from "@krizaka/ui/badge";
5
+ import { Button } from "@krizaka/ui/button";
6
+ import * as React from "react";
7
+
8
+ const at = (id: string, hour: number, title: string, description: string, status: string) => ({
9
+ id, title, description, status, done: status === "Done",
10
+ start: `2026-10-22T${String(hour).padStart(2, "0")}:00:00Z`,
11
+ end: `2026-10-22T${String(hour).padStart(2, "0")}:45:00Z`,
12
+ });
13
+ const items = [
14
+ at("a1", 9, "Léa Tremblay", "Cut and colour · Camille", "Done"),
15
+ at("a2", 10, "Marc Gagnon", "Beard trim · Camille", "Done"),
16
+ at("a3", 11, "Sofia Rossi", "Cut · Éric", "Booked"),
17
+ at("a4", 13, "Nadia Ben Ali", "Colour · Camille", "Booked"),
18
+ ];
19
+
20
+ // The day, the past dimmed, « now » between the done and the booked; one quiet action on the rows to come.
21
+ export default function AgendaDay() {
22
+ const [open, setOpen] = React.useState<string | null>("a3");
23
+ return (
24
+ <Agenda
25
+ aria-label="Appointments of Thursday"
26
+ timeZone="UTC"
27
+ now={new Date("2026-10-22T10:50:00Z")}
28
+ selectedId={open}
29
+ onSelect={(item) => setOpen(item.id)}
30
+ items={items.map((i) => ({ ...i, tone: i.done ? ("success" as const) : ("accent" as const), leading: <Avatar alt="" fallback={i.title.charAt(0)} size="sm" />, status: <Badge tone={i.done ? "success" : "accent"}>{i.status}</Badge> }))}
31
+ action={(i) => (i.done ? null : <Button size="sm" variant="ghost">Start</Button>)}
32
+ className="max-w-xl"
33
+ />
34
+ );
35
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;
@@ -0,0 +1,20 @@
1
+ "use client";
2
+
3
+ // registry/examples/drop-overlay/default.tsx
4
+ import { DropOverlay } from "@krizaka/ui/drop-overlay";
5
+ import * as React from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ function DropOverlayExample() {
8
+ const [names, setNames] = React.useState([]);
9
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-40 w-full flex-col items-start gap-3", children: [
10
+ /* @__PURE__ */ jsx(DropOverlay, { label: "D\xE9posez pour v\xE9rifier", hint: "PDF ou texte", accept: [".pdf", ".txt"], onFiles: (accepted) => setNames(accepted.map((file) => file.name)) }),
11
+ /* @__PURE__ */ jsxs("label", { className: "cursor-pointer rounded-md bg-accent px-4 py-2 text-sm font-semibold text-on-accent", children: [
12
+ "V\xE9rifier un document",
13
+ /* @__PURE__ */ jsx("input", { type: "file", className: "sr-only", multiple: true, accept: ".pdf,.txt", onChange: (event) => setNames(Array.from(event.target.files ?? []).map((file) => file.name)) })
14
+ ] }),
15
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-fg-secondary", children: names.length > 0 ? names.join(", ") : "Glissez un fichier n'importe o\xF9 sur la fen\xEAtre." })
16
+ ] });
17
+ }
18
+ export {
19
+ DropOverlayExample as default
20
+ };
@@ -0,0 +1,18 @@
1
+ import { DropOverlay } from "@krizaka/ui/drop-overlay";
2
+ import * as React from "react";
3
+
4
+ // Drag a file over the window: the overlay says where to drop, the files go to onFiles. The page keeps a real file input
5
+ // behind its primary action (the keyboard, a phone) — no dashed box in the page.
6
+ export default function DropOverlayExample() {
7
+ const [names, setNames] = React.useState<string[]>([]);
8
+ return (
9
+ <div className="flex min-h-40 w-full flex-col items-start gap-3">
10
+ <DropOverlay label="Déposez pour vérifier" hint="PDF ou texte" accept={[".pdf", ".txt"]} onFiles={(accepted) => setNames(accepted.map((file) => file.name))} />
11
+ <label className="cursor-pointer rounded-md bg-accent px-4 py-2 text-sm font-semibold text-on-accent">
12
+ Vérifier un document
13
+ <input type="file" className="sr-only" multiple accept=".pdf,.txt" onChange={(event) => setNames(Array.from(event.target.files ?? []).map((file) => file.name))} />
14
+ </label>
15
+ <p className="text-sm text-fg-secondary">{names.length > 0 ? names.join(", ") : "Glissez un fichier n'importe où sur la fenêtre."}</p>
16
+ </div>
17
+ );
18
+ }
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from "react";
2
+ /** A named example of the @krizaka/ui registry; `defaultOpen` opens what it opens (a dialog, a menu, toasts) at load. */
3
+ declare const Example: ComponentType<{ defaultOpen?: boolean }>;
4
+ export default Example;