@krizaka/ui 2.5.0 → 2.6.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 (222) hide show
  1. package/README.md +44 -1
  2. package/dist/action-bar.d.ts +38 -0
  3. package/dist/action-bar.js +52 -0
  4. package/dist/action-bar.js.map +1 -0
  5. package/dist/argument-card.d.ts +67 -0
  6. package/dist/argument-card.js +69 -0
  7. package/dist/argument-card.js.map +1 -0
  8. package/dist/audio-player.js +1 -1
  9. package/dist/block-link-BAg4eoZk.d.ts +12 -0
  10. package/dist/blocks.css +529 -0
  11. package/dist/button.js +5 -94
  12. package/dist/button.js.map +1 -1
  13. package/dist/card-grid.d.ts +42 -0
  14. package/dist/card-grid.js +47 -0
  15. package/dist/card-grid.js.map +1 -0
  16. package/dist/chunk-2AGSO3WH.js +20 -0
  17. package/dist/chunk-2AGSO3WH.js.map +1 -0
  18. package/dist/chunk-AB5D3KBG.js +37 -0
  19. package/dist/chunk-AB5D3KBG.js.map +1 -0
  20. package/dist/{chunk-YX6CNVJA.js → chunk-CPA5CF35.js} +1 -1
  21. package/dist/chunk-CPA5CF35.js.map +1 -0
  22. package/dist/chunk-K3SWZXYT.js +92 -0
  23. package/dist/chunk-K3SWZXYT.js.map +1 -0
  24. package/dist/{chunk-XUMJA5ZI.js → chunk-X6TW3X6Y.js} +2 -2
  25. package/dist/chunk-XCBVFMNV.js +41 -0
  26. package/dist/{chunk-YX6CNVJA.js.map → chunk-XCBVFMNV.js.map} +1 -1
  27. package/dist/chunk-XVLWVTQA.js +28 -0
  28. package/dist/chunk-XVLWVTQA.js.map +1 -0
  29. package/dist/chunk-Z6FUPB3Q.js +102 -0
  30. package/dist/chunk-Z6FUPB3Q.js.map +1 -0
  31. package/dist/code-block.d.ts +42 -0
  32. package/dist/code-block.js +202 -0
  33. package/dist/code-block.js.map +1 -0
  34. package/dist/combobox.js +2 -2
  35. package/dist/cta-panel.d.ts +23 -0
  36. package/dist/cta-panel.js +20 -0
  37. package/dist/cta-panel.js.map +1 -0
  38. package/dist/data-table.js +1 -1
  39. package/dist/date-picker.js +1 -1
  40. package/dist/decision-list.d.ts +34 -0
  41. package/dist/decision-list.js +67 -0
  42. package/dist/decision-list.js.map +1 -0
  43. package/dist/file-upload.js +1 -1
  44. package/dist/filter-bar.js +1 -1
  45. package/dist/link-card.d.ts +35 -0
  46. package/dist/link-card.js +46 -0
  47. package/dist/link-card.js.map +1 -0
  48. package/dist/mascot-quote.d.ts +42 -0
  49. package/dist/mascot-quote.js +267 -0
  50. package/dist/mascot-quote.js.map +1 -0
  51. package/dist/media-capture.js +1 -1
  52. package/dist/motion.css +25 -1
  53. package/dist/page-hero.d.ts +44 -0
  54. package/dist/page-hero.js +41 -0
  55. package/dist/page-hero.js.map +1 -0
  56. package/dist/page.d.ts +116 -0
  57. package/dist/page.js +17 -0
  58. package/dist/page.js.map +1 -0
  59. package/dist/pagination.js +25 -44
  60. package/dist/pagination.js.map +1 -1
  61. package/dist/pointer-light.d.ts +20 -0
  62. package/dist/pointer-light.js +12 -0
  63. package/dist/pointer-light.js.map +1 -0
  64. package/dist/search-field.js +1 -1
  65. package/dist/section-backdrop.js +4 -22
  66. package/dist/section-backdrop.js.map +1 -1
  67. package/dist/tag-input.js +2 -2
  68. package/dist/terminal-replay.d.ts +68 -0
  69. package/dist/terminal-replay.js +231 -0
  70. package/dist/terminal-replay.js.map +1 -0
  71. package/dist/toc.d.ts +23 -0
  72. package/dist/toc.js +39 -0
  73. package/dist/toc.js.map +1 -0
  74. package/dist/video-player.js +1 -1
  75. package/package.json +192 -7
  76. package/registry/action-bar.json +205 -0
  77. package/registry/alert.json +1 -1
  78. package/registry/argument-card.json +327 -0
  79. package/registry/audio-player.json +2 -2
  80. package/registry/avatar.json +1 -1
  81. package/registry/badge.json +1 -1
  82. package/registry/button.json +5 -5
  83. package/registry/card-grid.json +221 -0
  84. package/registry/card.json +3 -3
  85. package/registry/checkbox.json +1 -1
  86. package/registry/chip-link.json +1 -1
  87. package/registry/chip.json +1 -1
  88. package/registry/code-block.json +262 -0
  89. package/registry/combobox.json +2 -2
  90. package/registry/command.json +1 -1
  91. package/registry/confirm-button.json +3 -3
  92. package/registry/countdown.json +1 -1
  93. package/registry/cta-panel.json +154 -0
  94. package/registry/data-table.json +2 -2
  95. package/registry/date-picker.json +2 -2
  96. package/registry/decision-list.json +144 -0
  97. package/registry/dialog.json +1 -1
  98. package/registry/dropdown-menu.json +1 -1
  99. package/registry/empty-state.json +1 -1
  100. package/registry/examples/action-bar/buttons.d.ts +4 -0
  101. package/registry/examples/action-bar/buttons.js +22 -0
  102. package/registry/examples/action-bar/buttons.tsx +17 -0
  103. package/registry/examples/action-bar/icons.d.ts +4 -0
  104. package/registry/examples/action-bar/icons.js +24 -0
  105. package/registry/examples/action-bar/icons.tsx +23 -0
  106. package/registry/examples/argument-card/building-block.d.ts +4 -0
  107. package/registry/examples/argument-card/building-block.js +29 -0
  108. package/registry/examples/argument-card/building-block.tsx +29 -0
  109. package/registry/examples/argument-card/grid.d.ts +4 -0
  110. package/registry/examples/argument-card/grid.js +17 -0
  111. package/registry/examples/argument-card/grid.tsx +19 -0
  112. package/registry/examples/argument-card/unfold.d.ts +4 -0
  113. package/registry/examples/argument-card/unfold.js +26 -0
  114. package/registry/examples/argument-card/unfold.tsx +21 -0
  115. package/registry/examples/card-grid/products.d.ts +4 -0
  116. package/registry/examples/card-grid/products.js +16 -0
  117. package/registry/examples/card-grid/products.tsx +13 -0
  118. package/registry/examples/card-grid/reveal.d.ts +4 -0
  119. package/registry/examples/card-grid/reveal.js +13 -0
  120. package/registry/examples/card-grid/reveal.tsx +16 -0
  121. package/registry/examples/code-block/build-tools.d.ts +4 -0
  122. package/registry/examples/code-block/build-tools.js +30 -0
  123. package/registry/examples/code-block/build-tools.tsx +25 -0
  124. package/registry/examples/code-block/file.d.ts +4 -0
  125. package/registry/examples/code-block/file.js +17 -0
  126. package/registry/examples/code-block/file.tsx +13 -0
  127. package/registry/examples/cta-panel/discuss.d.ts +4 -0
  128. package/registry/examples/cta-panel/discuss.js +31 -0
  129. package/registry/examples/cta-panel/discuss.tsx +23 -0
  130. package/registry/examples/decision-list/product.d.ts +4 -0
  131. package/registry/examples/decision-list/product.js +35 -0
  132. package/registry/examples/decision-list/product.tsx +30 -0
  133. package/registry/examples/link-card/docs-hub.d.ts +4 -0
  134. package/registry/examples/link-card/docs-hub.js +18 -0
  135. package/registry/examples/link-card/docs-hub.tsx +20 -0
  136. package/registry/examples/link-card/external.d.ts +4 -0
  137. package/registry/examples/link-card/external.js +22 -0
  138. package/registry/examples/link-card/external.tsx +16 -0
  139. package/registry/examples/link-card/stack.d.ts +4 -0
  140. package/registry/examples/link-card/stack.js +26 -0
  141. package/registry/examples/link-card/stack.tsx +21 -0
  142. package/registry/examples/mascot-quote/callout.d.ts +4 -0
  143. package/registry/examples/mascot-quote/callout.js +11 -0
  144. package/registry/examples/mascot-quote/callout.tsx +10 -0
  145. package/registry/examples/mascot-quote/inline.d.ts +4 -0
  146. package/registry/examples/mascot-quote/inline.js +11 -0
  147. package/registry/examples/mascot-quote/inline.tsx +10 -0
  148. package/registry/examples/page/backdrop.d.ts +4 -0
  149. package/registry/examples/page/backdrop.js +23 -0
  150. package/registry/examples/page/backdrop.tsx +18 -0
  151. package/registry/examples/page/facts.d.ts +4 -0
  152. package/registry/examples/page/facts.js +24 -0
  153. package/registry/examples/page/facts.tsx +21 -0
  154. package/registry/examples/page/frame.d.ts +4 -0
  155. package/registry/examples/page/frame.js +15 -0
  156. package/registry/examples/page/frame.tsx +17 -0
  157. package/registry/examples/page/sections.d.ts +4 -0
  158. package/registry/examples/page/sections.js +14 -0
  159. package/registry/examples/page/sections.tsx +15 -0
  160. package/registry/examples/page-hero/building-block.d.ts +4 -0
  161. package/registry/examples/page-hero/building-block.js +24 -0
  162. package/registry/examples/page-hero/building-block.tsx +20 -0
  163. package/registry/examples/page-hero/hub.d.ts +4 -0
  164. package/registry/examples/page-hero/hub.js +21 -0
  165. package/registry/examples/page-hero/hub.tsx +15 -0
  166. package/registry/examples/pointer-light/list.d.ts +4 -0
  167. package/registry/examples/pointer-light/list.js +16 -0
  168. package/registry/examples/pointer-light/list.tsx +14 -0
  169. package/registry/examples/terminal-replay/at-rest.d.ts +4 -0
  170. package/registry/examples/terminal-replay/at-rest.js +32 -0
  171. package/registry/examples/terminal-replay/at-rest.tsx +26 -0
  172. package/registry/examples/terminal-replay/session.d.ts +4 -0
  173. package/registry/examples/terminal-replay/session.js +34 -0
  174. package/registry/examples/terminal-replay/session.tsx +28 -0
  175. package/registry/examples/toc/reading-page.d.ts +4 -0
  176. package/registry/examples/toc/reading-page.js +21 -0
  177. package/registry/examples/toc/reading-page.tsx +21 -0
  178. package/registry/field.json +1 -1
  179. package/registry/file-upload.json +2 -2
  180. package/registry/filter-bar.json +2 -2
  181. package/registry/glow-card.json +1 -1
  182. package/registry/image-cropper.json +1 -1
  183. package/registry/index.json +241 -1
  184. package/registry/iso.json +1 -1
  185. package/registry/kbd.json +1 -1
  186. package/registry/link-card.json +279 -0
  187. package/registry/loader.json +1 -1
  188. package/registry/marquee.json +1 -1
  189. package/registry/mascot-quote.json +191 -0
  190. package/registry/mascots.json +1 -1
  191. package/registry/media-capture.json +4 -4
  192. package/registry/meter.json +1 -1
  193. package/registry/nav-bar.json +1 -1
  194. package/registry/number-ticker.json +1 -1
  195. package/registry/page-header.json +1 -1
  196. package/registry/page-hero.json +254 -0
  197. package/registry/page.json +497 -0
  198. package/registry/pagination.json +2 -2
  199. package/registry/pointer-light.json +119 -0
  200. package/registry/popover.json +1 -1
  201. package/registry/progress.json +1 -1
  202. package/registry/radio-group.json +1 -1
  203. package/registry/search-field.json +2 -2
  204. package/registry/section-backdrop.json +1 -1
  205. package/registry/separator.json +1 -1
  206. package/registry/skeleton.json +3 -3
  207. package/registry/slider.json +1 -1
  208. package/registry/slot.json +1 -1
  209. package/registry/spinner.json +1 -1
  210. package/registry/stat.json +1 -1
  211. package/registry/stepper.json +1 -1
  212. package/registry/switch.json +1 -1
  213. package/registry/tabs.json +1 -1
  214. package/registry/tag-input.json +1 -1
  215. package/registry/terminal-replay.json +317 -0
  216. package/registry/theme.json +1 -1
  217. package/registry/toast.json +1 -1
  218. package/registry/toc.json +157 -0
  219. package/registry/tooltip.json +1 -1
  220. package/registry/video-player.json +4 -4
  221. package/registry/video-trimmer.json +3 -3
  222. /package/dist/{chunk-XUMJA5ZI.js.map → chunk-X6TW3X6Y.js.map} +0 -0
@@ -0,0 +1,279 @@
1
+ {
2
+ "name": "link-card",
3
+ "type": "primitive",
4
+ "title": "Link card",
5
+ "summary": "An entry point where the whole card is one link: an icon tile, a title, one sentence and the way in — compact, the same on every page, lifting and lighting under the pointer or the focus.",
6
+ "description": "An entry point where the whole card is one link: an icon tile, a title, one sentence and the way in — compact, the same on every page, lifting and lighting under the pointer or the focus.",
7
+ "status": "beta",
8
+ "category": "blocks",
9
+ "platforms": "web",
10
+ "whenToUse": [
11
+ "The entry points of a hub: a documentation's sections, the products, the next steps of a guide.",
12
+ "Any link that deserves more than its words: what the reader finds there, in one sentence."
13
+ ],
14
+ "whenNotToUse": [
15
+ {
16
+ "when": "When the card holds several actions: a card that is a link holds no other link.",
17
+ "use": "argument-card"
18
+ },
19
+ {
20
+ "when": "For a link inside a sentence or a list of plain links.",
21
+ "use": "chip-link"
22
+ }
23
+ ],
24
+ "bestPractices": [
25
+ "One sentence of description; the title names the destination, the way in (`cta`) says the action.",
26
+ "Use the product's mark or a signature icon as `icon`, never a placeholder.",
27
+ "Pass the app's router link as `linkAs` (Next's `Link`) so internal links prefetch.",
28
+ "In a hub, keep the default `h3` titles under the section's `h2`; in a list of links, `titleAs=\"span\"`."
29
+ ],
30
+ "accessibility": {
31
+ "keyboard": [
32
+ {
33
+ "keys": "Tab",
34
+ "action": "Focuses the card, which lights and draws the focus ring like the pointer does."
35
+ }
36
+ ],
37
+ "notes": [
38
+ "The card is a single link: its accessible name is its whole text — keep it short.",
39
+ "An absolute address opens in a new tab with `rel=\"noopener noreferrer\"` and the external mark.",
40
+ "The icon and the arrow are decorative; the lift and the light stop under `prefers-reduced-motion`."
41
+ ]
42
+ },
43
+ "related": [
44
+ "card-grid",
45
+ "glow-card",
46
+ "chip-link"
47
+ ],
48
+ "web": {
49
+ "entry": "@krizaka/ui/link-card",
50
+ "import": "import { LinkCard } from \"@krizaka/ui/link-card\";",
51
+ "props": [
52
+ {
53
+ "component": "LinkComponent",
54
+ "description": "The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children.",
55
+ "props": []
56
+ },
57
+ {
58
+ "component": "LinkCard",
59
+ "description": "An entry point: the whole card is one link — icon, title, sentence, the way in. Lifts and lights under the pointer.",
60
+ "props": [
61
+ {
62
+ "name": "href",
63
+ "type": "string",
64
+ "default": null,
65
+ "description": "Where the card leads. An absolute URL opens in a new tab, with the external mark.",
66
+ "required": true
67
+ },
68
+ {
69
+ "name": "title",
70
+ "type": "ReactNode",
71
+ "default": null,
72
+ "description": "The title: the name of the destination.",
73
+ "required": true
74
+ },
75
+ {
76
+ "name": "cta",
77
+ "type": "ReactNode",
78
+ "default": null,
79
+ "description": "The way in, under the text, with an arrow: `Open`, `Read the guide`.",
80
+ "required": false
81
+ },
82
+ {
83
+ "name": "description",
84
+ "type": "ReactNode",
85
+ "default": null,
86
+ "description": "One sentence: what the reader finds there.",
87
+ "required": false
88
+ },
89
+ {
90
+ "name": "extra",
91
+ "type": "ReactNode",
92
+ "default": null,
93
+ "description": "Under the text, before the way in: facts (`Facts`), badges. Never another link — the card is one.",
94
+ "required": false
95
+ },
96
+ {
97
+ "name": "icon",
98
+ "type": "ReactNode",
99
+ "default": null,
100
+ "description": "The icon tile on the left (a product mark, a signature icon): decorative, the title names the link.",
101
+ "required": false
102
+ },
103
+ {
104
+ "name": "layout",
105
+ "type": "\"row\" | \"stack\"",
106
+ "default": "row",
107
+ "description": "`row`: the icon beside the text (compact, the default); `stack`: the icon above it.",
108
+ "required": false
109
+ },
110
+ {
111
+ "name": "linkAs",
112
+ "type": "LinkComponent",
113
+ "default": null,
114
+ "description": "The app's link component for internal addresses (Next's `Link`); an `<a>` otherwise.",
115
+ "required": false
116
+ },
117
+ {
118
+ "name": "meta",
119
+ "type": "ReactNode",
120
+ "default": null,
121
+ "description": "A short mono line above the title (a category, a version).",
122
+ "required": false
123
+ },
124
+ {
125
+ "name": "titleAs",
126
+ "type": "\"h2\" | \"h3\" | \"h4\" | \"span\"",
127
+ "default": "h3",
128
+ "description": "The title's element: a heading when the cards are the content of a section (a hub), `span` inside a list of links.",
129
+ "required": false
130
+ }
131
+ ]
132
+ }
133
+ ],
134
+ "examples": [
135
+ {
136
+ "name": "docs-hub",
137
+ "title": "A documentation hub",
138
+ "description": "Three compact cards in a grid: a mark, a title, a sentence, `Open`.",
139
+ "path": "examples/link-card/docs-hub.tsx",
140
+ "module": "@krizaka/ui/registry/examples/link-card/docs-hub",
141
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\nimport { LinkCard } from \"@krizaka/ui/link-card\";\n\nconst shortcuts = [\n { id: \"cli\", logo: \"orazaka\", title: \"The CLI\", text: \"npx orazaka install, start, dev — then every command and option.\" },\n { id: \"packs\", logo: \"orazaka\", title: \"Packs & Studios\", text: \"The business offers Orazaka installs without code.\" },\n { id: \"admin\", logo: \"orochia\", title: \"Orochia admin console\", text: \"Verification, moderation, payouts — behind four gates.\" },\n] as const;\n\n// The entry points of a documentation hub: compact cards, the whole card one link. The pointer lights the card it is on.\nexport default function LinkCardDocsHub() {\n return (\n <CardGrid className=\"w-full max-w-4xl\" min={260} reveal={false}>\n {shortcuts.map((s) => (\n <LinkCard key={s.id} href={`#${s.id}`} icon={<ProductLogo id={s.logo} size={24} animated={false} />} title={s.title} description={s.text} cta=\"Open\" />\n ))}\n </CardGrid>\n );\n}\n"
142
+ },
143
+ {
144
+ "name": "stack",
145
+ "title": "Stacked, with facts",
146
+ "description": "`layout=\"stack\"`, a category above the title and facts under the text.",
147
+ "path": "examples/link-card/stack.tsx",
148
+ "module": "@krizaka/ui/registry/examples/link-card/stack",
149
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { LinkCard } from \"@krizaka/ui/link-card\";\nimport { Facts } from \"@krizaka/ui/page\";\n\n// `layout=\"stack\"`: the icon above the text, for a few large entry points (the products). `meta` names the category,\n// `extra` carries facts — never another link: the card is one.\nexport default function LinkCardStack() {\n return (\n <LinkCard\n className=\"max-w-sm\"\n layout=\"stack\"\n href=\"#orazaka\"\n icon={<ProductLogo id=\"orazaka\" size={26} animated={false} />}\n meta=\"Product\"\n title=\"Orazaka\"\n description=\"The sovereign AI engine: chat, image, video and voice on your own servers.\"\n extra={<Facts items={[{ label: \"Self-hosted\", tone: \"ok\" }, { label: \"Apache-2.0\" }]} />}\n cta=\"Overview\"\n />\n );\n}\n"
150
+ },
151
+ {
152
+ "name": "external",
153
+ "title": "An external link",
154
+ "description": "An absolute address: a new tab and the external mark.",
155
+ "path": "examples/link-card/external.tsx",
156
+ "module": "@krizaka/ui/registry/examples/link-card/external",
157
+ "code": "import { ProductLogo } from \"@krizaka/ui\";\nimport { LinkCard } from \"@krizaka/ui/link-card\";\n\n// An absolute address opens in a new tab and wears the external mark instead of the arrow.\nexport default function LinkCardExternal() {\n return (\n <LinkCard\n className=\"max-w-sm\"\n href=\"https://github.com/krizaka/krizaka-ui\"\n icon={<ProductLogo id=\"krizaka\" size={24} animated={false} />}\n title=\"krizaka-ui on GitHub\"\n description=\"The sources, the issues, the discussions.\"\n cta=\"Open the repository\"\n />\n );\n}\n"
158
+ }
159
+ ]
160
+ },
161
+ "native": null,
162
+ "files": [
163
+ {
164
+ "path": "block-link.tsx",
165
+ "content": "// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} {...props} />;\n}\n"
166
+ },
167
+ {
168
+ "path": "glyphs.tsx",
169
+ "content": "// The small line glyphs the data and media primitives draw (play, volume, search, chevrons…): decorative, 24-unit\n// box, `currentColor`, sized by the caller's class. Shared by the entries that need them; never exported on its own —\n// a product draws its own icons with @krizaka/icons.\nimport type * as React from \"react\";\n\ntype GlyphProps = { className?: string };\n\nfunction Glyph({ className = \"h-4 w-4\", fill, children }: GlyphProps & { fill?: boolean; children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n className={className}\n fill={fill ? \"currentColor\" : \"none\"}\n stroke={fill ? \"none\" : \"currentColor\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n focusable=\"false\"\n >\n {children}\n </svg>\n );\n}\n\nexport const PlayGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <path d=\"M8 5.5v13a1 1 0 0 0 1.5.86l10.4-6.5a1 1 0 0 0 0-1.72L9.5 4.64A1 1 0 0 0 8 5.5Z\" />\n </Glyph>\n);\nexport const PauseGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n </Glyph>\n);\nexport const VolumeGlyph = ({ muted, ...p }: GlyphProps & { muted?: boolean }) => (\n <Glyph {...p}>\n <path d=\"M11 5 6 9H3v6h3l5 4V5Z\" />\n {muted ? <path d=\"m22 9-6 6m0-6 6 6\" /> : <path d=\"M15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13\" />}\n </Glyph>\n);\nexport const FullscreenGlyph = ({ exit, ...p }: GlyphProps & { exit?: boolean }) => (\n <Glyph {...p}>\n {exit ? <path d=\"M9 4v5H4m11-5v5h5M9 20v-5H4m11 5v-5h5\" /> : <path d=\"M4 9V4h5m6 0h5v5M4 15v5h5m11-5v5h-5\" />}\n </Glyph>\n);\nexport const CaptionsGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"M10 10.5a2 2 0 1 0 0 3M17 10.5a2 2 0 1 0 0 3\" />\n </Glyph>\n);\nexport const PipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <rect x=\"12\" y=\"12\" width=\"6\" height=\"4\" rx=\"1\" />\n </Glyph>\n);\nexport const SearchGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <path d=\"m20 20-3.5-3.5\" />\n </Glyph>\n);\nexport const CloseGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </Glyph>\n);\nexport const ChevronGlyph = ({ direction = \"down\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" | \"up\" | \"down\" }) => (\n <Glyph {...p}>\n <path d={{ left: \"m15 6-6 6 6 6\", right: \"m9 6 6 6-6 6\", up: \"m6 15 6-6 6 6\", down: \"m6 9 6 6 6-6\" }[direction]} />\n </Glyph>\n);\nexport const CheckGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Glyph>\n);\nexport const PlusGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 5v14M5 12h14\" />\n </Glyph>\n);\nexport const CalendarGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\" />\n <path d=\"M3 10h18M8 3v4M16 3v4\" />\n </Glyph>\n);\nexport const UploadGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 16V4m0 0L7 9m5-5 5 5\" />\n <path d=\"M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\" />\n </Glyph>\n);\nexport const FileGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5Z\" />\n <path d=\"M14 3v5h5\" />\n </Glyph>\n);\nexport const CameraGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 8h3l2-3h6l2 3h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z\" />\n <circle cx=\"12\" cy=\"13.5\" r=\"3.5\" />\n </Glyph>\n);\nexport const FlipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 0 1 14-5.3M20 12a8 8 0 0 1-14 5.3\" />\n <path d=\"M18 3v4h-4M6 21v-4h4\" />\n </Glyph>\n);\nexport const RetryGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 1 0 2.3-5.7L4 8.5\" />\n <path d=\"M4 4v4.5h4.5\" />\n </Glyph>\n);\nexport const SortGlyph = ({ direction, ...p }: GlyphProps & { direction?: \"ascending\" | \"descending\" }) => (\n <Glyph {...p}>\n {direction === \"ascending\" ? <path d=\"m7 14 5-5 5 5\" /> : direction === \"descending\" ? <path d=\"m7 10 5 5 5-5\" /> : <path d=\"m8 9 4-4 4 4M8 15l4 4 4-4\" />}\n </Glyph>\n);\nexport const ArrowGlyph = ({ direction = \"right\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" }) => (\n <Glyph {...p}>\n <path d={direction === \"left\" ? \"M19 12H5m0 0 6-6m-6 6 6 6\" : \"M5 12h14m0 0-6-6m6 6-6 6\"} />\n </Glyph>\n);\nexport const ExternalGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 4h6v6M20 4l-9 9\" />\n <path d=\"M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4\" />\n </Glyph>\n);\nexport const WarningGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 4 2.5 20h19L12 4Z\" />\n <path d=\"M12 10v4M12 17.2v.1\" />\n </Glyph>\n);\nexport const CopyGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"9\" y=\"9\" width=\"11\" height=\"11\" rx=\"2\" />\n <path d=\"M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3\" />\n </Glyph>\n);\n"
170
+ },
171
+ {
172
+ "path": "link-card/index.ts",
173
+ "content": "/** @krizaka/ui/link-card — `LinkCard`: an entry point, the whole card one link (icon, title, sentence, the way in). Server-safe. */\nexport type { LinkComponent } from \"../block-link\";\nexport { LinkCard, type LinkCardProps } from \"./link-card\";\n"
174
+ },
175
+ {
176
+ "path": "link-card/link-card.tsx",
177
+ "content": "// Server-safe. A card that leads somewhere (blocks.css): the whole card is the link — an icon, a title, one sentence,\n// the way in. Compact, one look for every entry point of a page (a documentation hub, the products, the next step).\nimport type * as React from \"react\";\n\nimport { BlockLink, isExternal, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { ArrowGlyph, ExternalGlyph } from \"../glyphs\";\n\nexport type LinkCardProps = Omit<React.ComponentProps<\"a\">, \"title\" | \"href\"> & {\n /** Where the card leads. An absolute URL opens in a new tab, with the external mark. */\n href: string;\n /** The title: the name of the destination. */\n title: React.ReactNode;\n /** One sentence: what the reader finds there. */\n description?: React.ReactNode;\n /** The icon tile on the left (a product mark, a signature icon): decorative, the title names the link. */\n icon?: React.ReactNode;\n /** A short mono line above the title (a category, a version). */\n meta?: React.ReactNode;\n /** The way in, under the text, with an arrow: `Open`, `Read the guide`. */\n cta?: React.ReactNode;\n /** Under the text, before the way in: facts (`Facts`), badges. Never another link — the card is one. */\n extra?: React.ReactNode;\n /**\n * The title's element: a heading when the cards are the content of a section (a hub), `span` inside a list of links.\n * @default \"h3\"\n */\n titleAs?: \"h2\" | \"h3\" | \"h4\" | \"span\";\n /**\n * `row`: the icon beside the text (compact, the default); `stack`: the icon above it.\n * @default \"row\"\n */\n layout?: \"row\" | \"stack\";\n /** The app's link component for internal addresses (Next's `Link`); an `<a>` otherwise. */\n linkAs?: LinkComponent;\n};\n\n/** An entry point: the whole card is one link — icon, title, sentence, the way in. Lifts and lights under the pointer. */\nexport function LinkCard({ href, title, description, icon, meta, cta, extra, titleAs: Title = \"h3\", layout = \"row\", linkAs, className, ...props }: LinkCardProps) {\n const external = isExternal(href);\n return (\n <BlockLink\n href={href}\n linkAs={linkAs}\n external={external}\n className={cn(\"kz-block-card kz-link-card\", className)}\n data-kz-light=\"\"\n data-layout={layout === \"row\" ? undefined : layout}\n {...props}\n >\n {icon && (\n <span className=\"kz-block-icon\" aria-hidden>\n {icon}\n </span>\n )}\n <div className=\"kz-link-card-body\">\n {meta && <p className=\"kz-link-card-meta\">{meta}</p>}\n <Title className=\"kz-link-card-title\">{title}</Title>\n {description && <p className=\"kz-link-card-text\">{description}</p>}\n {extra && <div className=\"kz-link-card-extra\">{extra}</div>}\n {(cta || external) && (\n <span className=\"kz-link-card-cta\">\n {cta}\n {external ? <ExternalGlyph className=\"h-3.5 w-3.5\" /> : <ArrowGlyph className=\"h-3.5 w-3.5\" />}\n </span>\n )}\n </div>\n </BlockLink>\n );\n}\n"
178
+ },
179
+ {
180
+ "path": "link-card/meta.ts",
181
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Link card\",\n summary:\n \"An entry point where the whole card is one link: an icon tile, a title, one sentence and the way in — compact, the same on every page, lifting and lighting under the pointer or the focus.\",\n status: \"beta\",\n category: \"blocks\",\n platforms: \"web\",\n whenToUse: [\n \"The entry points of a hub: a documentation's sections, the products, the next steps of a guide.\",\n \"Any link that deserves more than its words: what the reader finds there, in one sentence.\",\n ],\n whenNotToUse: [\n { when: \"When the card holds several actions: a card that is a link holds no other link.\", use: \"argument-card\" },\n { when: \"For a link inside a sentence or a list of plain links.\", use: \"chip-link\" },\n ],\n bestPractices: [\n \"One sentence of description; the title names the destination, the way in (`cta`) says the action.\",\n \"Use the product's mark or a signature icon as `icon`, never a placeholder.\",\n \"Pass the app's router link as `linkAs` (Next's `Link`) so internal links prefetch.\",\n \"In a hub, keep the default `h3` titles under the section's `h2`; in a list of links, `titleAs=\\\"span\\\"`.\",\n ],\n accessibility: {\n keyboard: [{ keys: \"Tab\", action: \"Focuses the card, which lights and draws the focus ring like the pointer does.\" }],\n notes: [\n \"The card is a single link: its accessible name is its whole text — keep it short.\",\n \"An absolute address opens in a new tab with `rel=\\\"noopener noreferrer\\\"` and the external mark.\",\n \"The icon and the arrow are decorative; the lift and the light stop under `prefers-reduced-motion`.\",\n ],\n },\n related: [\"card-grid\", \"glow-card\", \"chip-link\"],\n web: {\n imports: [\"LinkCard\"],\n examples: [\n { name: \"docs-hub\", title: \"A documentation hub\", description: \"Three compact cards in a grid: a mark, a title, a sentence, `Open`.\" },\n { name: \"stack\", title: \"Stacked, with facts\", description: \"`layout=\\\"stack\\\"`, a category above the title and facts under the text.\" },\n { name: \"external\", title: \"An external link\", description: \"An absolute address: a new tab and the external mark.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
182
+ },
183
+ {
184
+ "path": "meta.ts",
185
+ "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 krizaka.com renders as\n// /docs/ui/<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 | \"action-bar\"\n | \"alert\"\n | \"argument-card\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"card-grid\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"cta-panel\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"link-card\"\n | \"loader\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"pointer-light\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\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/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\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 */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layout\" | \"foundations\";\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 */\nexport interface Example {\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/** 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 readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\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"
186
+ }
187
+ ],
188
+ "dependencies": [],
189
+ "registryDependencies": [
190
+ "cn"
191
+ ],
192
+ "demo": {
193
+ "path": "examples/link-card/docs-hub.tsx",
194
+ "content": "import { ProductLogo } from \"@krizaka/ui\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\nimport { LinkCard } from \"@krizaka/ui/link-card\";\n\nconst shortcuts = [\n { id: \"cli\", logo: \"orazaka\", title: \"The CLI\", text: \"npx orazaka install, start, dev — then every command and option.\" },\n { id: \"packs\", logo: \"orazaka\", title: \"Packs & Studios\", text: \"The business offers Orazaka installs without code.\" },\n { id: \"admin\", logo: \"orochia\", title: \"Orochia admin console\", text: \"Verification, moderation, payouts — behind four gates.\" },\n] as const;\n\n// The entry points of a documentation hub: compact cards, the whole card one link. The pointer lights the card it is on.\nexport default function LinkCardDocsHub() {\n return (\n <CardGrid className=\"w-full max-w-4xl\" min={260} reveal={false}>\n {shortcuts.map((s) => (\n <LinkCard key={s.id} href={`#${s.id}`} icon={<ProductLogo id={s.logo} size={24} animated={false} />} title={s.title} description={s.text} cta=\"Open\" />\n ))}\n </CardGrid>\n );\n}\n"
195
+ },
196
+ "props": [
197
+ {
198
+ "component": "LinkComponent",
199
+ "description": "The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children.",
200
+ "props": []
201
+ },
202
+ {
203
+ "component": "LinkCard",
204
+ "description": "An entry point: the whole card is one link — icon, title, sentence, the way in. Lifts and lights under the pointer.",
205
+ "props": [
206
+ {
207
+ "name": "href",
208
+ "type": "string",
209
+ "default": null,
210
+ "description": "Where the card leads. An absolute URL opens in a new tab, with the external mark.",
211
+ "required": true
212
+ },
213
+ {
214
+ "name": "title",
215
+ "type": "ReactNode",
216
+ "default": null,
217
+ "description": "The title: the name of the destination.",
218
+ "required": true
219
+ },
220
+ {
221
+ "name": "cta",
222
+ "type": "ReactNode",
223
+ "default": null,
224
+ "description": "The way in, under the text, with an arrow: `Open`, `Read the guide`.",
225
+ "required": false
226
+ },
227
+ {
228
+ "name": "description",
229
+ "type": "ReactNode",
230
+ "default": null,
231
+ "description": "One sentence: what the reader finds there.",
232
+ "required": false
233
+ },
234
+ {
235
+ "name": "extra",
236
+ "type": "ReactNode",
237
+ "default": null,
238
+ "description": "Under the text, before the way in: facts (`Facts`), badges. Never another link — the card is one.",
239
+ "required": false
240
+ },
241
+ {
242
+ "name": "icon",
243
+ "type": "ReactNode",
244
+ "default": null,
245
+ "description": "The icon tile on the left (a product mark, a signature icon): decorative, the title names the link.",
246
+ "required": false
247
+ },
248
+ {
249
+ "name": "layout",
250
+ "type": "\"row\" | \"stack\"",
251
+ "default": "row",
252
+ "description": "`row`: the icon beside the text (compact, the default); `stack`: the icon above it.",
253
+ "required": false
254
+ },
255
+ {
256
+ "name": "linkAs",
257
+ "type": "LinkComponent",
258
+ "default": null,
259
+ "description": "The app's link component for internal addresses (Next's `Link`); an `<a>` otherwise.",
260
+ "required": false
261
+ },
262
+ {
263
+ "name": "meta",
264
+ "type": "ReactNode",
265
+ "default": null,
266
+ "description": "A short mono line above the title (a category, a version).",
267
+ "required": false
268
+ },
269
+ {
270
+ "name": "titleAs",
271
+ "type": "\"h2\" | \"h3\" | \"h4\" | \"span\"",
272
+ "default": "h3",
273
+ "description": "The title's element: a heading when the cards are the content of a section (a hub), `span` inside a list of links.",
274
+ "required": false
275
+ }
276
+ ]
277
+ }
278
+ ]
279
+ }
@@ -250,7 +250,7 @@
250
250
  },
251
251
  {
252
252
  "path": "meta.ts",
253
- "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 krizaka.com renders as\n// /docs/ui/<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 | \"alert\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"data-table\"\n | \"date-picker\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"loader\"\n | \"marquee\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page-header\"\n | \"pagination\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\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/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. `media`: video, sound, camera, files, cropping. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"layout\" | \"foundations\";\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 */\nexport interface Example {\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/** 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 readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\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"
253
+ "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 krizaka.com renders as\n// /docs/ui/<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 | \"action-bar\"\n | \"alert\"\n | \"argument-card\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"card-grid\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"cta-panel\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"link-card\"\n | \"loader\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"pointer-light\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\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/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\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 */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layout\" | \"foundations\";\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 */\nexport interface Example {\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/** 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 readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\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"
254
254
  }
255
255
  ],
256
256
  "dependencies": [
@@ -147,7 +147,7 @@
147
147
  },
148
148
  {
149
149
  "path": "meta.ts",
150
- "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 krizaka.com renders as\n// /docs/ui/<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 | \"alert\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"data-table\"\n | \"date-picker\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"loader\"\n | \"marquee\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page-header\"\n | \"pagination\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\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/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. `media`: video, sound, camera, files, cropping. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"layout\" | \"foundations\";\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 */\nexport interface Example {\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/** 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 readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\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"
150
+ "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 krizaka.com renders as\n// /docs/ui/<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 | \"action-bar\"\n | \"alert\"\n | \"argument-card\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"card-grid\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"cta-panel\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"link-card\"\n | \"loader\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"pointer-light\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\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/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\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 */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layout\" | \"foundations\";\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 */\nexport interface Example {\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/** 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 readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\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"
151
151
  }
152
152
  ],
153
153
  "dependencies": [],
@@ -0,0 +1,191 @@
1
+ {
2
+ "name": "mascot-quote",
3
+ "type": "primitive",
4
+ "title": "Mascot quote",
5
+ "summary": "A rule, a promise or a decision told by a bird: the sentence in a speech bubble, the bird under its tail and who speaks — `inline` in a card, `callout` alone in a section.",
6
+ "description": "A rule, a promise or a decision told by a bird: the sentence in a speech bubble, the bird under its tail and who speaks — `inline` in a card, `callout` alone in a section.",
7
+ "status": "beta",
8
+ "category": "blocks",
9
+ "platforms": "web",
10
+ "whenToUse": [
11
+ "To state the rule a feature stands for (the falcon watches, the owl reads, the duck builds, the flamingo answers or gets paid, the pigeon delivers).",
12
+ "A promise that deserves its own moment in a section (`callout`)."
13
+ ],
14
+ "whenNotToUse": [
15
+ {
16
+ "when": "For a bird that only decorates: a bird carries a promise, or it is not there.",
17
+ "use": "mascots"
18
+ },
19
+ {
20
+ "when": "For a status or a warning the reader must act on.",
21
+ "use": "alert"
22
+ }
23
+ ],
24
+ "bestPractices": [
25
+ "One bird per idea, the same bird for the same idea everywhere.",
26
+ "One sentence, said as a rule: short, in the present tense.",
27
+ "The label says who speaks (`The falcon's rule`): words as props."
28
+ ],
29
+ "accessibility": {
30
+ "keyboard": [],
31
+ "notes": [
32
+ "A `figure` with a `blockquote` and its `figcaption`: read as a quote and who says it.",
33
+ "The bird is decorative (`aria-hidden`); its idle loop pauses off screen and stops under `prefers-reduced-motion`."
34
+ ]
35
+ },
36
+ "related": [
37
+ "mascots",
38
+ "argument-card",
39
+ "alert"
40
+ ],
41
+ "web": {
42
+ "entry": "@krizaka/ui/mascot-quote",
43
+ "import": "import { MascotQuote } from \"@krizaka/ui/mascot-quote\";",
44
+ "props": [
45
+ {
46
+ "component": "MascotQuote",
47
+ "description": "A sentence told by a bird: a speech bubble, the bird under its tail, who speaks. The bird is decorative.",
48
+ "props": [
49
+ {
50
+ "name": "bird",
51
+ "type": "\"falcon\" | \"owl\" | \"duck\" | \"flamingo\" | \"pigeon\"",
52
+ "default": null,
53
+ "description": "The bird that speaks — the one whose idea it is.",
54
+ "required": true
55
+ },
56
+ {
57
+ "name": "children",
58
+ "type": "ReactNode",
59
+ "default": null,
60
+ "description": "The sentence: the rule, the promise.",
61
+ "required": true
62
+ },
63
+ {
64
+ "name": "label",
65
+ "type": "ReactNode",
66
+ "default": null,
67
+ "description": "Who speaks, under the bubble: `The falcon's rule`.",
68
+ "required": true
69
+ },
70
+ {
71
+ "name": "animated",
72
+ "type": "boolean",
73
+ "default": null,
74
+ "description": "The bird's idle loop (it pauses off screen and stops under reduced motion). Defaults to `true` for a callout.",
75
+ "required": false
76
+ },
77
+ {
78
+ "name": "mood",
79
+ "type": "\"success\" | \"error\" | \"empty\" | \"welcome\" | \"thinking\"",
80
+ "default": "thinking",
81
+ "description": "Its mood.",
82
+ "required": false
83
+ },
84
+ {
85
+ "name": "variant",
86
+ "type": "\"inline\" | \"callout\"",
87
+ "default": "inline",
88
+ "description": "`inline` inside a card (small, the bird answers the pointer); `callout` alone in a section (larger, the bird alive).",
89
+ "required": false
90
+ }
91
+ ]
92
+ }
93
+ ],
94
+ "examples": [
95
+ {
96
+ "name": "inline",
97
+ "title": "Inline",
98
+ "description": "The falcon's rule, small, beside a paragraph or inside a card.",
99
+ "path": "examples/mascot-quote/inline.tsx",
100
+ "module": "@krizaka/ui/registry/examples/mascot-quote/inline",
101
+ "code": "import { MascotQuote } from \"@krizaka/ui/mascot-quote\";\n\n// `inline`: a rule inside a card or beside a paragraph — small, the bird still (it hops once under the pointer).\nexport default function MascotQuoteInline() {\n return (\n <MascotQuote className=\"max-w-sm\" bird=\"falcon\" label=\"The falcon's rule\">\n Nothing crosses the walls: no prompt, no file, no metric.\n </MascotQuote>\n );\n}\n"
102
+ },
103
+ {
104
+ "name": "callout",
105
+ "title": "Callout",
106
+ "description": "The owl's promise, alone in a section, the bird alive.",
107
+ "path": "examples/mascot-quote/callout.tsx",
108
+ "module": "@krizaka/ui/registry/examples/mascot-quote/callout",
109
+ "code": "import { MascotQuote } from \"@krizaka/ui/mascot-quote\";\n\n// `callout`: a promise alone in a section — larger, the bird alive (its loop pauses off screen and under reduced motion).\nexport default function MascotQuoteCallout() {\n return (\n <MascotQuote className=\"max-w-2xl\" variant=\"callout\" bird=\"owl\" mood=\"welcome\" label=\"The owl's promise\">\n Every personal record stays in Québec, and you can read who touched it — Law 25, by design.\n </MascotQuote>\n );\n}\n"
110
+ }
111
+ ]
112
+ },
113
+ "native": null,
114
+ "files": [
115
+ {
116
+ "path": "mascot-quote/index.ts",
117
+ "content": "/** @krizaka/ui/mascot-quote — `MascotQuote`: a rule told by a bird, in a speech bubble. Client (the bird). */\nexport type { MascotBird, MascotMood } from \"../mascots/geometry\";\nexport { MascotQuote, type MascotQuoteProps } from \"./mascot-quote\";\n"
118
+ },
119
+ {
120
+ "path": "mascot-quote/mascot-quote.tsx",
121
+ "content": "// Client (the bird has an id per instance). A rule, a promise or a decision told by a bird (blocks.css): the sentence in\n// a speech bubble — an opening quote mark, the hue around it — and under its tail the bird and who speaks. One bird per\n// idea (Mascot's rule): the falcon watches, the owl reads, the duck builds, the flamingo answers or gets paid, the\n// pigeon delivers.\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { type MascotBird, type MascotMood } from \"../mascots/geometry\";\nimport { Mascot } from \"../mascots/mascot\";\n\nexport type MascotQuoteProps = Omit<React.HTMLAttributes<HTMLElement>, \"children\"> & {\n /** The bird that speaks — the one whose idea it is. */\n bird: MascotBird;\n /**\n * Its mood.\n * @default \"thinking\"\n */\n mood?: MascotMood;\n /** Who speaks, under the bubble: `The falcon's rule`. */\n label: React.ReactNode;\n /** The sentence: the rule, the promise. */\n children: React.ReactNode;\n /**\n * `inline` inside a card (small, the bird answers the pointer); `callout` alone in a section (larger, the bird alive).\n * @default \"inline\"\n */\n variant?: \"inline\" | \"callout\";\n /** The bird's idle loop (it pauses off screen and stops under reduced motion). Defaults to `true` for a callout. */\n animated?: boolean;\n};\n\n/** A sentence told by a bird: a speech bubble, the bird under its tail, who speaks. The bird is decorative. */\nexport function MascotQuote({ bird, mood = \"thinking\", label, children, variant = \"inline\", animated, className, ...props }: MascotQuoteProps) {\n const callout = variant === \"callout\";\n return (\n <figure className={cn(\"kz-quote\", className)} data-variant={callout ? \"callout\" : undefined} {...props}>\n <blockquote>\n <p>{children}</p>\n </blockquote>\n <figcaption>\n <Mascot bird={bird} mood={mood} size={callout ? 72 : 44} animated={animated ?? callout} className=\"kz-quote-bird\" aria-hidden />\n <span>{label}</span>\n </figcaption>\n </figure>\n );\n}\n"
122
+ },
123
+ {
124
+ "path": "mascot-quote/meta.ts",
125
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Mascot quote\",\n summary:\n \"A rule, a promise or a decision told by a bird: the sentence in a speech bubble, the bird under its tail and who speaks — `inline` in a card, `callout` alone in a section.\",\n status: \"beta\",\n category: \"blocks\",\n platforms: \"web\",\n whenToUse: [\n \"To state the rule a feature stands for (the falcon watches, the owl reads, the duck builds, the flamingo answers or gets paid, the pigeon delivers).\",\n \"A promise that deserves its own moment in a section (`callout`).\",\n ],\n whenNotToUse: [\n { when: \"For a bird that only decorates: a bird carries a promise, or it is not there.\", use: \"mascots\" },\n { when: \"For a status or a warning the reader must act on.\", use: \"alert\" },\n ],\n bestPractices: [\n \"One bird per idea, the same bird for the same idea everywhere.\",\n \"One sentence, said as a rule: short, in the present tense.\",\n \"The label says who speaks (`The falcon's rule`): words as props.\",\n ],\n accessibility: {\n keyboard: [],\n notes: [\n \"A `figure` with a `blockquote` and its `figcaption`: read as a quote and who says it.\",\n \"The bird is decorative (`aria-hidden`); its idle loop pauses off screen and stops under `prefers-reduced-motion`.\",\n ],\n },\n related: [\"mascots\", \"argument-card\", \"alert\"],\n web: {\n imports: [\"MascotQuote\"],\n examples: [\n { name: \"inline\", title: \"Inline\", description: \"The falcon's rule, small, beside a paragraph or inside a card.\" },\n { name: \"callout\", title: \"Callout\", description: \"The owl's promise, alone in a section, the bird alive.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
126
+ },
127
+ {
128
+ "path": "meta.ts",
129
+ "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 krizaka.com renders as\n// /docs/ui/<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 | \"action-bar\"\n | \"alert\"\n | \"argument-card\"\n | \"audio-player\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"card-grid\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"cta-panel\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"glow-card\"\n | \"image-cropper\"\n | \"iso\"\n | \"kbd\"\n | \"link-card\"\n | \"loader\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascots\"\n | \"media-capture\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"pointer-light\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"tag-input\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"txt\"\n | \"video-player\"\n | \"video-trimmer\";\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/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\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 */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layout\" | \"foundations\";\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 */\nexport interface Example {\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/** 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 readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\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"
130
+ }
131
+ ],
132
+ "dependencies": [],
133
+ "registryDependencies": [
134
+ "cn",
135
+ "mascots"
136
+ ],
137
+ "demo": {
138
+ "path": "examples/mascot-quote/inline.tsx",
139
+ "content": "import { MascotQuote } from \"@krizaka/ui/mascot-quote\";\n\n// `inline`: a rule inside a card or beside a paragraph — small, the bird still (it hops once under the pointer).\nexport default function MascotQuoteInline() {\n return (\n <MascotQuote className=\"max-w-sm\" bird=\"falcon\" label=\"The falcon's rule\">\n Nothing crosses the walls: no prompt, no file, no metric.\n </MascotQuote>\n );\n}\n"
140
+ },
141
+ "props": [
142
+ {
143
+ "component": "MascotQuote",
144
+ "description": "A sentence told by a bird: a speech bubble, the bird under its tail, who speaks. The bird is decorative.",
145
+ "props": [
146
+ {
147
+ "name": "bird",
148
+ "type": "\"falcon\" | \"owl\" | \"duck\" | \"flamingo\" | \"pigeon\"",
149
+ "default": null,
150
+ "description": "The bird that speaks — the one whose idea it is.",
151
+ "required": true
152
+ },
153
+ {
154
+ "name": "children",
155
+ "type": "ReactNode",
156
+ "default": null,
157
+ "description": "The sentence: the rule, the promise.",
158
+ "required": true
159
+ },
160
+ {
161
+ "name": "label",
162
+ "type": "ReactNode",
163
+ "default": null,
164
+ "description": "Who speaks, under the bubble: `The falcon's rule`.",
165
+ "required": true
166
+ },
167
+ {
168
+ "name": "animated",
169
+ "type": "boolean",
170
+ "default": null,
171
+ "description": "The bird's idle loop (it pauses off screen and stops under reduced motion). Defaults to `true` for a callout.",
172
+ "required": false
173
+ },
174
+ {
175
+ "name": "mood",
176
+ "type": "\"success\" | \"error\" | \"empty\" | \"welcome\" | \"thinking\"",
177
+ "default": "thinking",
178
+ "description": "Its mood.",
179
+ "required": false
180
+ },
181
+ {
182
+ "name": "variant",
183
+ "type": "\"inline\" | \"callout\"",
184
+ "default": "inline",
185
+ "description": "`inline` inside a card (small, the bird answers the pointer); `callout` alone in a section (larger, the bird alive).",
186
+ "required": false
187
+ }
188
+ ]
189
+ }
190
+ ]
191
+ }