@krizaka/ui 3.52.0 → 3.53.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 (204) hide show
  1. package/dist/action-bar.js +1 -1
  2. package/dist/argument-card.js +2 -2
  3. package/dist/blocks.css +108 -0
  4. package/dist/chapter.d.ts +89 -0
  5. package/dist/chapter.js +123 -0
  6. package/dist/chapter.js.map +1 -0
  7. package/dist/choice-grid.js +1 -1
  8. package/dist/choice-grid.js.map +1 -1
  9. package/dist/{chunk-IBDTAMPF.js → chunk-7JG3VR4C.js} +2 -2
  10. package/dist/{chunk-C7LTF5CC.js → chunk-ENOS6ETI.js} +2 -2
  11. package/dist/{chunk-C7LTF5CC.js.map → chunk-ENOS6ETI.js.map} +1 -1
  12. package/dist/{chunk-2AGSO3WH.js → chunk-FVGFPB73.js} +2 -2
  13. package/dist/{chunk-2AGSO3WH.js.map → chunk-FVGFPB73.js.map} +1 -1
  14. package/dist/cover-hero.js +1 -1
  15. package/dist/link-card.js +2 -2
  16. package/dist/media-grid.js +1 -1
  17. package/dist/media-grid.js.map +1 -1
  18. package/dist/page-hero.js +1 -1
  19. package/dist/page-index.js +1 -1
  20. package/dist/service-card.js +1 -1
  21. package/dist/slot-picker.js +1 -1
  22. package/package.json +20 -6
  23. package/registry/account-menu.json +1 -1
  24. package/registry/account-settings.json +1 -1
  25. package/registry/achievement.json +1 -1
  26. package/registry/action-bar.json +2 -2
  27. package/registry/activity-feed.json +1 -1
  28. package/registry/agenda.json +1 -1
  29. package/registry/alert.json +1 -1
  30. package/registry/anatomy-plate.json +1 -1
  31. package/registry/app-header.json +1 -1
  32. package/registry/app-shell.json +1 -1
  33. package/registry/argument-card.json +2 -2
  34. package/registry/audio-player.json +1 -1
  35. package/registry/auth-layout.json +1 -1
  36. package/registry/avatar.json +1 -1
  37. package/registry/badge.json +1 -1
  38. package/registry/bird-plate.json +1 -1
  39. package/registry/button.json +1 -1
  40. package/registry/captcha.json +1 -1
  41. package/registry/card-grid.json +1 -1
  42. package/registry/card.json +1 -1
  43. package/registry/catalogue-page.json +1 -1
  44. package/registry/changelog-page.json +1 -1
  45. package/registry/chapter.json +478 -0
  46. package/registry/chat.json +1 -1
  47. package/registry/checkbox.json +1 -1
  48. package/registry/chip-link.json +1 -1
  49. package/registry/chip-row.json +1 -1
  50. package/registry/chip.json +1 -1
  51. package/registry/choice-grid.json +2 -2
  52. package/registry/code-block.json +1 -1
  53. package/registry/combobox.json +1 -1
  54. package/registry/command.json +1 -1
  55. package/registry/comparison-table.json +1 -1
  56. package/registry/component-page.json +1 -1
  57. package/registry/confirm-button.json +1 -1
  58. package/registry/contact-page.json +1 -1
  59. package/registry/continue-prompt.json +1 -1
  60. package/registry/countdown.json +1 -1
  61. package/registry/cover-hero.json +2 -2
  62. package/registry/cta-panel.json +1 -1
  63. package/registry/dashboard-layout.json +1 -1
  64. package/registry/data-table.json +1 -1
  65. package/registry/date-picker.json +1 -1
  66. package/registry/decision-list.json +1 -1
  67. package/registry/description-list.json +1 -1
  68. package/registry/detail-layout.json +1 -1
  69. package/registry/dialog.json +1 -1
  70. package/registry/docs-article-page.json +1 -1
  71. package/registry/docs-hub-page.json +1 -1
  72. package/registry/docs-layout.json +1 -1
  73. package/registry/docs-nav.json +1 -1
  74. package/registry/document-viewer.json +1 -1
  75. package/registry/drop-overlay.json +1 -1
  76. package/registry/dropdown-menu.json +1 -1
  77. package/registry/elephant.json +2 -2
  78. package/registry/empty-state.json +1 -1
  79. package/registry/engine-flow.json +1 -1
  80. package/registry/error-page.json +1 -1
  81. package/registry/examples/chapter/detail.d.ts +4 -0
  82. package/registry/examples/chapter/detail.js +21 -0
  83. package/registry/examples/chapter/detail.tsx +16 -0
  84. package/registry/examples/chapter/foot.d.ts +4 -0
  85. package/registry/examples/chapter/foot.js +20 -0
  86. package/registry/examples/chapter/foot.tsx +15 -0
  87. package/registry/examples/chapter/head.d.ts +4 -0
  88. package/registry/examples/chapter/head.js +22 -0
  89. package/registry/examples/chapter/head.tsx +17 -0
  90. package/registry/examples/chapter/index.d.ts +4 -0
  91. package/registry/examples/chapter/index.js +34 -0
  92. package/registry/examples/chapter/index.tsx +30 -0
  93. package/registry/examples/chapter/reading-page.d.ts +4 -0
  94. package/registry/examples/chapter/reading-page.js +34 -0
  95. package/registry/examples/chapter/reading-page.tsx +25 -0
  96. package/registry/field.json +1 -1
  97. package/registry/file-upload.json +1 -1
  98. package/registry/filter-bar.json +1 -1
  99. package/registry/flock.json +1 -1
  100. package/registry/footnote.json +1 -1
  101. package/registry/force-update-screen.json +1 -1
  102. package/registry/form.json +1 -1
  103. package/registry/gallery-page.json +1 -1
  104. package/registry/genui.json +1 -1
  105. package/registry/glossary-term.json +1 -1
  106. package/registry/glossary.json +1 -1
  107. package/registry/glow-card.json +1 -1
  108. package/registry/goal-gauge.json +1 -1
  109. package/registry/how-it-works-page.json +1 -1
  110. package/registry/image-cropper.json +1 -1
  111. package/registry/index.json +37 -6
  112. package/registry/iso.json +1 -1
  113. package/registry/kanban.json +1 -1
  114. package/registry/kbd.json +1 -1
  115. package/registry/kpi-explained.json +1 -1
  116. package/registry/landing-page.json +1 -1
  117. package/registry/landscape.json +1 -1
  118. package/registry/language-switch.json +1 -1
  119. package/registry/legal-page.json +1 -1
  120. package/registry/link-card.json +2 -2
  121. package/registry/list.json +1 -1
  122. package/registry/loader.json +1 -1
  123. package/registry/longform-page.json +1 -1
  124. package/registry/maintenance-screen.json +1 -1
  125. package/registry/map.json +2 -2
  126. package/registry/markdown.json +1 -1
  127. package/registry/marketing-layout.json +1 -1
  128. package/registry/marquee.json +1 -1
  129. package/registry/mascot-quote.json +1 -1
  130. package/registry/mascot-state.json +1 -1
  131. package/registry/mascots.json +1 -1
  132. package/registry/match-dialog.json +1 -1
  133. package/registry/media-capture.json +1 -1
  134. package/registry/media-gallery.json +1 -1
  135. package/registry/media-grid.json +2 -2
  136. package/registry/meta-row.json +1 -1
  137. package/registry/meter.json +1 -1
  138. package/registry/nav-bar.json +2 -2
  139. package/registry/next-actions.json +1 -1
  140. package/registry/number-ticker.json +1 -1
  141. package/registry/opening-hours.json +1 -1
  142. package/registry/page-header.json +1 -1
  143. package/registry/page-hero.json +2 -2
  144. package/registry/page-index.json +2 -2
  145. package/registry/page.json +1 -1
  146. package/registry/pagination.json +1 -1
  147. package/registry/photo-grid.json +1 -1
  148. package/registry/pointer-light.json +1 -1
  149. package/registry/popover.json +1 -1
  150. package/registry/pricing-page.json +1 -1
  151. package/registry/product-page.json +1 -1
  152. package/registry/profile-card.json +1 -1
  153. package/registry/progress.json +1 -1
  154. package/registry/promise-card.json +1 -1
  155. package/registry/radio-group.json +1 -1
  156. package/registry/rail-nav.json +2 -2
  157. package/registry/recipes.json +1 -1
  158. package/registry/router.json +1 -1
  159. package/registry/scroll-stage.json +1 -1
  160. package/registry/search-field.json +1 -1
  161. package/registry/section-backdrop.json +1 -1
  162. package/registry/separator.json +1 -1
  163. package/registry/service-card.json +2 -2
  164. package/registry/settings-layout.json +1 -1
  165. package/registry/showcase.json +1 -1
  166. package/registry/site-footer.json +2 -2
  167. package/registry/sites.json +1 -1
  168. package/registry/skeleton.json +1 -1
  169. package/registry/skip-link.json +1 -1
  170. package/registry/slider.json +1 -1
  171. package/registry/slot-picker.json +2 -2
  172. package/registry/slot.json +1 -1
  173. package/registry/specimen-tag.json +1 -1
  174. package/registry/spinner.json +1 -1
  175. package/registry/split-view.json +1 -1
  176. package/registry/stage-banner.json +1 -1
  177. package/registry/stat.json +1 -1
  178. package/registry/status-page.json +1 -1
  179. package/registry/step-progress.json +1 -1
  180. package/registry/step-showcase.json +1 -1
  181. package/registry/stepper.json +1 -1
  182. package/registry/sticky-action.json +1 -1
  183. package/registry/swipe-deck.json +1 -1
  184. package/registry/switch.json +1 -1
  185. package/registry/tabs.json +1 -1
  186. package/registry/tag-input.json +1 -1
  187. package/registry/tag-selector.json +1 -1
  188. package/registry/taped-photo.json +1 -1
  189. package/registry/terminal-replay.json +1 -1
  190. package/registry/text-style.json +1 -1
  191. package/registry/theme.json +1 -1
  192. package/registry/toast.json +1 -1
  193. package/registry/toc.json +1 -1
  194. package/registry/tooltip.json +1 -1
  195. package/registry/tree-view.json +1 -1
  196. package/registry/update-prompt.json +1 -1
  197. package/registry/upload-queue.json +1 -1
  198. package/registry/verified-badge.json +1 -1
  199. package/registry/vertical-video.json +1 -1
  200. package/registry/video-player.json +1 -1
  201. package/registry/video-trimmer.json +1 -1
  202. package/registry/virtual.json +1 -1
  203. package/registry/waveform.json +1 -1
  204. /package/dist/{chunk-IBDTAMPF.js.map → chunk-7JG3VR4C.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/media-grid/load-more.tsx","../src/spinner/spinner.tsx","../src/media-grid/media-grid.tsx","../src/media-grid/section-hint.tsx","../src/block-link.tsx","../src/media-grid/shorts-shelf.tsx","../src/media-grid/video-card.tsx","../src/media-grid/preview-focus.ts","../src/media-grid/video-card-skeleton.tsx"],"sourcesContent":["// Client (IntersectionObserver). The end of a long list: the next page is requested while the person is still a\n// screenful away (`rootMargin`), so it is there before they reach it; the button stays as the way that never fails\n// (no observer, a failed page, a keyboard).\nimport * as React from \"react\";\n\nimport { Button } from \"../button\";\nimport { cn } from \"../cn\";\nimport { Spinner } from \"../spinner\";\n\nexport interface LoadMoreProps extends Omit<React.ComponentProps<\"div\">, \"children\" | \"onError\"> {\n /** Asks for the next page. Not called while `loading`, nor once `hasMore` is false. */\n onLoadMore: () => void;\n /** There is a next page. */\n hasMore: boolean;\n /** A page is on its way. */\n loading?: boolean;\n /** The last page failed: the button reads `retryLabel`, and nothing loads by itself until it is pressed. */\n failed?: boolean;\n /** The button, passed translated (\"Load more\"). */\n label: string;\n /** The wait, passed translated (\"Loading more videos\"). */\n loadingLabel: string;\n /** The button after a failure, passed translated (\"Try again\"). Defaults to `label`. */\n retryLabel?: string;\n /** Shown instead of the button when the list is over, passed translated (\"You have seen everything\"). Nothing if absent. */\n endLabel?: string;\n /**\n * How far below the viewport the page is already requested (an IntersectionObserver `rootMargin`).\n * @default \"900px 0px\"\n */\n rootMargin?: string;\n}\n\n/** Infinite scroll with a visible \"Load more\" under it. */\nexport function LoadMore({ onLoadMore, hasMore, loading = false, failed = false, label, loadingLabel, retryLabel, endLabel, rootMargin = \"900px 0px\", className, ...props }: LoadMoreProps) {\n const sentinel = React.useRef<HTMLDivElement>(null);\n const ask = React.useRef(onLoadMore);\n React.useEffect(() => {\n ask.current = onLoadMore;\n });\n // Observing again after each page makes the observer report the current state: a short page that leaves the sentinel in view asks for the next.\n React.useEffect(() => {\n const el = sentinel.current;\n if (!el || !hasMore || loading || failed || typeof IntersectionObserver === \"undefined\") return;\n const io = new IntersectionObserver((entries) => entries.some((e) => e.isIntersecting) && ask.current(), { rootMargin });\n io.observe(el);\n return () => io.disconnect();\n }, [hasMore, loading, failed, rootMargin]);\n return (\n <div data-load-more=\"\" data-state={loading ? \"loading\" : failed ? \"failed\" : hasMore ? \"idle\" : \"end\"} className={cn(\"relative flex min-h-14 items-center justify-center py-6\", className)} {...props}>\n <div ref={sentinel} aria-hidden className=\"pointer-events-none absolute inset-x-0 top-0 h-px\" />\n {loading ? (\n <Spinner label={loadingLabel} size=\"md\" />\n ) : hasMore ? (\n <Button type=\"button\" variant=\"secondary\" size=\"md\" onClick={() => onLoadMore()}>\n {failed ? (retryLabel ?? label) : label}\n </Button>\n ) : endLabel ? (\n <p className=\"m-0 text-sm text-fg-secondary\">{endLabel}</p>\n ) : null}\n </div>\n );\n}\n","// Server-safe. An indeterminate wait: the Krizaka loader glyph (a hexagon traced by light around a node), announced as\n// a status with its `label`. For a wait with a delay, a value, an ETA or an ending, see `@krizaka/ui/loader`.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { LoaderGlyph } from \"./glyph\";\n\nexport const spinnerVariants = tv({\n base: \"shrink-0 text-accent\",\n variants: { size: { sm: \"h-4 w-4\", md: \"h-6 w-6\", lg: \"h-10 w-10\" } },\n defaultVariants: { size: \"md\" },\n});\n\nexport type SpinnerProps = Omit<React.ComponentProps<\"svg\">, \"children\"> &\n VariantProps<typeof spinnerVariants> & {\n /**\n * sm · md · lg.\n * @default \"md\"\n */\n size?: VariantProps<typeof spinnerVariants>[\"size\"];\n /** The accessible name of the wait, e.g. \"Loading\" — passed translated. */\n label: string;\n /** Between 0 and 1: the trace grows to the value (a determinate wait). Absent: it travels around. */\n value?: number | null;\n };\n\n/**\n * The Krizaka spinner: a hexagon traced by a segment of light around a breathing node, in `currentColor` (the accent by\n * default). `role=\"status\"`, named by `label`. Under prefers-reduced-motion it rests — a segment and the node lit.\n */\nexport function Spinner({ label, size, value, className, ...props }: SpinnerProps) {\n return (\n <LoaderGlyph\n role=\"status\"\n aria-label={label}\n aria-hidden={undefined}\n value={value}\n data-size={size ?? \"md\"}\n className={spinnerVariants({ size, className })}\n {...props}\n />\n );\n}\n","// Client (it renders the shelf). Mixed orientations without a broken grid. `split` (the feed default) sends the 9:16\n// clips to a `ShortsShelf` and lays the rest in a uniform 16:9 grid; `uniform` puts everything in one grid of one frame\n// (a source of the other orientation is told to `contain`, never cropped to a face). `layout=\"list\"` is one column.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { SectionHint, type SectionHintProps } from \"./section-hint\";\nimport { ShortsShelf, type ShortsShelfProps } from \"./shorts-shelf\";\nimport type { VideoCardAspect } from \"./video-card\";\n\nexport interface MediaGridState {\n /** The frame the card is drawn in (`aspect` of `VideoCard`). */\n aspect: VideoCardAspect;\n /** The card's `layout`. */\n layout: \"stack\" | \"row\";\n /** The source's orientation differs from the frame: pass `fit=\"contain\"`. */\n mismatch: boolean;\n}\n\nexport interface MediaGridProps<T> extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** The videos, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** The source's orientation (from its width and height). */\n orientationOf: (item: T) => VideoCardAspect;\n /** One card, drawn in the frame the grid gives (`state`): use `VideoCard`. */\n renderItem: (item: T, state: MediaGridState) => React.ReactNode;\n /**\n * `split`: verticals on the shelf, the others in the grid · `uniform`: all in one frame (`frame`).\n * @default \"split\"\n */\n mode?: \"split\" | \"uniform\";\n /** The frame of `uniform`. @default \"landscape\" */\n frame?: VideoCardAspect;\n /** `grid` or `list` (one row per video). @default \"grid\" */\n layout?: \"grid\" | \"list\";\n /** The shelf of `split`: its name, \"See all\" and arrows, passed translated. */\n shelf: Pick<ShortsShelfProps<unknown>, \"label\" | \"title\" | \"hint\" | \"seeAll\" | \"previousLabel\" | \"nextLabel\">;\n /** A heading for the grid of the others (“Videos”), in the style of the shelf's, with an optional definition. */\n grid?: { label: string; hint?: SectionHintProps };\n}\n\nconst GRID = {\n landscape: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\",\n portrait: \"grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6\",\n} as const;\n\n/** A media grid that never mixes heights badly: a shelf for the 9:16, a uniform grid for the rest. */\nexport function MediaGrid<T>({ items, getId, orientationOf, renderItem, mode = \"split\", frame = \"landscape\", layout = \"grid\", shelf, grid, className, ...props }: MediaGridProps<T>) {\n const gridHeading = React.useId();\n const row = layout === \"list\";\n const split = mode === \"split\";\n const verticals = split ? items.filter((i) => orientationOf(i) === \"portrait\") : [];\n const rest = split ? items.filter((i) => orientationOf(i) !== \"portrait\") : items;\n const gridFrame: VideoCardAspect = split ? \"landscape\" : frame;\n const state = (item: T, aspect: VideoCardAspect): MediaGridState => ({ aspect, layout: row ? \"row\" : \"stack\", mismatch: orientationOf(item) !== aspect });\n return (\n <div data-media-grid={mode} className={cn(\"flex min-w-0 flex-col gap-8\", className)} {...props}>\n {verticals.length > 0 && <ShortsShelf {...shelf} items={verticals} getId={getId} renderItem={(item) => renderItem(item, { ...state(item, \"portrait\"), layout: \"stack\" })} />}\n {rest.length > 0 && (\n <section aria-labelledby={grid ? gridHeading : undefined} data-media-grid-section className=\"min-w-0\">\n {grid && (\n <div className=\"mb-3 flex items-center gap-2\">\n <h2 id={gridHeading} className=\"m-0 text-base font-bold text-fg\">\n {grid.label}\n </h2>\n {grid.hint && <SectionHint {...grid.hint} />}\n </div>\n )}\n <ul data-grid-frame={gridFrame} className={cn(\"m-0 grid list-none auto-rows-fr gap-4 p-0\", row ? \"grid-cols-1\" : GRID[gridFrame])}>\n {rest.map((item) => (\n <li key={getId(item)} className=\"min-w-0\">\n {renderItem(item, state(item, gridFrame))}\n </li>\n ))}\n </ul>\n </section>\n )}\n </div>\n );\n}\n","// Client (open state). A tiny \"i\" button beside a section heading: it opens a one-line definition and, when given, a link to\n// the glossary. Opens on a tap or a press, on hover with a mouse, closes on Escape or when the focus leaves.\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\n\nexport interface SectionHintProps {\n /** The button's accessible name, passed translated (“What are Shorts?”). */\n label: string;\n /** The definition, in one line. */\n text: string;\n /** A link to the full definition (the glossary). */\n link?: { href: string; label: string; linkAs?: LinkComponent };\n}\n\n/** The definition of a section, one tap away from its heading. */\nexport function SectionHint({ label, text, link }: SectionHintProps) {\n const [open, setOpen] = React.useState(false);\n const id = React.useId();\n return (\n <span\n className=\"relative inline-flex\"\n onMouseEnter={() => setOpen(true)}\n onMouseLeave={() => setOpen(false)}\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget)) setOpen(false);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") setOpen(false);\n }}\n >\n <button\n type=\"button\"\n aria-label={label}\n aria-expanded={open}\n aria-controls={id}\n onClick={() => setOpen((o) => !o)}\n className=\"inline-flex h-6 w-6 items-center justify-center rounded-full text-fg-muted transition-colors hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 11v5M12 8h.01\" />\n </svg>\n </button>\n <span\n id={id}\n role=\"tooltip\"\n hidden={!open}\n className={cn(\"absolute left-0 top-full z-20 mt-1 w-64 max-w-[80vw] rounded-xl border border-border-default bg-surface-1 p-3 text-sm font-normal leading-snug text-fg-secondary shadow-lg\")}\n >\n {text}\n {link && (\n <>\n {\" \"}\n <BlockLink href={link.href} linkAs={link.linkAs} className=\"font-semibold text-fg-accent hover:underline\">\n {link.label}\n </BlockLink>\n </>\n )}\n </span>\n </span>\n );\n}\n","// 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","// Client (the arrows scroll the row). A horizontal row of 9:16 cards of one height: scroll-snap, arrows with a mouse,\n// a swipe on touch, a \"See all\" link. The row is a labelled list that scrolls with the keyboard (it takes focus).\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { SectionHint, type SectionHintProps } from \"./section-hint\";\n\nexport interface ShortsShelfProps<T> extends Omit<React.ComponentProps<\"section\">, \"children\" | \"title\"> {\n /** The shelf's accessible name (\"Shorts\"), passed translated; shown as its heading unless `title` is set. */\n label: string;\n /** A heading different from the name. */\n title?: React.ReactNode;\n /** A small “i” beside the heading: the one-line definition of the section and a link to the glossary. */\n hint?: SectionHintProps;\n /** The clips, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** One card: use `VideoCard aspect=\"portrait\"`. */\n renderItem: (item: T, index: number) => React.ReactNode;\n /** Opens the vertical feed. */\n seeAll?: { href: string; label: string; linkAs?: LinkComponent };\n /** The arrows' names, passed translated. */\n previousLabel: string;\n /** The next arrow's name. */\n nextLabel: string;\n}\n\nconst Chevron = ({ flip }: { flip?: boolean }) => (\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden className={flip ? \"rotate-180\" : undefined}>\n <path d=\"m9 6 6 6-6 6\" />\n </svg>\n);\n\nconst ARROW =\n \"hidden h-9 w-9 items-center justify-center rounded-full border border-border-default bg-surface-1 text-fg shadow-sm transition-colors hover:bg-surface-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-40 [@media(hover:hover)]:inline-flex\";\n\n/** A Shorts shelf: equal-height 9:16 cards in a snap-scrolling row. */\nexport function ShortsShelf<T>({ label, title, hint, items, getId, renderItem, seeAll, previousLabel, nextLabel, className, ...props }: ShortsShelfProps<T>) {\n const row = React.useRef<HTMLUListElement>(null);\n const [edge, setEdge] = React.useState({ start: true, end: false });\n const measure = React.useCallback(() => {\n const el = row.current;\n if (!el) return;\n setEdge({ start: el.scrollLeft <= 2, end: el.scrollLeft + el.clientWidth >= el.scrollWidth - 2 });\n }, []);\n React.useEffect(measure, [measure, items.length]);\n const page = (dir: 1 | -1) => {\n const el = row.current;\n if (el) el.scrollBy({ left: dir * el.clientWidth * 0.85, behavior: window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\" });\n };\n const headingId = React.useId();\n if (items.length === 0) return null;\n return (\n <section aria-labelledby={headingId} data-shorts-shelf className={cn(\"min-w-0\", className)} {...props}>\n <div className=\"mb-3 flex items-center gap-2\">\n <h2 id={headingId} className=\"m-0 mr-auto text-base font-bold text-fg\">\n {title ?? label}\n </h2>\n {hint && <SectionHint {...hint} />}\n {seeAll && (\n <BlockLink href={seeAll.href} linkAs={seeAll.linkAs} className=\"text-sm font-semibold text-fg-accent hover:underline\">\n {seeAll.label}\n </BlockLink>\n )}\n <button type=\"button\" aria-label={previousLabel} disabled={edge.start} onClick={() => page(-1)} className={ARROW}>\n <Chevron flip />\n </button>\n <button type=\"button\" aria-label={nextLabel} disabled={edge.end} onClick={() => page(1)} className={ARROW}>\n <Chevron />\n </button>\n </div>\n <ul\n ref={row}\n onScroll={measure}\n // biome-ignore: a scroll container must take the keyboard focus to scroll with the arrow keys\n tabIndex={0}\n aria-labelledby={headingId}\n className=\"m-0 flex list-none snap-x snap-mandatory items-stretch gap-3 overflow-x-auto overflow-y-hidden overscroll-x-contain p-0 pt-1 -mt-1 pb-2 [scrollbar-width:none] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&::-webkit-scrollbar]:hidden\"\n >\n {items.map((item, i) => (\n <li key={getId(item)} className=\"w-[9.5rem] shrink-0 snap-start sm:w-44\">\n {renderItem(item, i)}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","// Client (hover / focus swaps the picture for its animated preview). A video in a grid or a shelf: the picture in a 16:9\n// or 9:16 frame (a source of the other shape is shown inside, never stretched), badges, duration, the title on two lines\n// reserved, the creator, a count and one quick action — the same height of body in every card so a row aligns.\nimport * as React from \"react\";\n\nimport { Avatar } from \"../avatar\";\nimport type { DefaultAvatar } from \"../avatar/default-avatar\";\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\nimport { isLeader, subscribeLeader, trackVisibility } from \"./preview-focus\";\n\nexport type VideoCardAspect = \"landscape\" | \"portrait\";\n\nexport interface VideoCardCreator {\n /** The creator's name. */\n name: string;\n /** Their photo. */\n avatarSrc?: string | null;\n /** Their profile. */\n href?: string;\n /** The Krizaka default picture when there is no photo (a brand and a seed). */\n defaultAvatar?: DefaultAvatar;\n}\n\nexport interface VideoCardProps extends Omit<React.ComponentProps<\"article\">, \"title\"> {\n /** The title; it names the card and is its link. */\n title: string;\n /** Where the card opens. */\n href: string;\n /** The app's router link (Next's `Link`). */\n linkAs?: LinkComponent;\n /**\n * The frame: `landscape` (16:9) or `portrait` (9:16).\n * @default \"landscape\"\n */\n aspect?: VideoCardAspect;\n /**\n * `stack` (picture over text) or `row` (picture beside the text: the list mode of a section).\n * @default \"stack\"\n */\n layout?: \"stack\" | \"row\";\n /** The picture. */\n poster?: string | null;\n /**\n * An animated picture (WebP, a few hundred kB) that fades in over the poster once the pointer has rested on the card\n * (or it is focused) for `previewDelay`, and is removed again on leave. It is never requested before. On a phone (no\n * hover) only the card most inside the viewport plays it, unless the person asked for less data or less motion.\n */\n previewSrc?: string | null;\n /**\n * How long the pointer must rest before the preview is requested, in ms: a pointer crossing the grid loads nothing.\n * @default 200\n */\n previewDelay?: number;\n /**\n * `fetchPriority` of the poster: `high` for the first row (the largest contentful paint).\n * @default \"auto\"\n */\n posterPriority?: \"high\" | \"low\" | \"auto\";\n /**\n * `cover` fills the frame; `contain` draws the whole picture over a blurred copy of itself (a source of the other\n * orientation: no cropped face, no black bar).\n * @default \"cover\"\n */\n fit?: \"cover\" | \"contain\";\n /** The length, already formatted (`3:42`). */\n duration?: string;\n /** Badges at the top-left of the picture (Free, a price, 18+). Put them on `scrim` so they read in both themes. */\n badges?: React.ReactNode;\n /** Who made it: name, photo, profile. */\n creator?: VideoCardCreator;\n /** What is counted (`12.4K views`), already formatted. */\n meta?: React.ReactNode;\n /** One quick action at the end of the footer (a tip, a save). Its clicks must not follow the card's link. */\n action?: React.ReactNode;\n /** A sensitive picture: blurred and scaled so nothing shows (put the reveal button in `overlay`). */\n blurred?: boolean;\n /** Over the whole picture, above the card's link (a veil, a reveal button). */\n overlay?: React.ReactNode;\n /** Shown instead of the picture while there is none. */\n fallback?: React.ReactNode;\n /** `eager` for the first cards of a page. */\n loading?: \"lazy\" | \"eager\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** A video card whose frame, body and footer have one height per aspect, so a grid row or a shelf never staggers. */\nexport function VideoCard({\n title,\n href,\n linkAs,\n aspect = \"landscape\",\n layout = \"stack\",\n poster,\n previewSrc,\n previewDelay = 200,\n posterPriority = \"auto\",\n fit = \"cover\",\n duration,\n badges,\n creator,\n meta,\n action,\n fallback,\n blurred = false,\n overlay,\n loading = \"lazy\",\n className,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ref,\n ...props\n}: VideoCardProps) {\n const [node, setNode] = React.useState<HTMLElement | null>(null);\n const setRef = React.useCallback(\n (el: HTMLElement | null) => {\n setNode(el);\n if (typeof ref === \"function\") ref(el);\n else if (ref) (ref as React.RefObject<HTMLElement | null>).current = el;\n },\n [ref],\n );\n const canPreview = Boolean(previewSrc) && !blurred;\n const { live, arm, disarm } = usePreviewIntent(node, canPreview, previewDelay);\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <article\n ref={setRef}\n data-aspect={aspect}\n data-layout={layout}\n className={cn(\"group relative h-full min-w-0\", className)}\n data-preview={live ? \"on\" : undefined}\n onMouseEnter={(e) => (arm(\"pointer\"), onMouseEnter?.(e))}\n onMouseLeave={(e) => (disarm(\"pointer\"), onMouseLeave?.(e))}\n onFocus={(e) => (arm(\"focus\"), onFocus?.(e))}\n onBlur={(e) => (disarm(\"focus\"), onBlur?.(e))}\n {...props}\n >\n <Card.Root interactive tone=\"glass\" className={cn(\"h-full w-full max-w-full\", row ? \"flex-row\" : \"flex-col\")}>\n <Card.Media aspect=\"auto\" className={cn(\"shrink-0\", FRAME[aspect], row && (aspect === \"portrait\" ? \"w-24 sm:w-28\" : \"w-40 sm:w-56\"))}>\n {fit === \"contain\" && poster && <img src={poster} alt=\"\" aria-hidden loading=\"lazy\" className=\"absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl\" />}\n <Card.Image\n src={poster}\n loading={loading}\n fetchPriority={posterPriority === \"auto\" ? undefined : posterPriority}\n fallback={fallback}\n className={cn(fit === \"contain\" && \"relative object-contain\", blurred && \"scale-110 blur-xl\")}\n />\n {live && previewSrc && <PreviewLayer src={previewSrc} contain={fit === \"contain\"} />}\n {overlay && <div className=\"absolute inset-0 z-20 flex\">{overlay}</div>}\n {badges && (\n <Card.Overlay corner=\"top-left\" className=\"theme-dark pointer-events-none flex-wrap\">\n {badges}\n </Card.Overlay>\n )}\n {duration && (\n <Card.Overlay corner=\"bottom-right\" className=\"pointer-events-none\">\n <span className=\"rounded-sm bg-scrim px-1.5 py-0.5 font-mono text-[11px] text-fg-on-media\">{duration}</span>\n </Card.Overlay>\n )}\n </Card.Media>\n {/* `static`: the body must not be the containing block of the title link's ::after, or the link would cover the text only and the picture would not open the video. */}\n <Card.Body className=\"static min-w-0 flex-1 justify-between gap-2 p-3\">\n <h3 className=\"m-0 min-h-[2.5em] text-sm font-semibold leading-tight text-fg\">\n <BlockLink href={href} linkAs={linkAs} className=\"line-clamp-2 outline-none after:absolute after:inset-0 after:z-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-ring\">\n {title}\n </BlockLink>\n </h3>\n {/* A narrow card (9:16 on a shelf) puts the count and the action on a second line so the name is never cut to an initial. */}\n <div className={cn(\"relative z-10 text-xs text-fg-secondary\", tall ? \"flex flex-col gap-1\" : \"flex h-8 items-center gap-2\")}>\n {creator && (\n <div className=\"flex h-6 min-w-0 items-center gap-2\">\n <Avatar src={creator.avatarSrc} defaultAvatar={creator.defaultAvatar} alt=\"\" fallback={creator.name.charAt(0)} size=\"xs\" className=\"shrink-0\" />\n {creator.href ? (\n <BlockLink href={creator.href} linkAs={linkAs} className=\"min-w-0 truncate hover:text-fg\">\n {creator.name}\n </BlockLink>\n ) : (\n <span className=\"min-w-0 truncate\">{creator.name}</span>\n )}\n </div>\n )}\n {(meta || action) && (\n <div className={cn(\"flex items-center gap-2\", tall ? \"h-7 justify-between\" : \"ml-auto shrink-0\")}>\n {meta && <span className=\"shrink-0 font-mono text-[11px] text-fg-muted\">{meta}</span>}\n {action && <span className=\"shrink-0\">{action}</span>}\n </div>\n )}\n </div>\n </Card.Body>\n </Card.Root>\n </article>\n );\n}\n\n/** The animated preview, fading in over the poster once it has loaded; unmounted (so unloaded) on leave. */\nfunction PreviewLayer({ src, contain }: { src: string; contain: boolean }) {\n const [ready, setReady] = React.useState(false);\n return (\n <img\n src={src}\n alt=\"\"\n aria-hidden\n decoding=\"async\"\n data-preview-layer=\"\"\n data-ready={ready ? \"\" : undefined}\n onLoad={() => setReady(true)}\n className={cn(\"pointer-events-none absolute inset-0 h-full w-full opacity-0 transition-opacity duration-300 data-[ready]:opacity-100 motion-reduce:transition-none\", contain ? \"object-contain\" : \"object-cover\")}\n />\n );\n}\n\ntype Cause = \"pointer\" | \"focus\";\n\nconst matches = (query: string) => typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(query).matches;\nconst hoverCapable = () => matches(\"(hover: hover)\");\nconst saveData = () => typeof navigator !== \"undefined\" && (navigator as Navigator & { connection?: { saveData?: boolean } }).connection?.saveData === true;\n\n/**\n * When the preview is wanted. A desktop pointer or the keyboard focus must rest `delay` ms first; on a phone the card\n * the page shows most (and only one) wants it, never under Save-Data or reduced motion. Leaving clears everything.\n */\nfunction usePreviewIntent(node: HTMLElement | null, enabled: boolean, delay: number) {\n const [causes, setCauses] = React.useState<ReadonlySet<Cause>>(new Set());\n const timers = React.useRef(new Map<Cause, ReturnType<typeof setTimeout>>());\n const arm = React.useCallback(\n (cause: Cause) => {\n if (!enabled || saveData()) return;\n if (cause === \"pointer\" && !hoverCapable()) return;\n clearTimeout(timers.current.get(cause));\n timers.current.set(\n cause,\n setTimeout(() => setCauses((c) => new Set(c).add(cause)), delay),\n );\n },\n [enabled, delay],\n );\n const disarm = React.useCallback((cause: Cause) => {\n clearTimeout(timers.current.get(cause));\n timers.current.delete(cause);\n setCauses((c) => {\n if (!c.has(cause)) return c;\n const next = new Set(c);\n next.delete(cause);\n return next;\n });\n }, []);\n React.useEffect(() => {\n const pending = timers.current;\n return () => {\n for (const t of pending.values()) clearTimeout(t);\n pending.clear();\n };\n }, []);\n\n // A phone: the single most visible card, after the same rest.\n const touch = enabled && !hoverCapable();\n const leading = React.useSyncExternalStore(\n subscribeLeader,\n () => isLeader(node),\n () => false,\n );\n React.useEffect(() => {\n if (!node || !touch) return;\n return trackVisibility(node);\n }, [node, touch]);\n const [ready, setReady] = React.useState(false);\n const [wasLeading, setWasLeading] = React.useState(false);\n if (leading !== wasLeading) {\n setWasLeading(leading);\n if (!leading) setReady(false);\n }\n const wanted = touch && leading && !saveData() && !matches(\"(prefers-reduced-motion: reduce)\");\n React.useEffect(() => {\n if (!wanted) return;\n const t = setTimeout(() => setReady(true), delay);\n return () => clearTimeout(t);\n }, [wanted, delay]);\n\n return { live: enabled && (causes.size > 0 || (wanted && ready)), arm, disarm };\n}\n","// Client only. Which card of the page is the most visible: on a phone there is no hover, so exactly one card at a time\n// (the one most inside the viewport) may play its preview. One IntersectionObserver for the whole page, no per-card\n// observer; the answer is a store read with `useSyncExternalStore`.\nconst MIN_RATIO = 0.6;\nconst ratios = new Map<Element, number>();\nconst listeners = new Set<() => void>();\nlet observer: IntersectionObserver | null = null;\nlet leader: Element | null = null;\n\nfunction elect() {\n let best: Element | null = null;\n let bestRatio = MIN_RATIO - Number.EPSILON;\n for (const [el, ratio] of ratios) {\n if (ratio > bestRatio) {\n best = el;\n bestRatio = ratio;\n }\n }\n if (best === leader) return;\n leader = best;\n for (const l of listeners) l();\n}\n\n/** Starts counting an element's visibility; returns the function that stops it. */\nexport function trackVisibility(el: Element): () => void {\n if (typeof IntersectionObserver === \"undefined\") return () => {};\n observer ??= new IntersectionObserver(\n (entries) => {\n for (const e of entries) ratios.set(e.target, e.isIntersecting ? e.intersectionRatio : 0);\n elect();\n },\n { threshold: [0, 0.25, 0.5, 0.6, 0.75, 1] },\n );\n ratios.set(el, 0);\n observer.observe(el);\n return () => {\n observer?.unobserve(el);\n ratios.delete(el);\n elect();\n };\n}\n\nexport const subscribeLeader = (l: () => void) => (listeners.add(l), () => void listeners.delete(l));\n\n/** Whether this element is the card the page is showing most. */\nexport const isLeader = (el: Element | null) => el !== null && leader === el;\n\n/** Test seam: forget everything. */\nexport function resetPreviewFocus() {\n observer?.disconnect();\n observer = null;\n ratios.clear();\n leader = null;\n}\n","// A video card on its way: the same frame, body and footer heights as `VideoCard`, so nothing moves when it arrives.\nimport * as React from \"react\";\n\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\nimport { Skeleton } from \"../skeleton\";\nimport type { VideoCardAspect } from \"./video-card\";\n\nexport interface VideoCardSkeletonProps extends React.ComponentProps<\"div\"> {\n /** `landscape` (16:9) or `portrait` (9:16), as the card it stands for. @default \"landscape\" */\n aspect?: VideoCardAspect;\n /** `stack` or `row`, as the card it stands for. @default \"stack\" */\n layout?: \"stack\" | \"row\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** The placeholder of a `VideoCard` (decorative: announce the wait on the list, with `MediaGridSkeleton`). */\nexport function VideoCardSkeleton({ aspect = \"landscape\", layout = \"stack\", className, ...props }: VideoCardSkeletonProps) {\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <div aria-hidden data-skeleton=\"video-card\" data-aspect={aspect} data-layout={layout} className={cn(\"h-full min-w-0\", className)} {...props}>\n <Card.Root tone=\"glass\" className={cn(\"h-full w-full max-w-full\", row ? \"flex-row\" : \"flex-col\")}>\n <Card.Media aspect=\"auto\" className={cn(\"shrink-0\", FRAME[aspect], row && (aspect === \"portrait\" ? \"w-24 sm:w-28\" : \"w-40 sm:w-56\"))}>\n <Skeleton shape=\"rect\" className=\"h-full w-full rounded-none\" />\n </Card.Media>\n <Card.Body className=\"static min-w-0 flex-1 justify-between gap-2 p-3\">\n <div className=\"flex min-h-[2.5em] flex-col justify-center gap-1.5\">\n <Skeleton className=\"h-3\" />\n <Skeleton className=\"h-3 w-3/5\" />\n </div>\n <div className={cn(\"flex text-xs\", tall ? \"flex-col gap-1\" : \"h-8 items-center gap-2\")}>\n <div className=\"flex h-6 min-w-0 items-center gap-2\">\n <Skeleton shape=\"circle\" className=\"h-6 w-6 shrink-0\" />\n <Skeleton className=\"h-2.5 w-20\" />\n </div>\n <div className={cn(\"flex items-center\", tall ? \"h-7\" : \"ml-auto\")}>\n <Skeleton className=\"h-2.5 w-14\" />\n </div>\n </div>\n </Card.Body>\n </Card.Root>\n </div>\n );\n}\n\nexport interface MediaGridSkeletonProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** What is loading, passed translated (\"Loading videos\"): announced once, the cards are hidden from assistive technology. */\n label: string;\n /** Cards in the grid. @default 8 */\n count?: number;\n /** Cards on the Shorts shelf above the grid (`split` mode); 0 for none. @default 0 */\n shelfCount?: number;\n /** `grid` or `list`. @default \"grid\" */\n layout?: \"grid\" | \"list\";\n /** The frame of the grid. @default \"landscape\" */\n frame?: VideoCardAspect;\n}\n\nconst GRID = {\n landscape: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\",\n portrait: \"grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6\",\n} as const;\n\n/** The placeholder of a `MediaGrid`: the same shelf and grid, skeleton cards, one polite announcement. */\nexport function MediaGridSkeleton({ label, count = 8, shelfCount = 0, layout = \"grid\", frame = \"landscape\", className, ...props }: MediaGridSkeletonProps) {\n const row = layout === \"list\";\n return (\n <div role=\"status\" aria-busy=\"true\" data-media-grid-skeleton=\"\" className={cn(\"flex min-w-0 flex-col gap-8\", className)} {...props}>\n <span className=\"sr-only\">{label}</span>\n {shelfCount > 0 && (\n <div aria-hidden className=\"min-w-0\">\n <Skeleton className=\"mb-3 h-4 w-24\" />\n <ul className=\"m-0 flex list-none items-stretch gap-3 overflow-hidden p-0\">\n {Array.from({ length: shelfCount }, (_, i) => (\n <li key={i} className=\"w-[9.5rem] shrink-0 sm:w-44\">\n <VideoCardSkeleton aspect=\"portrait\" />\n </li>\n ))}\n </ul>\n </div>\n )}\n <ul aria-hidden className={cn(\"m-0 grid list-none auto-rows-fr gap-4 p-0\", row ? \"grid-cols-1\" : GRID[frame])}>\n {Array.from({ length: count }, (_, i) => (\n <li key={i} className=\"min-w-0\">\n <VideoCardSkeleton aspect={frame} layout={row ? \"row\" : \"stack\"} />\n </li>\n ))}\n </ul>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","React","React","jsx","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","FRAME","GRID"]}
1
+ {"version":3,"sources":["../src/media-grid/load-more.tsx","../src/spinner/spinner.tsx","../src/media-grid/media-grid.tsx","../src/media-grid/section-hint.tsx","../src/block-link.tsx","../src/media-grid/shorts-shelf.tsx","../src/media-grid/video-card.tsx","../src/media-grid/preview-focus.ts","../src/media-grid/video-card-skeleton.tsx"],"sourcesContent":["// Client (IntersectionObserver). The end of a long list: the next page is requested while the person is still a\n// screenful away (`rootMargin`), so it is there before they reach it; the button stays as the way that never fails\n// (no observer, a failed page, a keyboard).\nimport * as React from \"react\";\n\nimport { Button } from \"../button\";\nimport { cn } from \"../cn\";\nimport { Spinner } from \"../spinner\";\n\nexport interface LoadMoreProps extends Omit<React.ComponentProps<\"div\">, \"children\" | \"onError\"> {\n /** Asks for the next page. Not called while `loading`, nor once `hasMore` is false. */\n onLoadMore: () => void;\n /** There is a next page. */\n hasMore: boolean;\n /** A page is on its way. */\n loading?: boolean;\n /** The last page failed: the button reads `retryLabel`, and nothing loads by itself until it is pressed. */\n failed?: boolean;\n /** The button, passed translated (\"Load more\"). */\n label: string;\n /** The wait, passed translated (\"Loading more videos\"). */\n loadingLabel: string;\n /** The button after a failure, passed translated (\"Try again\"). Defaults to `label`. */\n retryLabel?: string;\n /** Shown instead of the button when the list is over, passed translated (\"You have seen everything\"). Nothing if absent. */\n endLabel?: string;\n /**\n * How far below the viewport the page is already requested (an IntersectionObserver `rootMargin`).\n * @default \"900px 0px\"\n */\n rootMargin?: string;\n}\n\n/** Infinite scroll with a visible \"Load more\" under it. */\nexport function LoadMore({ onLoadMore, hasMore, loading = false, failed = false, label, loadingLabel, retryLabel, endLabel, rootMargin = \"900px 0px\", className, ...props }: LoadMoreProps) {\n const sentinel = React.useRef<HTMLDivElement>(null);\n const ask = React.useRef(onLoadMore);\n React.useEffect(() => {\n ask.current = onLoadMore;\n });\n // Observing again after each page makes the observer report the current state: a short page that leaves the sentinel in view asks for the next.\n React.useEffect(() => {\n const el = sentinel.current;\n if (!el || !hasMore || loading || failed || typeof IntersectionObserver === \"undefined\") return;\n const io = new IntersectionObserver((entries) => entries.some((e) => e.isIntersecting) && ask.current(), { rootMargin });\n io.observe(el);\n return () => io.disconnect();\n }, [hasMore, loading, failed, rootMargin]);\n return (\n <div data-load-more=\"\" data-state={loading ? \"loading\" : failed ? \"failed\" : hasMore ? \"idle\" : \"end\"} className={cn(\"relative flex min-h-14 items-center justify-center py-6\", className)} {...props}>\n <div ref={sentinel} aria-hidden className=\"pointer-events-none absolute inset-x-0 top-0 h-px\" />\n {loading ? (\n <Spinner label={loadingLabel} size=\"md\" />\n ) : hasMore ? (\n <Button type=\"button\" variant=\"secondary\" size=\"md\" onClick={() => onLoadMore()}>\n {failed ? (retryLabel ?? label) : label}\n </Button>\n ) : endLabel ? (\n <p className=\"m-0 text-sm text-fg-secondary\">{endLabel}</p>\n ) : null}\n </div>\n );\n}\n","// Server-safe. An indeterminate wait: the Krizaka loader glyph (a hexagon traced by light around a node), announced as\n// a status with its `label`. For a wait with a delay, a value, an ETA or an ending, see `@krizaka/ui/loader`.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { LoaderGlyph } from \"./glyph\";\n\nexport const spinnerVariants = tv({\n base: \"shrink-0 text-accent\",\n variants: { size: { sm: \"h-4 w-4\", md: \"h-6 w-6\", lg: \"h-10 w-10\" } },\n defaultVariants: { size: \"md\" },\n});\n\nexport type SpinnerProps = Omit<React.ComponentProps<\"svg\">, \"children\"> &\n VariantProps<typeof spinnerVariants> & {\n /**\n * sm · md · lg.\n * @default \"md\"\n */\n size?: VariantProps<typeof spinnerVariants>[\"size\"];\n /** The accessible name of the wait, e.g. \"Loading\" — passed translated. */\n label: string;\n /** Between 0 and 1: the trace grows to the value (a determinate wait). Absent: it travels around. */\n value?: number | null;\n };\n\n/**\n * The Krizaka spinner: a hexagon traced by a segment of light around a breathing node, in `currentColor` (the accent by\n * default). `role=\"status\"`, named by `label`. Under prefers-reduced-motion it rests — a segment and the node lit.\n */\nexport function Spinner({ label, size, value, className, ...props }: SpinnerProps) {\n return (\n <LoaderGlyph\n role=\"status\"\n aria-label={label}\n aria-hidden={undefined}\n value={value}\n data-size={size ?? \"md\"}\n className={spinnerVariants({ size, className })}\n {...props}\n />\n );\n}\n","// Client (it renders the shelf). Mixed orientations without a broken grid. `split` (the feed default) sends the 9:16\n// clips to a `ShortsShelf` and lays the rest in a uniform 16:9 grid; `uniform` puts everything in one grid of one frame\n// (a source of the other orientation is told to `contain`, never cropped to a face). `layout=\"list\"` is one column.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { SectionHint, type SectionHintProps } from \"./section-hint\";\nimport { ShortsShelf, type ShortsShelfProps } from \"./shorts-shelf\";\nimport type { VideoCardAspect } from \"./video-card\";\n\nexport interface MediaGridState {\n /** The frame the card is drawn in (`aspect` of `VideoCard`). */\n aspect: VideoCardAspect;\n /** The card's `layout`. */\n layout: \"stack\" | \"row\";\n /** The source's orientation differs from the frame: pass `fit=\"contain\"`. */\n mismatch: boolean;\n}\n\nexport interface MediaGridProps<T> extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** The videos, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** The source's orientation (from its width and height). */\n orientationOf: (item: T) => VideoCardAspect;\n /** One card, drawn in the frame the grid gives (`state`): use `VideoCard`. */\n renderItem: (item: T, state: MediaGridState) => React.ReactNode;\n /**\n * `split`: verticals on the shelf, the others in the grid · `uniform`: all in one frame (`frame`).\n * @default \"split\"\n */\n mode?: \"split\" | \"uniform\";\n /** The frame of `uniform`. @default \"landscape\" */\n frame?: VideoCardAspect;\n /** `grid` or `list` (one row per video). @default \"grid\" */\n layout?: \"grid\" | \"list\";\n /** The shelf of `split`: its name, \"See all\" and arrows, passed translated. */\n shelf: Pick<ShortsShelfProps<unknown>, \"label\" | \"title\" | \"hint\" | \"seeAll\" | \"previousLabel\" | \"nextLabel\">;\n /** A heading for the grid of the others (“Videos”), in the style of the shelf's, with an optional definition. */\n grid?: { label: string; hint?: SectionHintProps };\n}\n\nconst GRID = {\n landscape: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\",\n portrait: \"grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6\",\n} as const;\n\n/** A media grid that never mixes heights badly: a shelf for the 9:16, a uniform grid for the rest. */\nexport function MediaGrid<T>({ items, getId, orientationOf, renderItem, mode = \"split\", frame = \"landscape\", layout = \"grid\", shelf, grid, className, ...props }: MediaGridProps<T>) {\n const gridHeading = React.useId();\n const row = layout === \"list\";\n const split = mode === \"split\";\n const verticals = split ? items.filter((i) => orientationOf(i) === \"portrait\") : [];\n const rest = split ? items.filter((i) => orientationOf(i) !== \"portrait\") : items;\n const gridFrame: VideoCardAspect = split ? \"landscape\" : frame;\n const state = (item: T, aspect: VideoCardAspect): MediaGridState => ({ aspect, layout: row ? \"row\" : \"stack\", mismatch: orientationOf(item) !== aspect });\n return (\n <div data-media-grid={mode} className={cn(\"flex min-w-0 flex-col gap-8\", className)} {...props}>\n {verticals.length > 0 && <ShortsShelf {...shelf} items={verticals} getId={getId} renderItem={(item) => renderItem(item, { ...state(item, \"portrait\"), layout: \"stack\" })} />}\n {rest.length > 0 && (\n <section aria-labelledby={grid ? gridHeading : undefined} data-media-grid-section className=\"min-w-0\">\n {grid && (\n <div className=\"mb-3 flex items-center gap-2\">\n <h2 id={gridHeading} className=\"m-0 text-base font-bold text-fg\">\n {grid.label}\n </h2>\n {grid.hint && <SectionHint {...grid.hint} />}\n </div>\n )}\n <ul data-grid-frame={gridFrame} className={cn(\"m-0 grid list-none auto-rows-fr gap-4 p-0\", row ? \"grid-cols-1\" : GRID[gridFrame])}>\n {rest.map((item) => (\n <li key={getId(item)} className=\"min-w-0\">\n {renderItem(item, state(item, gridFrame))}\n </li>\n ))}\n </ul>\n </section>\n )}\n </div>\n );\n}\n","// Client (open state). A tiny \"i\" button beside a section heading: it opens a one-line definition and, when given, a link to\n// the glossary. Opens on a tap or a press, on hover with a mouse, closes on Escape or when the focus leaves.\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\n\nexport interface SectionHintProps {\n /** The button's accessible name, passed translated (“What are Shorts?”). */\n label: string;\n /** The definition, in one line. */\n text: string;\n /** A link to the full definition (the glossary). */\n link?: { href: string; label: string; linkAs?: LinkComponent };\n}\n\n/** The definition of a section, one tap away from its heading. */\nexport function SectionHint({ label, text, link }: SectionHintProps) {\n const [open, setOpen] = React.useState(false);\n const id = React.useId();\n return (\n <span\n className=\"relative inline-flex\"\n onMouseEnter={() => setOpen(true)}\n onMouseLeave={() => setOpen(false)}\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget)) setOpen(false);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") setOpen(false);\n }}\n >\n <button\n type=\"button\"\n aria-label={label}\n aria-expanded={open}\n aria-controls={id}\n onClick={() => setOpen((o) => !o)}\n className=\"inline-flex h-6 w-6 items-center justify-center rounded-full text-fg-muted transition-colors hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 11v5M12 8h.01\" />\n </svg>\n </button>\n <span\n id={id}\n role=\"tooltip\"\n hidden={!open}\n className={cn(\"absolute left-0 top-full z-20 mt-1 w-64 max-w-[80vw] rounded-xl border border-border-default bg-surface-1 p-3 text-sm font-normal leading-snug text-fg-secondary shadow-lg\")}\n >\n {text}\n {link && (\n <>\n {\" \"}\n <BlockLink href={link.href} linkAs={link.linkAs} className=\"font-semibold text-fg-accent hover:underline\">\n {link.label}\n </BlockLink>\n </>\n )}\n </span>\n </span>\n );\n}\n","// 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} rel={rel} {...props} />;\n}\n","// Client (the arrows scroll the row). A horizontal row of 9:16 cards of one height: scroll-snap, arrows with a mouse,\n// a swipe on touch, a \"See all\" link. The row is a labelled list that scrolls with the keyboard (it takes focus).\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { SectionHint, type SectionHintProps } from \"./section-hint\";\n\nexport interface ShortsShelfProps<T> extends Omit<React.ComponentProps<\"section\">, \"children\" | \"title\"> {\n /** The shelf's accessible name (\"Shorts\"), passed translated; shown as its heading unless `title` is set. */\n label: string;\n /** A heading different from the name. */\n title?: React.ReactNode;\n /** A small “i” beside the heading: the one-line definition of the section and a link to the glossary. */\n hint?: SectionHintProps;\n /** The clips, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** One card: use `VideoCard aspect=\"portrait\"`. */\n renderItem: (item: T, index: number) => React.ReactNode;\n /** Opens the vertical feed. */\n seeAll?: { href: string; label: string; linkAs?: LinkComponent };\n /** The arrows' names, passed translated. */\n previousLabel: string;\n /** The next arrow's name. */\n nextLabel: string;\n}\n\nconst Chevron = ({ flip }: { flip?: boolean }) => (\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden className={flip ? \"rotate-180\" : undefined}>\n <path d=\"m9 6 6 6-6 6\" />\n </svg>\n);\n\nconst ARROW =\n \"hidden h-9 w-9 items-center justify-center rounded-full border border-border-default bg-surface-1 text-fg shadow-sm transition-colors hover:bg-surface-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-40 [@media(hover:hover)]:inline-flex\";\n\n/** A Shorts shelf: equal-height 9:16 cards in a snap-scrolling row. */\nexport function ShortsShelf<T>({ label, title, hint, items, getId, renderItem, seeAll, previousLabel, nextLabel, className, ...props }: ShortsShelfProps<T>) {\n const row = React.useRef<HTMLUListElement>(null);\n const [edge, setEdge] = React.useState({ start: true, end: false });\n const measure = React.useCallback(() => {\n const el = row.current;\n if (!el) return;\n setEdge({ start: el.scrollLeft <= 2, end: el.scrollLeft + el.clientWidth >= el.scrollWidth - 2 });\n }, []);\n React.useEffect(measure, [measure, items.length]);\n const page = (dir: 1 | -1) => {\n const el = row.current;\n if (el) el.scrollBy({ left: dir * el.clientWidth * 0.85, behavior: window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\" });\n };\n const headingId = React.useId();\n if (items.length === 0) return null;\n return (\n <section aria-labelledby={headingId} data-shorts-shelf className={cn(\"min-w-0\", className)} {...props}>\n <div className=\"mb-3 flex items-center gap-2\">\n <h2 id={headingId} className=\"m-0 mr-auto text-base font-bold text-fg\">\n {title ?? label}\n </h2>\n {hint && <SectionHint {...hint} />}\n {seeAll && (\n <BlockLink href={seeAll.href} linkAs={seeAll.linkAs} className=\"text-sm font-semibold text-fg-accent hover:underline\">\n {seeAll.label}\n </BlockLink>\n )}\n <button type=\"button\" aria-label={previousLabel} disabled={edge.start} onClick={() => page(-1)} className={ARROW}>\n <Chevron flip />\n </button>\n <button type=\"button\" aria-label={nextLabel} disabled={edge.end} onClick={() => page(1)} className={ARROW}>\n <Chevron />\n </button>\n </div>\n <ul\n ref={row}\n onScroll={measure}\n // biome-ignore: a scroll container must take the keyboard focus to scroll with the arrow keys\n tabIndex={0}\n aria-labelledby={headingId}\n className=\"m-0 flex list-none snap-x snap-mandatory items-stretch gap-3 overflow-x-auto overflow-y-hidden overscroll-x-contain p-0 pt-1 -mt-1 pb-2 [scrollbar-width:none] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&::-webkit-scrollbar]:hidden\"\n >\n {items.map((item, i) => (\n <li key={getId(item)} className=\"w-[9.5rem] shrink-0 snap-start sm:w-44\">\n {renderItem(item, i)}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","// Client (hover / focus swaps the picture for its animated preview). A video in a grid or a shelf: the picture in a 16:9\n// or 9:16 frame (a source of the other shape is shown inside, never stretched), badges, duration, the title on two lines\n// reserved, the creator, a count and one quick action — the same height of body in every card so a row aligns.\nimport * as React from \"react\";\n\nimport { Avatar } from \"../avatar\";\nimport type { DefaultAvatar } from \"../avatar/default-avatar\";\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\nimport { isLeader, subscribeLeader, trackVisibility } from \"./preview-focus\";\n\nexport type VideoCardAspect = \"landscape\" | \"portrait\";\n\nexport interface VideoCardCreator {\n /** The creator's name. */\n name: string;\n /** Their photo. */\n avatarSrc?: string | null;\n /** Their profile. */\n href?: string;\n /** The Krizaka default picture when there is no photo (a brand and a seed). */\n defaultAvatar?: DefaultAvatar;\n}\n\nexport interface VideoCardProps extends Omit<React.ComponentProps<\"article\">, \"title\"> {\n /** The title; it names the card and is its link. */\n title: string;\n /** Where the card opens. */\n href: string;\n /** The app's router link (Next's `Link`). */\n linkAs?: LinkComponent;\n /**\n * The frame: `landscape` (16:9) or `portrait` (9:16).\n * @default \"landscape\"\n */\n aspect?: VideoCardAspect;\n /**\n * `stack` (picture over text) or `row` (picture beside the text: the list mode of a section).\n * @default \"stack\"\n */\n layout?: \"stack\" | \"row\";\n /** The picture. */\n poster?: string | null;\n /**\n * An animated picture (WebP, a few hundred kB) that fades in over the poster once the pointer has rested on the card\n * (or it is focused) for `previewDelay`, and is removed again on leave. It is never requested before. On a phone (no\n * hover) only the card most inside the viewport plays it, unless the person asked for less data or less motion.\n */\n previewSrc?: string | null;\n /**\n * How long the pointer must rest before the preview is requested, in ms: a pointer crossing the grid loads nothing.\n * @default 200\n */\n previewDelay?: number;\n /**\n * `fetchPriority` of the poster: `high` for the first row (the largest contentful paint).\n * @default \"auto\"\n */\n posterPriority?: \"high\" | \"low\" | \"auto\";\n /**\n * `cover` fills the frame; `contain` draws the whole picture over a blurred copy of itself (a source of the other\n * orientation: no cropped face, no black bar).\n * @default \"cover\"\n */\n fit?: \"cover\" | \"contain\";\n /** The length, already formatted (`3:42`). */\n duration?: string;\n /** Badges at the top-left of the picture (Free, a price, 18+). Put them on `scrim` so they read in both themes. */\n badges?: React.ReactNode;\n /** Who made it: name, photo, profile. */\n creator?: VideoCardCreator;\n /** What is counted (`12.4K views`), already formatted. */\n meta?: React.ReactNode;\n /** One quick action at the end of the footer (a tip, a save). Its clicks must not follow the card's link. */\n action?: React.ReactNode;\n /** A sensitive picture: blurred and scaled so nothing shows (put the reveal button in `overlay`). */\n blurred?: boolean;\n /** Over the whole picture, above the card's link (a veil, a reveal button). */\n overlay?: React.ReactNode;\n /** Shown instead of the picture while there is none. */\n fallback?: React.ReactNode;\n /** `eager` for the first cards of a page. */\n loading?: \"lazy\" | \"eager\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** A video card whose frame, body and footer have one height per aspect, so a grid row or a shelf never staggers. */\nexport function VideoCard({\n title,\n href,\n linkAs,\n aspect = \"landscape\",\n layout = \"stack\",\n poster,\n previewSrc,\n previewDelay = 200,\n posterPriority = \"auto\",\n fit = \"cover\",\n duration,\n badges,\n creator,\n meta,\n action,\n fallback,\n blurred = false,\n overlay,\n loading = \"lazy\",\n className,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ref,\n ...props\n}: VideoCardProps) {\n const [node, setNode] = React.useState<HTMLElement | null>(null);\n const setRef = React.useCallback(\n (el: HTMLElement | null) => {\n setNode(el);\n if (typeof ref === \"function\") ref(el);\n else if (ref) (ref as React.RefObject<HTMLElement | null>).current = el;\n },\n [ref],\n );\n const canPreview = Boolean(previewSrc) && !blurred;\n const { live, arm, disarm } = usePreviewIntent(node, canPreview, previewDelay);\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <article\n ref={setRef}\n data-aspect={aspect}\n data-layout={layout}\n className={cn(\"group relative h-full min-w-0\", className)}\n data-preview={live ? \"on\" : undefined}\n onMouseEnter={(e) => (arm(\"pointer\"), onMouseEnter?.(e))}\n onMouseLeave={(e) => (disarm(\"pointer\"), onMouseLeave?.(e))}\n onFocus={(e) => (arm(\"focus\"), onFocus?.(e))}\n onBlur={(e) => (disarm(\"focus\"), onBlur?.(e))}\n {...props}\n >\n <Card.Root interactive tone=\"glass\" className={cn(\"h-full w-full max-w-full\", row ? \"flex-row\" : \"flex-col\")}>\n <Card.Media aspect=\"auto\" className={cn(\"shrink-0\", FRAME[aspect], row && (aspect === \"portrait\" ? \"w-24 sm:w-28\" : \"w-40 sm:w-56\"))}>\n {fit === \"contain\" && poster && <img src={poster} alt=\"\" aria-hidden loading=\"lazy\" className=\"absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl\" />}\n <Card.Image\n src={poster}\n loading={loading}\n fetchPriority={posterPriority === \"auto\" ? undefined : posterPriority}\n fallback={fallback}\n className={cn(fit === \"contain\" && \"relative object-contain\", blurred && \"scale-110 blur-xl\")}\n />\n {live && previewSrc && <PreviewLayer src={previewSrc} contain={fit === \"contain\"} />}\n {overlay && <div className=\"absolute inset-0 z-20 flex\">{overlay}</div>}\n {badges && (\n <Card.Overlay corner=\"top-left\" className=\"theme-dark pointer-events-none flex-wrap\">\n {badges}\n </Card.Overlay>\n )}\n {duration && (\n <Card.Overlay corner=\"bottom-right\" className=\"pointer-events-none\">\n <span className=\"rounded-sm bg-scrim px-1.5 py-0.5 font-mono text-[11px] text-fg-on-media\">{duration}</span>\n </Card.Overlay>\n )}\n </Card.Media>\n {/* `static`: the body must not be the containing block of the title link's ::after, or the link would cover the text only and the picture would not open the video. */}\n <Card.Body className=\"static min-w-0 flex-1 justify-between gap-2 p-3\">\n <h3 className=\"m-0 min-h-[2.5em] text-sm font-semibold leading-tight text-fg\">\n <BlockLink href={href} linkAs={linkAs} className=\"line-clamp-2 outline-none after:absolute after:inset-0 after:z-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-ring\">\n {title}\n </BlockLink>\n </h3>\n {/* A narrow card (9:16 on a shelf) puts the count and the action on a second line so the name is never cut to an initial. */}\n <div className={cn(\"relative z-10 text-xs text-fg-secondary\", tall ? \"flex flex-col gap-1\" : \"flex h-8 items-center gap-2\")}>\n {creator && (\n <div className=\"flex h-6 min-w-0 items-center gap-2\">\n <Avatar src={creator.avatarSrc} defaultAvatar={creator.defaultAvatar} alt=\"\" fallback={creator.name.charAt(0)} size=\"xs\" className=\"shrink-0\" />\n {creator.href ? (\n <BlockLink href={creator.href} linkAs={linkAs} className=\"min-w-0 truncate hover:text-fg\">\n {creator.name}\n </BlockLink>\n ) : (\n <span className=\"min-w-0 truncate\">{creator.name}</span>\n )}\n </div>\n )}\n {(meta || action) && (\n <div className={cn(\"flex items-center gap-2\", tall ? \"h-7 justify-between\" : \"ml-auto shrink-0\")}>\n {meta && <span className=\"shrink-0 font-mono text-[11px] text-fg-muted\">{meta}</span>}\n {action && <span className=\"shrink-0\">{action}</span>}\n </div>\n )}\n </div>\n </Card.Body>\n </Card.Root>\n </article>\n );\n}\n\n/** The animated preview, fading in over the poster once it has loaded; unmounted (so unloaded) on leave. */\nfunction PreviewLayer({ src, contain }: { src: string; contain: boolean }) {\n const [ready, setReady] = React.useState(false);\n return (\n <img\n src={src}\n alt=\"\"\n aria-hidden\n decoding=\"async\"\n data-preview-layer=\"\"\n data-ready={ready ? \"\" : undefined}\n onLoad={() => setReady(true)}\n className={cn(\"pointer-events-none absolute inset-0 h-full w-full opacity-0 transition-opacity duration-300 data-[ready]:opacity-100 motion-reduce:transition-none\", contain ? \"object-contain\" : \"object-cover\")}\n />\n );\n}\n\ntype Cause = \"pointer\" | \"focus\";\n\nconst matches = (query: string) => typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(query).matches;\nconst hoverCapable = () => matches(\"(hover: hover)\");\nconst saveData = () => typeof navigator !== \"undefined\" && (navigator as Navigator & { connection?: { saveData?: boolean } }).connection?.saveData === true;\n\n/**\n * When the preview is wanted. A desktop pointer or the keyboard focus must rest `delay` ms first; on a phone the card\n * the page shows most (and only one) wants it, never under Save-Data or reduced motion. Leaving clears everything.\n */\nfunction usePreviewIntent(node: HTMLElement | null, enabled: boolean, delay: number) {\n const [causes, setCauses] = React.useState<ReadonlySet<Cause>>(new Set());\n const timers = React.useRef(new Map<Cause, ReturnType<typeof setTimeout>>());\n const arm = React.useCallback(\n (cause: Cause) => {\n if (!enabled || saveData()) return;\n if (cause === \"pointer\" && !hoverCapable()) return;\n clearTimeout(timers.current.get(cause));\n timers.current.set(\n cause,\n setTimeout(() => setCauses((c) => new Set(c).add(cause)), delay),\n );\n },\n [enabled, delay],\n );\n const disarm = React.useCallback((cause: Cause) => {\n clearTimeout(timers.current.get(cause));\n timers.current.delete(cause);\n setCauses((c) => {\n if (!c.has(cause)) return c;\n const next = new Set(c);\n next.delete(cause);\n return next;\n });\n }, []);\n React.useEffect(() => {\n const pending = timers.current;\n return () => {\n for (const t of pending.values()) clearTimeout(t);\n pending.clear();\n };\n }, []);\n\n // A phone: the single most visible card, after the same rest.\n const touch = enabled && !hoverCapable();\n const leading = React.useSyncExternalStore(\n subscribeLeader,\n () => isLeader(node),\n () => false,\n );\n React.useEffect(() => {\n if (!node || !touch) return;\n return trackVisibility(node);\n }, [node, touch]);\n const [ready, setReady] = React.useState(false);\n const [wasLeading, setWasLeading] = React.useState(false);\n if (leading !== wasLeading) {\n setWasLeading(leading);\n if (!leading) setReady(false);\n }\n const wanted = touch && leading && !saveData() && !matches(\"(prefers-reduced-motion: reduce)\");\n React.useEffect(() => {\n if (!wanted) return;\n const t = setTimeout(() => setReady(true), delay);\n return () => clearTimeout(t);\n }, [wanted, delay]);\n\n return { live: enabled && (causes.size > 0 || (wanted && ready)), arm, disarm };\n}\n","// Client only. Which card of the page is the most visible: on a phone there is no hover, so exactly one card at a time\n// (the one most inside the viewport) may play its preview. One IntersectionObserver for the whole page, no per-card\n// observer; the answer is a store read with `useSyncExternalStore`.\nconst MIN_RATIO = 0.6;\nconst ratios = new Map<Element, number>();\nconst listeners = new Set<() => void>();\nlet observer: IntersectionObserver | null = null;\nlet leader: Element | null = null;\n\nfunction elect() {\n let best: Element | null = null;\n let bestRatio = MIN_RATIO - Number.EPSILON;\n for (const [el, ratio] of ratios) {\n if (ratio > bestRatio) {\n best = el;\n bestRatio = ratio;\n }\n }\n if (best === leader) return;\n leader = best;\n for (const l of listeners) l();\n}\n\n/** Starts counting an element's visibility; returns the function that stops it. */\nexport function trackVisibility(el: Element): () => void {\n if (typeof IntersectionObserver === \"undefined\") return () => {};\n observer ??= new IntersectionObserver(\n (entries) => {\n for (const e of entries) ratios.set(e.target, e.isIntersecting ? e.intersectionRatio : 0);\n elect();\n },\n { threshold: [0, 0.25, 0.5, 0.6, 0.75, 1] },\n );\n ratios.set(el, 0);\n observer.observe(el);\n return () => {\n observer?.unobserve(el);\n ratios.delete(el);\n elect();\n };\n}\n\nexport const subscribeLeader = (l: () => void) => (listeners.add(l), () => void listeners.delete(l));\n\n/** Whether this element is the card the page is showing most. */\nexport const isLeader = (el: Element | null) => el !== null && leader === el;\n\n/** Test seam: forget everything. */\nexport function resetPreviewFocus() {\n observer?.disconnect();\n observer = null;\n ratios.clear();\n leader = null;\n}\n","// A video card on its way: the same frame, body and footer heights as `VideoCard`, so nothing moves when it arrives.\nimport * as React from \"react\";\n\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\nimport { Skeleton } from \"../skeleton\";\nimport type { VideoCardAspect } from \"./video-card\";\n\nexport interface VideoCardSkeletonProps extends React.ComponentProps<\"div\"> {\n /** `landscape` (16:9) or `portrait` (9:16), as the card it stands for. @default \"landscape\" */\n aspect?: VideoCardAspect;\n /** `stack` or `row`, as the card it stands for. @default \"stack\" */\n layout?: \"stack\" | \"row\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** The placeholder of a `VideoCard` (decorative: announce the wait on the list, with `MediaGridSkeleton`). */\nexport function VideoCardSkeleton({ aspect = \"landscape\", layout = \"stack\", className, ...props }: VideoCardSkeletonProps) {\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <div aria-hidden data-skeleton=\"video-card\" data-aspect={aspect} data-layout={layout} className={cn(\"h-full min-w-0\", className)} {...props}>\n <Card.Root tone=\"glass\" className={cn(\"h-full w-full max-w-full\", row ? \"flex-row\" : \"flex-col\")}>\n <Card.Media aspect=\"auto\" className={cn(\"shrink-0\", FRAME[aspect], row && (aspect === \"portrait\" ? \"w-24 sm:w-28\" : \"w-40 sm:w-56\"))}>\n <Skeleton shape=\"rect\" className=\"h-full w-full rounded-none\" />\n </Card.Media>\n <Card.Body className=\"static min-w-0 flex-1 justify-between gap-2 p-3\">\n <div className=\"flex min-h-[2.5em] flex-col justify-center gap-1.5\">\n <Skeleton className=\"h-3\" />\n <Skeleton className=\"h-3 w-3/5\" />\n </div>\n <div className={cn(\"flex text-xs\", tall ? \"flex-col gap-1\" : \"h-8 items-center gap-2\")}>\n <div className=\"flex h-6 min-w-0 items-center gap-2\">\n <Skeleton shape=\"circle\" className=\"h-6 w-6 shrink-0\" />\n <Skeleton className=\"h-2.5 w-20\" />\n </div>\n <div className={cn(\"flex items-center\", tall ? \"h-7\" : \"ml-auto\")}>\n <Skeleton className=\"h-2.5 w-14\" />\n </div>\n </div>\n </Card.Body>\n </Card.Root>\n </div>\n );\n}\n\nexport interface MediaGridSkeletonProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** What is loading, passed translated (\"Loading videos\"): announced once, the cards are hidden from assistive technology. */\n label: string;\n /** Cards in the grid. @default 8 */\n count?: number;\n /** Cards on the Shorts shelf above the grid (`split` mode); 0 for none. @default 0 */\n shelfCount?: number;\n /** `grid` or `list`. @default \"grid\" */\n layout?: \"grid\" | \"list\";\n /** The frame of the grid. @default \"landscape\" */\n frame?: VideoCardAspect;\n}\n\nconst GRID = {\n landscape: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\",\n portrait: \"grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6\",\n} as const;\n\n/** The placeholder of a `MediaGrid`: the same shelf and grid, skeleton cards, one polite announcement. */\nexport function MediaGridSkeleton({ label, count = 8, shelfCount = 0, layout = \"grid\", frame = \"landscape\", className, ...props }: MediaGridSkeletonProps) {\n const row = layout === \"list\";\n return (\n <div role=\"status\" aria-busy=\"true\" data-media-grid-skeleton=\"\" className={cn(\"flex min-w-0 flex-col gap-8\", className)} {...props}>\n <span className=\"sr-only\">{label}</span>\n {shelfCount > 0 && (\n <div aria-hidden className=\"min-w-0\">\n <Skeleton className=\"mb-3 h-4 w-24\" />\n <ul className=\"m-0 flex list-none items-stretch gap-3 overflow-hidden p-0\">\n {Array.from({ length: shelfCount }, (_, i) => (\n <li key={i} className=\"w-[9.5rem] shrink-0 sm:w-44\">\n <VideoCardSkeleton aspect=\"portrait\" />\n </li>\n ))}\n </ul>\n </div>\n )}\n <ul aria-hidden className={cn(\"m-0 grid list-none auto-rows-fr gap-4 p-0\", row ? \"grid-cols-1\" : GRID[frame])}>\n {Array.from({ length: count }, (_, i) => (\n <li key={i} className=\"min-w-0\">\n <VideoCardSkeleton aspect={frame} layout={row ? \"row\" : \"stack\"} />\n </li>\n ))}\n </ul>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","React","React","jsx","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","FRAME","GRID"]}
package/dist/page-hero.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-YKEIOYJ5.js";
4
4
  import {
5
5
  BlockLink
6
- } from "./chunk-2AGSO3WH.js";
6
+ } from "./chunk-FVGFPB73.js";
7
7
  import {
8
8
  ArrowGlyph
9
9
  } from "./chunk-XCBVFMNV.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BlockLink
3
- } from "./chunk-2AGSO3WH.js";
3
+ } from "./chunk-FVGFPB73.js";
4
4
  import {
5
5
  cn
6
6
  } from "./chunk-W675RFOA.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BlockLink
3
- } from "./chunk-2AGSO3WH.js";
3
+ } from "./chunk-FVGFPB73.js";
4
4
  import {
5
5
  CheckGlyph
6
6
  } from "./chunk-XCBVFMNV.js";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  BlockLink
4
- } from "./chunk-C7LTF5CC.js";
4
+ } from "./chunk-ENOS6ETI.js";
5
5
 
6
6
  // src/slot-picker/slot-picker.tsx
7
7
  import * as React from "react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krizaka/ui",
3
- "version": "3.52.0",
3
+ "version": "3.53.0",
4
4
  "description": "The Krizaka front-end platform's components: the primitives (button, card, dialog, toast, menu, field, tabs, chip, switch, slider, command palette, theme, countdown…) on the semantic --kz-* tokens, the animated marks (Krizaka, Orazaka, Orochia, Yasakia, Yororis) and the motion signature — web and /native.",
5
5
  "keywords": [
6
6
  "krizaka",
@@ -525,6 +525,10 @@
525
525
  "types": "./dist/page-index.d.ts",
526
526
  "import": "./dist/page-index.js"
527
527
  },
528
+ "./chapter": {
529
+ "types": "./dist/chapter.d.ts",
530
+ "import": "./dist/chapter.js"
531
+ },
528
532
  "./footnote": {
529
533
  "types": "./dist/footnote.d.ts",
530
534
  "import": "./dist/footnote.js"
@@ -797,7 +801,7 @@
797
801
  ],
798
802
  "peerDependencies": {
799
803
  "@krizaka/query": ">=0.2.1",
800
- "@krizaka/tailwind": ">=3.52.0",
804
+ "@krizaka/tailwind": ">=3.53.0",
801
805
  "@maplibre/maplibre-react-native": ">=11",
802
806
  "@shopify/flash-list": ">=2",
803
807
  "expo-camera": ">=16",
@@ -856,8 +860,8 @@
856
860
  "tsup": "^8.5.1",
857
861
  "typescript": "^5.9.0",
858
862
  "vitest": "^4.1.11",
859
- "@krizaka/config": "0.7.0",
860
- "@krizaka/query": "0.2.1"
863
+ "@krizaka/query": "0.2.1",
864
+ "@krizaka/config": "0.7.0"
861
865
  },
862
866
  "engines": {
863
867
  "node": ">=22"
@@ -2023,6 +2027,16 @@
2023
2027
  "clsx"
2024
2028
  ]
2025
2029
  },
2030
+ {
2031
+ "name": "./chapter",
2032
+ "path": "dist/chapter.js",
2033
+ "limit": "1.5 kB",
2034
+ "gzip": true,
2035
+ "ignore": [
2036
+ "tailwind-variants",
2037
+ "clsx"
2038
+ ]
2039
+ },
2026
2040
  {
2027
2041
  "name": "./footnote",
2028
2042
  "path": "dist/footnote.js",
@@ -2678,8 +2692,8 @@
2678
2692
  "tailwind-variants": "^3.3.1",
2679
2693
  "zod": "^4.6.5",
2680
2694
  "@krizaka/intl": "^0.3.0",
2681
- "@krizaka/pacer": "^0.1.0",
2682
- "@krizaka/tokens": "^3.52.0"
2695
+ "@krizaka/tokens": "^3.53.0",
2696
+ "@krizaka/pacer": "^0.1.0"
2683
2697
  },
2684
2698
  "scripts": {
2685
2699
  "build": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true});for(const f of fs.readdirSync('registry/examples',{recursive:true}))if(/\\.(js|d\\.ts)$/.test(f))fs.rmSync('registry/examples/'+f)\" && tsup && node -e \"require('node:fs').copyFileSync('src/motion.css','dist/motion.css');require('node:fs').copyFileSync('src/blocks.css','dist/blocks.css');require('node:fs').copyFileSync('src/story.css','dist/story.css')\" && node scripts/build-registry.mjs",
@@ -179,7 +179,7 @@
179
179
  },
180
180
  {
181
181
  "path": "meta.ts",
182
- "content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which ui.krizaka.com (apps/site) renders as\n// ui.krizaka.com/components/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"agenda\"\n | \"account-settings\"\n | \"drop-overlay\"\n | \"upload-queue\"\n | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"taped-photo\"\n | \"text-style\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\n | \"specimen-tag\"\n | \"action-bar\"\n | \"action-sheet\"\n | \"activity-feed\"\n | \"alert\"\n | \"app-header\"\n | \"app-shell\"\n | \"argument-card\"\n | \"audio-player\"\n | \"auth-layout\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"captcha\"\n | \"card\"\n | \"card-grid\"\n | \"catalogue-page\"\n | \"changelog-page\"\n | \"chat\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"chip-row\"\n | \"choice-grid\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"comparison-table\"\n | \"command\"\n | \"component-page\"\n | \"confirm-button\"\n | \"contact-page\"\n | \"continue-prompt\"\n | \"countdown\"\n | \"cover-hero\"\n | \"cta-panel\"\n | \"dashboard-layout\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"description-list\"\n | \"detail-layout\"\n | \"dialog\"\n | \"docs-article-page\"\n | \"docs-hub-page\"\n | \"docs-layout\"\n | \"docs-nav\"\n | \"document-viewer\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"engine-flow\"\n | \"error-page\"\n | \"fab\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"force-update-screen\"\n | \"form\"\n | \"gallery-page\"\n | \"genui\"\n | \"glossary\"\n | \"glossary-term\"\n | \"glow-card\"\n | \"goal-gauge\"\n | \"header\"\n | \"how-it-works-page\"\n | \"image-cropper\"\n | \"image-viewer\"\n | \"iso\"\n | \"kanban\"\n | \"kbd\"\n | \"kpi-explained\"\n | \"landing-page\"\n | \"landscape\"\n | \"legal-page\"\n | \"link-card\"\n | \"list\"\n | \"loader\"\n | \"longform-page\"\n | \"maintenance-screen\"\n | \"map\"\n | \"markdown\"\n | \"meta-row\"\n | \"waveform\"\n | \"marketing-layout\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascot-state\"\n | \"mascots\"\n | \"match-dialog\"\n | \"media-capture\"\n | \"media-grid\"\n | \"language-switch\"\n | \"media-gallery\"\n | \"media-picker\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"onboarding\"\n | \"opening-hours\"\n | \"otp-input\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"permission-prompt\"\n | \"photo-grid\"\n | \"pointer-light\"\n | \"popover\"\n | \"pricing-page\"\n | \"product-page\"\n | \"profile-card\"\n | \"progress\"\n | \"promise-card\"\n | \"pull-to-refresh\"\n | \"radio-group\"\n | \"router\"\n | \"rail-nav\"\n | \"recipes\"\n | \"screen\"\n | \"scroll-stage\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"service-card\"\n | \"settings-layout\"\n | \"account-menu\"\n | \"showcase\"\n | \"step-showcase\"\n | \"site-footer\"\n | \"sites\"\n | \"skeleton\"\n | \"skip-link\"\n | \"slider\"\n | \"slot-picker\"\n | \"slot\"\n | \"spinner\"\n | \"sticky-action\"\n | \"splash-handoff\"\n | \"split-view\"\n | \"stage-banner\"\n | \"stat\"\n | \"status-page\"\n | \"step-progress\"\n | \"stepper\"\n | \"swipe-deck\"\n | \"swipeable-row\"\n | \"switch\"\n | \"tab-bar\"\n | \"tabs\"\n | \"tag-input\"\n | \"tag-selector\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"tree-view\"\n | \"txt\"\n | \"update-prompt\"\n | \"verified-badge\"\n | \"vertical-video\"\n | \"video-player\"\n | \"video-trimmer\"\n | \"virtual\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/**\n * Why a component is not on a platform — a decision, never a silence (the parity matrix of ui.krizaka.com/platforms):\n * - `gap` (✗): it belongs there and is not built yet; `issue` is the issue that tracks it (`krizaka/krizaka-ui#275`);\n * - `n/a`: it is not meant for that platform (a site's page block on a phone, a swipe on a desktop); `use` names the\n * component that answers there, when one does.\n */\nexport type Absence =\n | { readonly status: \"gap\"; readonly issue: string; readonly reason: string; readonly use?: undefined }\n | { readonly status: \"n/a\"; readonly reason: string; readonly use?: ComponentName; readonly issue?: undefined };\n\n/**\n * Desktop is the Orazaka Mac app (Tauri 2: the system WebView renders the web components — ADR-002). `web`: the web\n * component runs there as it is; `desktop`: it also has a desktop form (a window's title bar, a denser layout…), said in\n * its documentation; otherwise the absence and why.\n */\nexport type DesktopSupport = \"web\" | \"desktop\" | Absence;\n\n/**\n * The three platforms of Krizaka UI — web · native (React Native, Expo) · desktop — for one component. The side a\n * component has is `platforms`; the side it lacks says why here: `native` is required for (and only for) a web-only\n * component, `web` for a native-only one; `desktop` always. `scripts/registry.test.mjs` fails on a missing decision.\n */\nexport interface Parity {\n readonly web?: Absence;\n readonly native?: Absence;\n readonly desktop: DesktopSupport;\n}\n\n/**\n * `stable`: its API only changes in a major. `beta`: it may still change in a minor. `deprecated`: no product uses it and\n * no work plans to — it still works, says what replaces it, and goes in the major named by `deprecated.removedIn`.\n */\nexport type Status = \"stable\" | \"beta\" | \"deprecated\";\n\n/** What a deprecated component says (required when `status` is `deprecated`, absent otherwise). */\nexport interface Deprecation {\n /** The version that deprecated it (`3.6.0`). */\n readonly since: string;\n /** The major that removes it (`4.0.0`). */\n readonly removedIn: string;\n /** What replaces it, when a component does. */\n readonly use?: ComponentName;\n /** Why it goes: no product uses it, no planned work needs it. */\n readonly reason: string;\n}\n\n/**\n * The group of the catalogue. `media`: video, sound, camera, files, cropping. `blocks`: the page blocks — the frame,\n * the hero, sections, cards that lead or argue, decisions, code, calls to act — that every page of a site is made of.\n * `layouts`: the shells of whole screens — an application, a dashboard, settings, sign-in, an object, a list and its\n * item, a site's page, a documentation page — each with its screens. `templates`: the page templates — whole pages of a\n * site (a landing, a product, a docs hub, a long read, a changelog, pricing, status, an error…), each a distinct\n * composition of the blocks, words and content as props.\n */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layouts\" | \"templates\" | \"layout\" | \"foundations\";\n\n/** Why a reader needs a template: the seven intents the templates are grouped by (sidebar sub-headings, catalogue filter). */\nexport type TemplatePurpose = \"convince\" | \"explain\" | \"show\" | \"act\" | \"operate\" | \"converse\" | \"recover\";\n\n/** The groups of templates, in reading order: the title, and the one line that says when to come to that group. */\nexport const templatePurposes = {\n convince: { title: \"Convince\", useWhen: \"You come here when a visitor must decide: a landing, a product, a price, a comparison, a proof.\" },\n explain: { title: \"Explain\", useWhen: \"You come here when a reader must understand: how it works, a documentation hub or article, a changelog, a FAQ, a policy.\" },\n show: { title: \"Show\", useWhen: \"You come here when the work itself is the argument: a gallery, a story, a case study, an object and its details.\" },\n act: { title: \"Act\", useWhen: \"You come here when a person must do something once: reach the team, sign in or up, set up, pay.\" },\n operate: { title: \"Operate\", useWhen: \"You come here when a person works every day: a dashboard, a console with a table, settings, an app shell.\" },\n converse: { title: \"Converse\", useWhen: \"You come here when people talk: an inbox, a chat, comments, a notifications centre.\" },\n recover: { title: \"Recover\", useWhen: \"You come here when the way is blocked: an empty list, an error, a missing page, maintenance, a product still being built.\" },\n} as const satisfies Record<TemplatePurpose, { readonly title: string; readonly useWhen: string }>;\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\ninterface ExampleBase {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** A plain example, or a template: a whole screen with its intent (`purpose`) and the user goal its layout serves (`why`). */\nexport type Example =\n | (ExampleBase & { readonly template?: false; readonly purpose?: undefined; readonly why?: undefined })\n | (ExampleBase & {\n /**\n * A template: a whole screen of a product composed from the platform (a layout and its blocks, real words, its\n * phone version thought out), copied as a starting point — at most 160 lines, listed on ui.krizaka.com/templates.\n */\n readonly template: true;\n /** The intent that groups it: why you need this block. */\n readonly purpose: TemplatePurpose;\n /** Why this layout: the user goal it serves, in one sentence. */\n readonly why: string;\n });\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n /** Required for, and only for, a `deprecated` component. */\n readonly deprecated?: Deprecation;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** The platforms it is not on, and why; and its desktop form (see `Parity`). */\n readonly parity: Parity;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
182
+ "content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which ui.krizaka.com (apps/site) renders as\n// ui.krizaka.com/components/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"agenda\"\n | \"account-settings\"\n | \"drop-overlay\"\n | \"upload-queue\"\n | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"taped-photo\"\n | \"text-style\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\n | \"chapter\"\n | \"specimen-tag\"\n | \"action-bar\"\n | \"action-sheet\"\n | \"activity-feed\"\n | \"alert\"\n | \"app-header\"\n | \"app-shell\"\n | \"argument-card\"\n | \"audio-player\"\n | \"auth-layout\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"captcha\"\n | \"card\"\n | \"card-grid\"\n | \"catalogue-page\"\n | \"changelog-page\"\n | \"chat\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"chip-row\"\n | \"choice-grid\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"comparison-table\"\n | \"command\"\n | \"component-page\"\n | \"confirm-button\"\n | \"contact-page\"\n | \"continue-prompt\"\n | \"countdown\"\n | \"cover-hero\"\n | \"cta-panel\"\n | \"dashboard-layout\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"description-list\"\n | \"detail-layout\"\n | \"dialog\"\n | \"docs-article-page\"\n | \"docs-hub-page\"\n | \"docs-layout\"\n | \"docs-nav\"\n | \"document-viewer\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"engine-flow\"\n | \"error-page\"\n | \"fab\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"force-update-screen\"\n | \"form\"\n | \"gallery-page\"\n | \"genui\"\n | \"glossary\"\n | \"glossary-term\"\n | \"glow-card\"\n | \"goal-gauge\"\n | \"header\"\n | \"how-it-works-page\"\n | \"image-cropper\"\n | \"image-viewer\"\n | \"iso\"\n | \"kanban\"\n | \"kbd\"\n | \"kpi-explained\"\n | \"landing-page\"\n | \"landscape\"\n | \"legal-page\"\n | \"link-card\"\n | \"list\"\n | \"loader\"\n | \"longform-page\"\n | \"maintenance-screen\"\n | \"map\"\n | \"markdown\"\n | \"meta-row\"\n | \"waveform\"\n | \"marketing-layout\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascot-state\"\n | \"mascots\"\n | \"match-dialog\"\n | \"media-capture\"\n | \"media-grid\"\n | \"language-switch\"\n | \"media-gallery\"\n | \"media-picker\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"onboarding\"\n | \"opening-hours\"\n | \"otp-input\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"permission-prompt\"\n | \"photo-grid\"\n | \"pointer-light\"\n | \"popover\"\n | \"pricing-page\"\n | \"product-page\"\n | \"profile-card\"\n | \"progress\"\n | \"promise-card\"\n | \"pull-to-refresh\"\n | \"radio-group\"\n | \"router\"\n | \"rail-nav\"\n | \"recipes\"\n | \"screen\"\n | \"scroll-stage\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"service-card\"\n | \"settings-layout\"\n | \"account-menu\"\n | \"showcase\"\n | \"step-showcase\"\n | \"site-footer\"\n | \"sites\"\n | \"skeleton\"\n | \"skip-link\"\n | \"slider\"\n | \"slot-picker\"\n | \"slot\"\n | \"spinner\"\n | \"sticky-action\"\n | \"splash-handoff\"\n | \"split-view\"\n | \"stage-banner\"\n | \"stat\"\n | \"status-page\"\n | \"step-progress\"\n | \"stepper\"\n | \"swipe-deck\"\n | \"swipeable-row\"\n | \"switch\"\n | \"tab-bar\"\n | \"tabs\"\n | \"tag-input\"\n | \"tag-selector\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"tree-view\"\n | \"txt\"\n | \"update-prompt\"\n | \"verified-badge\"\n | \"vertical-video\"\n | \"video-player\"\n | \"video-trimmer\"\n | \"virtual\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/**\n * Why a component is not on a platform — a decision, never a silence (the parity matrix of ui.krizaka.com/platforms):\n * - `gap` (✗): it belongs there and is not built yet; `issue` is the issue that tracks it (`krizaka/krizaka-ui#275`);\n * - `n/a`: it is not meant for that platform (a site's page block on a phone, a swipe on a desktop); `use` names the\n * component that answers there, when one does.\n */\nexport type Absence =\n | { readonly status: \"gap\"; readonly issue: string; readonly reason: string; readonly use?: undefined }\n | { readonly status: \"n/a\"; readonly reason: string; readonly use?: ComponentName; readonly issue?: undefined };\n\n/**\n * Desktop is the Orazaka Mac app (Tauri 2: the system WebView renders the web components — ADR-002). `web`: the web\n * component runs there as it is; `desktop`: it also has a desktop form (a window's title bar, a denser layout…), said in\n * its documentation; otherwise the absence and why.\n */\nexport type DesktopSupport = \"web\" | \"desktop\" | Absence;\n\n/**\n * The three platforms of Krizaka UI — web · native (React Native, Expo) · desktop — for one component. The side a\n * component has is `platforms`; the side it lacks says why here: `native` is required for (and only for) a web-only\n * component, `web` for a native-only one; `desktop` always. `scripts/registry.test.mjs` fails on a missing decision.\n */\nexport interface Parity {\n readonly web?: Absence;\n readonly native?: Absence;\n readonly desktop: DesktopSupport;\n}\n\n/**\n * `stable`: its API only changes in a major. `beta`: it may still change in a minor. `deprecated`: no product uses it and\n * no work plans to — it still works, says what replaces it, and goes in the major named by `deprecated.removedIn`.\n */\nexport type Status = \"stable\" | \"beta\" | \"deprecated\";\n\n/** What a deprecated component says (required when `status` is `deprecated`, absent otherwise). */\nexport interface Deprecation {\n /** The version that deprecated it (`3.6.0`). */\n readonly since: string;\n /** The major that removes it (`4.0.0`). */\n readonly removedIn: string;\n /** What replaces it, when a component does. */\n readonly use?: ComponentName;\n /** Why it goes: no product uses it, no planned work needs it. */\n readonly reason: string;\n}\n\n/**\n * The group of the catalogue. `media`: video, sound, camera, files, cropping. `blocks`: the page blocks — the frame,\n * the hero, sections, cards that lead or argue, decisions, code, calls to act — that every page of a site is made of.\n * `layouts`: the shells of whole screens — an application, a dashboard, settings, sign-in, an object, a list and its\n * item, a site's page, a documentation page — each with its screens. `templates`: the page templates — whole pages of a\n * site (a landing, a product, a docs hub, a long read, a changelog, pricing, status, an error…), each a distinct\n * composition of the blocks, words and content as props.\n */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layouts\" | \"templates\" | \"layout\" | \"foundations\";\n\n/** Why a reader needs a template: the seven intents the templates are grouped by (sidebar sub-headings, catalogue filter). */\nexport type TemplatePurpose = \"convince\" | \"explain\" | \"show\" | \"act\" | \"operate\" | \"converse\" | \"recover\";\n\n/** The groups of templates, in reading order: the title, and the one line that says when to come to that group. */\nexport const templatePurposes = {\n convince: { title: \"Convince\", useWhen: \"You come here when a visitor must decide: a landing, a product, a price, a comparison, a proof.\" },\n explain: { title: \"Explain\", useWhen: \"You come here when a reader must understand: how it works, a documentation hub or article, a changelog, a FAQ, a policy.\" },\n show: { title: \"Show\", useWhen: \"You come here when the work itself is the argument: a gallery, a story, a case study, an object and its details.\" },\n act: { title: \"Act\", useWhen: \"You come here when a person must do something once: reach the team, sign in or up, set up, pay.\" },\n operate: { title: \"Operate\", useWhen: \"You come here when a person works every day: a dashboard, a console with a table, settings, an app shell.\" },\n converse: { title: \"Converse\", useWhen: \"You come here when people talk: an inbox, a chat, comments, a notifications centre.\" },\n recover: { title: \"Recover\", useWhen: \"You come here when the way is blocked: an empty list, an error, a missing page, maintenance, a product still being built.\" },\n} as const satisfies Record<TemplatePurpose, { readonly title: string; readonly useWhen: string }>;\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\ninterface ExampleBase {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** A plain example, or a template: a whole screen with its intent (`purpose`) and the user goal its layout serves (`why`). */\nexport type Example =\n | (ExampleBase & { readonly template?: false; readonly purpose?: undefined; readonly why?: undefined })\n | (ExampleBase & {\n /**\n * A template: a whole screen of a product composed from the platform (a layout and its blocks, real words, its\n * phone version thought out), copied as a starting point — at most 160 lines, listed on ui.krizaka.com/templates.\n */\n readonly template: true;\n /** The intent that groups it: why you need this block. */\n readonly purpose: TemplatePurpose;\n /** Why this layout: the user goal it serves, in one sentence. */\n readonly why: string;\n });\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n /** Required for, and only for, a `deprecated` component. */\n readonly deprecated?: Deprecation;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** The platforms it is not on, and why; and its desktop form (see `Parity`). */\n readonly parity: Parity;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
183
183
  }
184
184
  ],
185
185
  "dependencies": [],
@@ -431,7 +431,7 @@
431
431
  },
432
432
  {
433
433
  "path": "meta.ts",
434
- "content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which ui.krizaka.com (apps/site) renders as\n// ui.krizaka.com/components/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"agenda\"\n | \"account-settings\"\n | \"drop-overlay\"\n | \"upload-queue\"\n | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"taped-photo\"\n | \"text-style\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\n | \"specimen-tag\"\n | \"action-bar\"\n | \"action-sheet\"\n | \"activity-feed\"\n | \"alert\"\n | \"app-header\"\n | \"app-shell\"\n | \"argument-card\"\n | \"audio-player\"\n | \"auth-layout\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"captcha\"\n | \"card\"\n | \"card-grid\"\n | \"catalogue-page\"\n | \"changelog-page\"\n | \"chat\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"chip-row\"\n | \"choice-grid\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"comparison-table\"\n | \"command\"\n | \"component-page\"\n | \"confirm-button\"\n | \"contact-page\"\n | \"continue-prompt\"\n | \"countdown\"\n | \"cover-hero\"\n | \"cta-panel\"\n | \"dashboard-layout\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"description-list\"\n | \"detail-layout\"\n | \"dialog\"\n | \"docs-article-page\"\n | \"docs-hub-page\"\n | \"docs-layout\"\n | \"docs-nav\"\n | \"document-viewer\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"engine-flow\"\n | \"error-page\"\n | \"fab\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"force-update-screen\"\n | \"form\"\n | \"gallery-page\"\n | \"genui\"\n | \"glossary\"\n | \"glossary-term\"\n | \"glow-card\"\n | \"goal-gauge\"\n | \"header\"\n | \"how-it-works-page\"\n | \"image-cropper\"\n | \"image-viewer\"\n | \"iso\"\n | \"kanban\"\n | \"kbd\"\n | \"kpi-explained\"\n | \"landing-page\"\n | \"landscape\"\n | \"legal-page\"\n | \"link-card\"\n | \"list\"\n | \"loader\"\n | \"longform-page\"\n | \"maintenance-screen\"\n | \"map\"\n | \"markdown\"\n | \"meta-row\"\n | \"waveform\"\n | \"marketing-layout\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascot-state\"\n | \"mascots\"\n | \"match-dialog\"\n | \"media-capture\"\n | \"media-grid\"\n | \"language-switch\"\n | \"media-gallery\"\n | \"media-picker\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"onboarding\"\n | \"opening-hours\"\n | \"otp-input\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"permission-prompt\"\n | \"photo-grid\"\n | \"pointer-light\"\n | \"popover\"\n | \"pricing-page\"\n | \"product-page\"\n | \"profile-card\"\n | \"progress\"\n | \"promise-card\"\n | \"pull-to-refresh\"\n | \"radio-group\"\n | \"router\"\n | \"rail-nav\"\n | \"recipes\"\n | \"screen\"\n | \"scroll-stage\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"service-card\"\n | \"settings-layout\"\n | \"account-menu\"\n | \"showcase\"\n | \"step-showcase\"\n | \"site-footer\"\n | \"sites\"\n | \"skeleton\"\n | \"skip-link\"\n | \"slider\"\n | \"slot-picker\"\n | \"slot\"\n | \"spinner\"\n | \"sticky-action\"\n | \"splash-handoff\"\n | \"split-view\"\n | \"stage-banner\"\n | \"stat\"\n | \"status-page\"\n | \"step-progress\"\n | \"stepper\"\n | \"swipe-deck\"\n | \"swipeable-row\"\n | \"switch\"\n | \"tab-bar\"\n | \"tabs\"\n | \"tag-input\"\n | \"tag-selector\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"tree-view\"\n | \"txt\"\n | \"update-prompt\"\n | \"verified-badge\"\n | \"vertical-video\"\n | \"video-player\"\n | \"video-trimmer\"\n | \"virtual\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/**\n * Why a component is not on a platform — a decision, never a silence (the parity matrix of ui.krizaka.com/platforms):\n * - `gap` (✗): it belongs there and is not built yet; `issue` is the issue that tracks it (`krizaka/krizaka-ui#275`);\n * - `n/a`: it is not meant for that platform (a site's page block on a phone, a swipe on a desktop); `use` names the\n * component that answers there, when one does.\n */\nexport type Absence =\n | { readonly status: \"gap\"; readonly issue: string; readonly reason: string; readonly use?: undefined }\n | { readonly status: \"n/a\"; readonly reason: string; readonly use?: ComponentName; readonly issue?: undefined };\n\n/**\n * Desktop is the Orazaka Mac app (Tauri 2: the system WebView renders the web components — ADR-002). `web`: the web\n * component runs there as it is; `desktop`: it also has a desktop form (a window's title bar, a denser layout…), said in\n * its documentation; otherwise the absence and why.\n */\nexport type DesktopSupport = \"web\" | \"desktop\" | Absence;\n\n/**\n * The three platforms of Krizaka UI — web · native (React Native, Expo) · desktop — for one component. The side a\n * component has is `platforms`; the side it lacks says why here: `native` is required for (and only for) a web-only\n * component, `web` for a native-only one; `desktop` always. `scripts/registry.test.mjs` fails on a missing decision.\n */\nexport interface Parity {\n readonly web?: Absence;\n readonly native?: Absence;\n readonly desktop: DesktopSupport;\n}\n\n/**\n * `stable`: its API only changes in a major. `beta`: it may still change in a minor. `deprecated`: no product uses it and\n * no work plans to — it still works, says what replaces it, and goes in the major named by `deprecated.removedIn`.\n */\nexport type Status = \"stable\" | \"beta\" | \"deprecated\";\n\n/** What a deprecated component says (required when `status` is `deprecated`, absent otherwise). */\nexport interface Deprecation {\n /** The version that deprecated it (`3.6.0`). */\n readonly since: string;\n /** The major that removes it (`4.0.0`). */\n readonly removedIn: string;\n /** What replaces it, when a component does. */\n readonly use?: ComponentName;\n /** Why it goes: no product uses it, no planned work needs it. */\n readonly reason: string;\n}\n\n/**\n * The group of the catalogue. `media`: video, sound, camera, files, cropping. `blocks`: the page blocks — the frame,\n * the hero, sections, cards that lead or argue, decisions, code, calls to act — that every page of a site is made of.\n * `layouts`: the shells of whole screens — an application, a dashboard, settings, sign-in, an object, a list and its\n * item, a site's page, a documentation page — each with its screens. `templates`: the page templates — whole pages of a\n * site (a landing, a product, a docs hub, a long read, a changelog, pricing, status, an error…), each a distinct\n * composition of the blocks, words and content as props.\n */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layouts\" | \"templates\" | \"layout\" | \"foundations\";\n\n/** Why a reader needs a template: the seven intents the templates are grouped by (sidebar sub-headings, catalogue filter). */\nexport type TemplatePurpose = \"convince\" | \"explain\" | \"show\" | \"act\" | \"operate\" | \"converse\" | \"recover\";\n\n/** The groups of templates, in reading order: the title, and the one line that says when to come to that group. */\nexport const templatePurposes = {\n convince: { title: \"Convince\", useWhen: \"You come here when a visitor must decide: a landing, a product, a price, a comparison, a proof.\" },\n explain: { title: \"Explain\", useWhen: \"You come here when a reader must understand: how it works, a documentation hub or article, a changelog, a FAQ, a policy.\" },\n show: { title: \"Show\", useWhen: \"You come here when the work itself is the argument: a gallery, a story, a case study, an object and its details.\" },\n act: { title: \"Act\", useWhen: \"You come here when a person must do something once: reach the team, sign in or up, set up, pay.\" },\n operate: { title: \"Operate\", useWhen: \"You come here when a person works every day: a dashboard, a console with a table, settings, an app shell.\" },\n converse: { title: \"Converse\", useWhen: \"You come here when people talk: an inbox, a chat, comments, a notifications centre.\" },\n recover: { title: \"Recover\", useWhen: \"You come here when the way is blocked: an empty list, an error, a missing page, maintenance, a product still being built.\" },\n} as const satisfies Record<TemplatePurpose, { readonly title: string; readonly useWhen: string }>;\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\ninterface ExampleBase {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** A plain example, or a template: a whole screen with its intent (`purpose`) and the user goal its layout serves (`why`). */\nexport type Example =\n | (ExampleBase & { readonly template?: false; readonly purpose?: undefined; readonly why?: undefined })\n | (ExampleBase & {\n /**\n * A template: a whole screen of a product composed from the platform (a layout and its blocks, real words, its\n * phone version thought out), copied as a starting point — at most 160 lines, listed on ui.krizaka.com/templates.\n */\n readonly template: true;\n /** The intent that groups it: why you need this block. */\n readonly purpose: TemplatePurpose;\n /** Why this layout: the user goal it serves, in one sentence. */\n readonly why: string;\n });\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n /** Required for, and only for, a `deprecated` component. */\n readonly deprecated?: Deprecation;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** The platforms it is not on, and why; and its desktop form (see `Parity`). */\n readonly parity: Parity;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
434
+ "content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which ui.krizaka.com (apps/site) renders as\n// ui.krizaka.com/components/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"agenda\"\n | \"account-settings\"\n | \"drop-overlay\"\n | \"upload-queue\"\n | \"achievement\"\n | \"anatomy-plate\"\n | \"bird-plate\"\n | \"taped-photo\"\n | \"text-style\"\n | \"flock\"\n | \"elephant\"\n | \"footnote\"\n | \"page-index\"\n | \"chapter\"\n | \"specimen-tag\"\n | \"action-bar\"\n | \"action-sheet\"\n | \"activity-feed\"\n | \"alert\"\n | \"app-header\"\n | \"app-shell\"\n | \"argument-card\"\n | \"audio-player\"\n | \"auth-layout\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"captcha\"\n | \"card\"\n | \"card-grid\"\n | \"catalogue-page\"\n | \"changelog-page\"\n | \"chat\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"chip-row\"\n | \"choice-grid\"\n | \"cn\"\n | \"code-block\"\n | \"combobox\"\n | \"comparison-table\"\n | \"command\"\n | \"component-page\"\n | \"confirm-button\"\n | \"contact-page\"\n | \"continue-prompt\"\n | \"countdown\"\n | \"cover-hero\"\n | \"cta-panel\"\n | \"dashboard-layout\"\n | \"data-table\"\n | \"date-picker\"\n | \"decision-list\"\n | \"description-list\"\n | \"detail-layout\"\n | \"dialog\"\n | \"docs-article-page\"\n | \"docs-hub-page\"\n | \"docs-layout\"\n | \"docs-nav\"\n | \"document-viewer\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"engine-flow\"\n | \"error-page\"\n | \"fab\"\n | \"field\"\n | \"file-upload\"\n | \"filter-bar\"\n | \"force-update-screen\"\n | \"form\"\n | \"gallery-page\"\n | \"genui\"\n | \"glossary\"\n | \"glossary-term\"\n | \"glow-card\"\n | \"goal-gauge\"\n | \"header\"\n | \"how-it-works-page\"\n | \"image-cropper\"\n | \"image-viewer\"\n | \"iso\"\n | \"kanban\"\n | \"kbd\"\n | \"kpi-explained\"\n | \"landing-page\"\n | \"landscape\"\n | \"legal-page\"\n | \"link-card\"\n | \"list\"\n | \"loader\"\n | \"longform-page\"\n | \"maintenance-screen\"\n | \"map\"\n | \"markdown\"\n | \"meta-row\"\n | \"waveform\"\n | \"marketing-layout\"\n | \"marquee\"\n | \"mascot-quote\"\n | \"mascot-state\"\n | \"mascots\"\n | \"match-dialog\"\n | \"media-capture\"\n | \"media-grid\"\n | \"language-switch\"\n | \"media-gallery\"\n | \"media-picker\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"onboarding\"\n | \"opening-hours\"\n | \"otp-input\"\n | \"page\"\n | \"page-header\"\n | \"page-hero\"\n | \"pagination\"\n | \"permission-prompt\"\n | \"photo-grid\"\n | \"pointer-light\"\n | \"popover\"\n | \"pricing-page\"\n | \"product-page\"\n | \"profile-card\"\n | \"progress\"\n | \"promise-card\"\n | \"pull-to-refresh\"\n | \"radio-group\"\n | \"router\"\n | \"rail-nav\"\n | \"recipes\"\n | \"screen\"\n | \"scroll-stage\"\n | \"search-field\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"service-card\"\n | \"settings-layout\"\n | \"account-menu\"\n | \"showcase\"\n | \"step-showcase\"\n | \"site-footer\"\n | \"sites\"\n | \"skeleton\"\n | \"skip-link\"\n | \"slider\"\n | \"slot-picker\"\n | \"slot\"\n | \"spinner\"\n | \"sticky-action\"\n | \"splash-handoff\"\n | \"split-view\"\n | \"stage-banner\"\n | \"stat\"\n | \"status-page\"\n | \"step-progress\"\n | \"stepper\"\n | \"swipe-deck\"\n | \"swipeable-row\"\n | \"switch\"\n | \"tab-bar\"\n | \"tabs\"\n | \"tag-input\"\n | \"tag-selector\"\n | \"terminal-replay\"\n | \"theme\"\n | \"toast\"\n | \"toc\"\n | \"tooltip\"\n | \"tree-view\"\n | \"txt\"\n | \"update-prompt\"\n | \"verified-badge\"\n | \"vertical-video\"\n | \"video-player\"\n | \"video-trimmer\"\n | \"virtual\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/**\n * Why a component is not on a platform — a decision, never a silence (the parity matrix of ui.krizaka.com/platforms):\n * - `gap` (✗): it belongs there and is not built yet; `issue` is the issue that tracks it (`krizaka/krizaka-ui#275`);\n * - `n/a`: it is not meant for that platform (a site's page block on a phone, a swipe on a desktop); `use` names the\n * component that answers there, when one does.\n */\nexport type Absence =\n | { readonly status: \"gap\"; readonly issue: string; readonly reason: string; readonly use?: undefined }\n | { readonly status: \"n/a\"; readonly reason: string; readonly use?: ComponentName; readonly issue?: undefined };\n\n/**\n * Desktop is the Orazaka Mac app (Tauri 2: the system WebView renders the web components — ADR-002). `web`: the web\n * component runs there as it is; `desktop`: it also has a desktop form (a window's title bar, a denser layout…), said in\n * its documentation; otherwise the absence and why.\n */\nexport type DesktopSupport = \"web\" | \"desktop\" | Absence;\n\n/**\n * The three platforms of Krizaka UI — web · native (React Native, Expo) · desktop — for one component. The side a\n * component has is `platforms`; the side it lacks says why here: `native` is required for (and only for) a web-only\n * component, `web` for a native-only one; `desktop` always. `scripts/registry.test.mjs` fails on a missing decision.\n */\nexport interface Parity {\n readonly web?: Absence;\n readonly native?: Absence;\n readonly desktop: DesktopSupport;\n}\n\n/**\n * `stable`: its API only changes in a major. `beta`: it may still change in a minor. `deprecated`: no product uses it and\n * no work plans to — it still works, says what replaces it, and goes in the major named by `deprecated.removedIn`.\n */\nexport type Status = \"stable\" | \"beta\" | \"deprecated\";\n\n/** What a deprecated component says (required when `status` is `deprecated`, absent otherwise). */\nexport interface Deprecation {\n /** The version that deprecated it (`3.6.0`). */\n readonly since: string;\n /** The major that removes it (`4.0.0`). */\n readonly removedIn: string;\n /** What replaces it, when a component does. */\n readonly use?: ComponentName;\n /** Why it goes: no product uses it, no planned work needs it. */\n readonly reason: string;\n}\n\n/**\n * The group of the catalogue. `media`: video, sound, camera, files, cropping. `blocks`: the page blocks — the frame,\n * the hero, sections, cards that lead or argue, decisions, code, calls to act — that every page of a site is made of.\n * `layouts`: the shells of whole screens — an application, a dashboard, settings, sign-in, an object, a list and its\n * item, a site's page, a documentation page — each with its screens. `templates`: the page templates — whole pages of a\n * site (a landing, a product, a docs hub, a long read, a changelog, pricing, status, an error…), each a distinct\n * composition of the blocks, words and content as props.\n */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"media\" | \"blocks\" | \"layouts\" | \"templates\" | \"layout\" | \"foundations\";\n\n/** Why a reader needs a template: the seven intents the templates are grouped by (sidebar sub-headings, catalogue filter). */\nexport type TemplatePurpose = \"convince\" | \"explain\" | \"show\" | \"act\" | \"operate\" | \"converse\" | \"recover\";\n\n/** The groups of templates, in reading order: the title, and the one line that says when to come to that group. */\nexport const templatePurposes = {\n convince: { title: \"Convince\", useWhen: \"You come here when a visitor must decide: a landing, a product, a price, a comparison, a proof.\" },\n explain: { title: \"Explain\", useWhen: \"You come here when a reader must understand: how it works, a documentation hub or article, a changelog, a FAQ, a policy.\" },\n show: { title: \"Show\", useWhen: \"You come here when the work itself is the argument: a gallery, a story, a case study, an object and its details.\" },\n act: { title: \"Act\", useWhen: \"You come here when a person must do something once: reach the team, sign in or up, set up, pay.\" },\n operate: { title: \"Operate\", useWhen: \"You come here when a person works every day: a dashboard, a console with a table, settings, an app shell.\" },\n converse: { title: \"Converse\", useWhen: \"You come here when people talk: an inbox, a chat, comments, a notifications centre.\" },\n recover: { title: \"Recover\", useWhen: \"You come here when the way is blocked: an empty list, an error, a missing page, maintenance, a product still being built.\" },\n} as const satisfies Record<TemplatePurpose, { readonly title: string; readonly useWhen: string }>;\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\ninterface ExampleBase {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** A plain example, or a template: a whole screen with its intent (`purpose`) and the user goal its layout serves (`why`). */\nexport type Example =\n | (ExampleBase & { readonly template?: false; readonly purpose?: undefined; readonly why?: undefined })\n | (ExampleBase & {\n /**\n * A template: a whole screen of a product composed from the platform (a layout and its blocks, real words, its\n * phone version thought out), copied as a starting point — at most 160 lines, listed on ui.krizaka.com/templates.\n */\n readonly template: true;\n /** The intent that groups it: why you need this block. */\n readonly purpose: TemplatePurpose;\n /** Why this layout: the user goal it serves, in one sentence. */\n readonly why: string;\n });\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /**\n * The entry to import from when it is not `@krizaka/ui/native`: a component that needs an Expo module (an optional\n * peer) has its own, `@krizaka/ui/native/<name>`, so an app that does not use it never installs the module.\n */\n readonly entry?: string;\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n /** Required for, and only for, a `deprecated` component. */\n readonly deprecated?: Deprecation;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** The platforms it is not on, and why; and its desktop form (see `Parity`). */\n readonly parity: Parity;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
435
435
  }
436
436
  ],
437
437
  "dependencies": [