@krizaka/ui 3.24.0 → 3.25.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 (214) hide show
  1. package/README.md +7 -0
  2. package/dist/account-menu.d.ts +163 -0
  3. package/dist/account-menu.js +211 -0
  4. package/dist/account-menu.js.map +1 -0
  5. package/dist/app-shell.js +4 -4
  6. package/dist/changelog-page.d.ts +13 -1
  7. package/dist/changelog-page.js +20 -0
  8. package/dist/changelog-page.js.map +1 -1
  9. package/dist/{chunk-CEJDH6SA.js → chunk-2PNLHZLT.js} +23 -3
  10. package/dist/chunk-2PNLHZLT.js.map +1 -0
  11. package/dist/chunk-C7LTF5CC.js +21 -0
  12. package/dist/chunk-C7LTF5CC.js.map +1 -0
  13. package/dist/{chunk-F7FVPPBB.js → chunk-LYOPPBMC.js} +2 -2
  14. package/dist/{chunk-AFY35UCB.js → chunk-P7GZR5CU.js} +3 -1
  15. package/dist/{chunk-AFY35UCB.js.map → chunk-P7GZR5CU.js.map} +1 -1
  16. package/dist/code-block.js +1 -1
  17. package/dist/cover-hero.d.ts +125 -0
  18. package/dist/cover-hero.js +82 -0
  19. package/dist/cover-hero.js.map +1 -0
  20. package/dist/data-table.js +2 -2
  21. package/dist/docs-nav.js +3 -16
  22. package/dist/docs-nav.js.map +1 -1
  23. package/dist/dropdown-menu.d.ts +12 -1
  24. package/dist/dropdown-menu.js +25 -2
  25. package/dist/dropdown-menu.js.map +1 -1
  26. package/dist/filter-bar.js +1 -1
  27. package/dist/genui.js +2 -2
  28. package/dist/media-gallery.d.ts +73 -0
  29. package/dist/media-gallery.js +42 -0
  30. package/dist/media-gallery.js.map +1 -0
  31. package/dist/opening-hours.d.ts +124 -0
  32. package/dist/opening-hours.js +48 -0
  33. package/dist/opening-hours.js.map +1 -0
  34. package/dist/rail-nav.js +1 -1
  35. package/dist/service-card.d.ts +168 -0
  36. package/dist/service-card.js +112 -0
  37. package/dist/service-card.js.map +1 -0
  38. package/dist/slot-picker.d.ts +119 -0
  39. package/dist/slot-picker.js +46 -0
  40. package/dist/slot-picker.js.map +1 -0
  41. package/dist/sticky-action.d.ts +12 -0
  42. package/dist/sticky-action.js +14 -0
  43. package/dist/sticky-action.js.map +1 -0
  44. package/package.json +106 -6
  45. package/registry/account-menu.json +280 -0
  46. package/registry/achievement.json +1 -1
  47. package/registry/action-bar.json +1 -1
  48. package/registry/activity-feed.json +3 -3
  49. package/registry/alert.json +1 -1
  50. package/registry/app-header.json +1 -1
  51. package/registry/app-shell.json +1 -1
  52. package/registry/argument-card.json +1 -1
  53. package/registry/audio-player.json +1 -1
  54. package/registry/auth-layout.json +1 -1
  55. package/registry/avatar.json +1 -1
  56. package/registry/badge.json +1 -1
  57. package/registry/button.json +1 -1
  58. package/registry/captcha.json +1 -1
  59. package/registry/card-grid.json +1 -1
  60. package/registry/card.json +3 -3
  61. package/registry/catalogue-page.json +1 -1
  62. package/registry/changelog-page.json +3 -3
  63. package/registry/chat.json +1 -1
  64. package/registry/checkbox.json +1 -1
  65. package/registry/chip-link.json +1 -1
  66. package/registry/chip.json +1 -1
  67. package/registry/choice-grid.json +1 -1
  68. package/registry/code-block.json +1 -1
  69. package/registry/combobox.json +1 -1
  70. package/registry/command.json +1 -1
  71. package/registry/comparison-table.json +1 -1
  72. package/registry/component-page.json +1 -1
  73. package/registry/confirm-button.json +1 -1
  74. package/registry/contact-page.json +1 -1
  75. package/registry/continue-prompt.json +1 -1
  76. package/registry/countdown.json +1 -1
  77. package/registry/cover-hero.json +246 -0
  78. package/registry/cta-panel.json +1 -1
  79. package/registry/dashboard-layout.json +1 -1
  80. package/registry/data-table.json +1 -1
  81. package/registry/date-picker.json +1 -1
  82. package/registry/decision-list.json +1 -1
  83. package/registry/description-list.json +1 -1
  84. package/registry/detail-layout.json +1 -1
  85. package/registry/dialog.json +1 -1
  86. package/registry/docs-article-page.json +1 -1
  87. package/registry/docs-hub-page.json +1 -1
  88. package/registry/docs-layout.json +1 -1
  89. package/registry/docs-nav.json +1 -1
  90. package/registry/document-viewer.json +1 -1
  91. package/registry/dropdown-menu.json +33 -3
  92. package/registry/empty-state.json +1 -1
  93. package/registry/error-page.json +1 -1
  94. package/registry/examples/account-menu/default.d.ts +4 -0
  95. package/registry/examples/account-menu/default.js +28 -0
  96. package/registry/examples/account-menu/default.tsx +22 -0
  97. package/registry/examples/cover-hero/plain.d.ts +4 -0
  98. package/registry/examples/cover-hero/plain.js +12 -0
  99. package/registry/examples/cover-hero/plain.tsx +7 -0
  100. package/registry/examples/cover-hero/shop.d.ts +4 -0
  101. package/registry/examples/cover-hero/shop.js +27 -0
  102. package/registry/examples/cover-hero/shop.tsx +20 -0
  103. package/registry/examples/media-gallery/shop.d.ts +4 -0
  104. package/registry/examples/media-gallery/shop.js +22 -0
  105. package/registry/examples/media-gallery/shop.tsx +18 -0
  106. package/registry/examples/opening-hours/week.d.ts +4 -0
  107. package/registry/examples/opening-hours/week.js +28 -0
  108. package/registry/examples/opening-hours/week.tsx +22 -0
  109. package/registry/examples/service-card/services.d.ts +4 -0
  110. package/registry/examples/service-card/services.js +15 -0
  111. package/registry/examples/service-card/services.tsx +12 -0
  112. package/registry/examples/slot-picker/times.d.ts +4 -0
  113. package/registry/examples/slot-picker/times.js +27 -0
  114. package/registry/examples/slot-picker/times.tsx +23 -0
  115. package/registry/examples/sticky-action/phone.d.ts +4 -0
  116. package/registry/examples/sticky-action/phone.js +15 -0
  117. package/registry/examples/sticky-action/phone.tsx +14 -0
  118. package/registry/field.json +1 -1
  119. package/registry/file-upload.json +1 -1
  120. package/registry/filter-bar.json +1 -1
  121. package/registry/force-update-screen.json +1 -1
  122. package/registry/form.json +3 -3
  123. package/registry/gallery-page.json +1 -1
  124. package/registry/genui.json +1 -1
  125. package/registry/glow-card.json +1 -1
  126. package/registry/goal-gauge.json +1 -1
  127. package/registry/how-it-works-page.json +1 -1
  128. package/registry/image-cropper.json +1 -1
  129. package/registry/index.json +226 -5
  130. package/registry/iso.json +1 -1
  131. package/registry/kanban.json +1 -1
  132. package/registry/kbd.json +1 -1
  133. package/registry/landing-page.json +1 -1
  134. package/registry/landscape.json +1 -1
  135. package/registry/legal-page.json +1 -1
  136. package/registry/link-card.json +3 -3
  137. package/registry/list.json +1 -1
  138. package/registry/loader.json +1 -1
  139. package/registry/longform-page.json +1 -1
  140. package/registry/maintenance-screen.json +1 -1
  141. package/registry/map.json +2 -2
  142. package/registry/markdown.json +1 -1
  143. package/registry/marketing-layout.json +1 -1
  144. package/registry/marquee.json +1 -1
  145. package/registry/mascot-quote.json +1 -1
  146. package/registry/mascot-state.json +1 -1
  147. package/registry/mascots.json +1 -1
  148. package/registry/match-dialog.json +1 -1
  149. package/registry/media-capture.json +3 -3
  150. package/registry/media-gallery.json +144 -0
  151. package/registry/media-grid.json +3 -3
  152. package/registry/meta-row.json +1 -1
  153. package/registry/meter.json +1 -1
  154. package/registry/nav-bar.json +2 -2
  155. package/registry/number-ticker.json +1 -1
  156. package/registry/opening-hours.json +178 -0
  157. package/registry/page-header.json +1 -1
  158. package/registry/page-hero.json +3 -3
  159. package/registry/page.json +7 -7
  160. package/registry/pagination.json +1 -1
  161. package/registry/photo-grid.json +1 -1
  162. package/registry/pointer-light.json +1 -1
  163. package/registry/popover.json +1 -1
  164. package/registry/pricing-page.json +1 -1
  165. package/registry/product-page.json +1 -1
  166. package/registry/profile-card.json +1 -1
  167. package/registry/progress.json +1 -1
  168. package/registry/promise-card.json +1 -1
  169. package/registry/radio-group.json +1 -1
  170. package/registry/rail-nav.json +2 -2
  171. package/registry/recipes.json +1 -1
  172. package/registry/scroll-stage.json +1 -1
  173. package/registry/search-field.json +1 -1
  174. package/registry/section-backdrop.json +1 -1
  175. package/registry/separator.json +1 -1
  176. package/registry/service-card.json +358 -0
  177. package/registry/settings-layout.json +1 -1
  178. package/registry/showcase.json +1 -1
  179. package/registry/site-footer.json +2 -2
  180. package/registry/sites.json +1 -1
  181. package/registry/skeleton.json +3 -3
  182. package/registry/skip-link.json +1 -1
  183. package/registry/slider.json +1 -1
  184. package/registry/slot-picker.json +222 -0
  185. package/registry/slot.json +1 -1
  186. package/registry/spinner.json +1 -1
  187. package/registry/split-view.json +1 -1
  188. package/registry/stage-banner.json +1 -1
  189. package/registry/stat.json +1 -1
  190. package/registry/status-page.json +1 -1
  191. package/registry/step-progress.json +1 -1
  192. package/registry/step-showcase.json +1 -1
  193. package/registry/stepper.json +1 -1
  194. package/registry/sticky-action.json +108 -0
  195. package/registry/swipe-deck.json +1 -1
  196. package/registry/switch.json +1 -1
  197. package/registry/tabs.json +1 -1
  198. package/registry/tag-input.json +1 -1
  199. package/registry/tag-selector.json +1 -1
  200. package/registry/terminal-replay.json +1 -1
  201. package/registry/theme.json +1 -1
  202. package/registry/toast.json +1 -1
  203. package/registry/toc.json +1 -1
  204. package/registry/tooltip.json +1 -1
  205. package/registry/tree-view.json +1 -1
  206. package/registry/update-prompt.json +1 -1
  207. package/registry/verified-badge.json +1 -1
  208. package/registry/vertical-video.json +5 -5
  209. package/registry/video-player.json +3 -3
  210. package/registry/video-trimmer.json +1 -1
  211. package/registry/virtual.json +1 -1
  212. package/registry/waveform.json +1 -1
  213. package/dist/chunk-CEJDH6SA.js.map +0 -1
  214. /package/dist/{chunk-F7FVPPBB.js.map → chunk-LYOPPBMC.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/changelog-page/adapter.ts","../src/changelog-page/changelog-page.tsx"],"sourcesContent":["/* The changelog's data, one shape for every source — pure, server-safe.\n Sources: a changesets CHANGELOG.md (the @krizaka packages), a GitHub Release body (the products), conventional PR\n titles (the draft generator). Nothing is hand-written: a site reads its sources at build into a JSON and maps it to\n `ChangelogPage` entries with `kindOfTag` (krizaka/krizaka-ui#307). */\nimport type { ChangeKind } from \"./changelog-page\";\n\nexport type ChangeTag = \"feature\" | \"fix\" | \"security\" | \"breaking\" | \"change\";\n\nexport interface ChangeItem {\n tag: ChangeTag;\n /** Plain user language, markdown links and backticks removed. */\n text: string;\n /** The pull request that made it, when the source names one. */\n pr?: { number: number; url: string };\n}\n\nexport interface Release {\n /** What was released: `@krizaka/ui`, `Orazaka`. */\n source: string;\n version: string;\n /** ISO date, `2026-10-17`. */\n date: string;\n /** The release's page (GitHub release, npm). */\n url?: string;\n changes: ChangeItem[];\n}\n\nexport const CHANGE_TAGS: readonly ChangeTag[] = [\"breaking\", \"security\", \"feature\", \"fix\", \"change\"];\n\nconst REPO_PR = /https:\\/\\/github\\.com\\/[\\w.-]+\\/[\\w.-]+\\/pull\\/(\\d+)/;\n\n/** A line of markdown as a reader reads it: links keep their words, backticks and emphasis go. */\nexport function plain(md: string): string {\n return md\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n .replace(/`([^`]*)`/g, \"$1\")\n .replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** The tag a sentence deserves when its source does not say (security and breaking words win). */\nexport function tagOf(text: string, fallback: ChangeTag): ChangeTag {\n if (/\\bBREAKING\\b|^\\w+(\\([^)]*\\))?!:/.test(text)) return \"breaking\";\n if (/\\b(security|vulnerabilit\\w*|CVE-\\d+|XSS|CSRF)\\b/i.test(text)) return \"security\";\n return fallback;\n}\n\n/** A highlight, not the whole note: the first sentence when it is short enough, else the text cut at a word. */\nconst clip = (s: string, max = 220) => {\n const first = /^(.{20,}?[.!?])(\\s|$)/.exec(s)?.[1];\n if (first && first.length <= max) return first;\n return s.length <= max ? s : `${s.slice(0, max).replace(/\\s+\\S*$/, \"\")}…`;\n};\n\n/** The first PR a line links to, read from its markdown (`[#293](…/pull/293)`) or a bare URL. */\nexport function prOf(line: string): ChangeItem[\"pr\"] {\n const url = REPO_PR.exec(line);\n return url ? { number: Number(url[1]), url: url[0] } : undefined;\n}\n\nconst CHANGESET_TAG: Record<string, ChangeTag> = { major: \"breaking\", minor: \"feature\", patch: \"fix\" };\n\n/** The releases of a changesets CHANGELOG.md, newest first as written. Dates are not in the file: `dateOf(version)`. */\nexport function parseChangesets(md: string, source: string, dateOf: (version: string) => string | undefined): Release[] {\n const releases: Release[] = [];\n let current: Release | undefined;\n let level: ChangeTag = \"change\";\n for (const raw of md.split(\"\\n\")) {\n const h2 = /^## (\\d+\\.\\d+\\.\\d+\\S*)\\s*$/.exec(raw);\n if (h2) {\n const date = dateOf(h2[1]);\n current = date ? { source, version: h2[1], date, changes: [] } : undefined;\n if (current) releases.push(current);\n continue;\n }\n const h3 = /^### (\\w+) Changes/.exec(raw);\n if (h3) {\n level = CHANGESET_TAG[h3[1].toLowerCase()] ?? \"change\";\n continue;\n }\n // top-level bullets only: \"Updated dependencies\" and its nested list are plumbing, not news\n const bullet = /^- (.+)$/.exec(raw);\n if (!current || !bullet || /^Updated dependencies/.test(bullet[1])) continue;\n const text = plain(bullet[1].replace(/^(\\[[^\\]]*\\]\\([^)]*\\)\\s*)+(Thanks \\[[^\\]]*\\]\\([^)]*\\)!\\s*)?-\\s*/, \"\"));\n if (!text) continue;\n current.changes.push({ tag: tagOf(text, level === \"feature\" ? \"feature\" : level), text: clip(text), pr: prOf(bullet[1]) });\n }\n return releases.filter((r) => r.changes.length > 0);\n}\n\nconst CONVENTIONAL = /^(feat|fix|perf|security|sec|revert|refactor|docs|chore|ci|test|build|style|deps)(\\([^)]*\\))?(!)?:\\s*(.+)$/i;\nconst TAG_OF_TYPE: Record<string, ChangeTag> = { feat: \"feature\", fix: \"fix\", perf: \"change\", security: \"security\", sec: \"security\", revert: \"change\" };\n/** Types that are the team's housekeeping, not news for a reader. */\nconst QUIET_TYPES = new Set([\"refactor\", \"docs\", \"chore\", \"ci\", \"test\", \"build\", \"style\", \"deps\"]);\n\n/** One conventional PR title as a change, or `null` when it is housekeeping (chore, ci, test, docs…). */\nexport function changeFromTitle(title: string, prUrl?: string): ChangeItem | null {\n const m = CONVENTIONAL.exec(title.trim());\n const type = m?.[1].toLowerCase();\n if (m && type && QUIET_TYPES.has(type) && !m[3]) return null;\n const body = (m ? m[4] : title).replace(/\\s*\\(#\\d+\\)\\s*$/, \"\").trim();\n const sentence = plain(body.replace(/^./, (c) => c.toUpperCase()));\n const tag = tagOf(m?.[3] ? `${type}!: ${body}` : sentence, type ? (TAG_OF_TYPE[type] ?? \"change\") : \"change\");\n const num = /\\(#(\\d+)\\)\\s*$/.exec(title)?.[1];\n const pr = prUrl ? prOf(prUrl) : num ? { number: Number(num), url: \"\" } : undefined;\n return { tag, text: sentence.replace(/[.\\s]*$/, \".\"), pr };\n}\n\n/** A GitHub Release body: bullets (`* feat: … by @x in <PR url>`, `- Fix …`), conventional titles tagged, the rest «change». */\nexport function parseReleaseBody(body: string): ChangeItem[] {\n const items: ChangeItem[] = [];\n for (const raw of body.split(\"\\n\")) {\n const bullet = /^\\s*[-*] (.+)$/.exec(raw);\n if (!bullet) continue;\n const line = bullet[1].replace(/\\s+by @[\\w-]+ in (https:\\/\\/\\S+)\\s*$/, \" $1\");\n const pr = prOf(line);\n const title = line.replace(/\\s*https:\\/\\/\\S+\\s*$/, \"\");\n const item = changeFromTitle(plain(title), pr?.url);\n if (item) items.push({ ...item, pr: pr ?? item.pr, text: clip(item.text) });\n }\n return items;\n}\n\n/** The draft generator: conventional PR titles → a plain-language draft entry (Markdown) for a human or an agent to polish. */\nexport function draftFromTitles(titles: readonly string[], heading: string): string {\n const groups = new Map<ChangeTag, string[]>();\n for (const title of titles) {\n const item = changeFromTitle(title);\n if (!item) continue;\n groups.set(item.tag, [...(groups.get(item.tag) ?? []), item.pr?.number ? `${item.text} (#${item.pr.number})` : item.text]);\n }\n const names: Record<ChangeTag, string> = { breaking: \"Breaking\", security: \"Security\", feature: \"New\", fix: \"Fixed\", change: \"Changed\" };\n const out = [`## ${heading}`];\n for (const tag of CHANGE_TAGS) {\n const lines = groups.get(tag);\n if (lines?.length) out.push(\"\", `### ${names[tag]}`, ...lines.map((l) => `- ${l}`));\n }\n return `${out.join(\"\\n\")}\\n`;\n}\n\n/** Semver-aware, newest first; falls back to the date. */\nexport function newestFirst(a: Release, b: Release): number {\n return b.date.localeCompare(a.date) || b.version.localeCompare(a.version, undefined, { numeric: true });\n}\n\n/** A stable anchor: `krizaka-ui-3-22-0`; the bare version is the anchor of the site's own entry. */\nexport const anchorOf = (r: Pick<Release, \"source\" | \"version\">): string =>\n `${r.source}-${r.version}`.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-|-$/g, \"\");\n\nconst esc = (s: string) => s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n\n/** The changelog as an RSS 2.0 feed. `tagLabel` words the tags in the feed's language. */\nexport function changelogRss(opts: {\n releases: readonly Release[];\n title: string;\n description: string;\n siteUrl: string;\n pageUrl: string;\n feedUrl: string;\n language: string;\n tagLabel: Record<ChangeTag, string>;\n}): string {\n const items = opts.releases\n .map((r) => {\n const list = r.changes.map((c) => `<li><b>${esc(opts.tagLabel[c.tag])}</b> ${esc(c.text)}</li>`).join(\"\");\n const link = `${opts.pageUrl}#${anchorOf(r)}`;\n return `<item><title>${esc(`${r.source} ${r.version}`)}</title><link>${esc(link)}</link><guid isPermaLink=\"true\">${esc(link)}</guid><pubDate>${new Date(`${r.date}T12:00:00Z`).toUTCString()}</pubDate><description>${esc(`<ul>${list}</ul>`)}</description></item>`;\n })\n .join(\"\");\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?><rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\"><channel><title>${esc(opts.title)}</title><link>${esc(opts.pageUrl)}</link><description>${esc(opts.description)}</description><language>${opts.language}</language><atom:link href=\"${esc(opts.feedUrl)}\" rel=\"self\" type=\"application/rss+xml\"/>${items}</channel></rss>`;\n}\n\n/** The template's kind for a tag: feature → added, fix → fixed, security and breaking stay themselves, the rest → changed. */\nexport const kindOfTag = (tag: ChangeTag): ChangeKind =>\n tag === \"feature\" ? \"added\" : tag === \"fix\" ? \"fixed\" : tag === \"change\" ? \"changed\" : tag;\n","// Server-safe. What changed and why (blocks.css `.kz-tpl-log`): the hero, then the entries — the date and version\n// sticking beside them while they scroll, a title, the changes by kind (added · changed · fixed · removed · security · breaking, in words and\n// colour) — and, when a change was a decision, its reasons (a DecisionList) under it.\nimport { Page } from \"@krizaka/ui/page\";\nimport type { LinkComponent } from \"@krizaka/ui/page-hero\";\nimport { PageHero } from \"@krizaka/ui/page-hero\";\nimport type * as React from \"react\";\n\nexport type ChangeKind = \"added\" | \"changed\" | \"fixed\" | \"removed\" | \"security\" | \"breaking\";\n\nexport interface ChangelogEntry {\n /** A stable key (the entry's anchor). */\n id: string;\n /** Its date, ISO (`2026-10-11`): shown as `dateLabel`. */\n date: string;\n /** The date as the reader reads it (`11 October 2026`). */\n dateLabel: React.ReactNode;\n /** The version or the release (`@krizaka/ui 2.6.0`): a fact beside the date. */\n version?: React.ReactNode;\n /** The entry's title. */\n title: React.ReactNode;\n /** The changes, each with its kind. */\n changes: readonly { kind: ChangeKind; text: React.ReactNode }[];\n /** Under the changes: why (a DecisionList, a quote), a link to the pull request. */\n children?: React.ReactNode;\n}\n\nexport type ChangelogPageProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The way back. */\n back?: { href: string; label: string };\n /** A mono line above the title. */\n eyebrow?: React.ReactNode;\n /** The page's `h1`. */\n title: React.ReactNode;\n /** One sentence under it. */\n lead?: React.ReactNode;\n /** In the hero: a subscribe action, the feed. */\n actions?: React.ReactNode;\n /** The words of the kinds: `{ added: \"Added\", security: \"Security\", … }`. */\n kindLabels: Record<ChangeKind, string>;\n /** The log's accessible name (`Changes`). */\n logLabel: string;\n /** The entries, newest first. */\n entries: readonly ChangelogEntry[];\n /** The app's link component (Next's `Link`). */\n linkAs?: LinkComponent;\n};\n\n/** A changelog: entries with a sticky date and version, changes by kind, the reasons under them. */\nexport function ChangelogPage({ back, eyebrow, title, lead, actions, kindLabels, logLabel, entries, linkAs, ...props }: ChangelogPageProps) {\n return (\n <div {...props}>\n <PageHero back={back} linkAs={linkAs} eyebrow={eyebrow} title={title} lead={lead} backdrop=\"plain\">\n {actions}\n </PageHero>\n <Page className=\"kz-tpl-longform\">\n <ol className=\"kz-tpl-log\" aria-label={logLabel}>\n {entries.map((e) => (\n <li key={e.id} id={e.id} className=\"kz-tpl-log-entry\">\n <div className=\"kz-tpl-log-when\">\n <time dateTime={e.date}>{e.dateLabel}</time>\n {e.version && <span className=\"kz-fact\">{e.version}</span>}\n </div>\n <div>\n <h2>{e.title}</h2>\n <ul className=\"kz-tpl-log-items\">\n {e.changes.map((c, i) => (\n <li key={i}>\n <span className=\"kz-tpl-log-kind\" data-kind={c.kind}>\n {kindLabels[c.kind]}\n </span>\n <span>{c.text}</span>\n </li>\n ))}\n </ul>\n {e.children}\n </div>\n </li>\n ))}\n </ol>\n </Page>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/changelog-page/adapter.ts","../src/changelog-page/changelog-page.tsx"],"sourcesContent":["/* The changelog's data, one shape for every source — pure, server-safe.\n Sources: a changesets CHANGELOG.md (the @krizaka packages), a GitHub Release body (the products), conventional PR\n titles (the draft generator). Nothing is hand-written: a site reads its sources at build into a JSON and maps it to\n `ChangelogPage` entries with `kindOfTag` (krizaka/krizaka-ui#307). */\nimport type { ChangeKind } from \"./changelog-page\";\n\nexport type ChangeTag = \"feature\" | \"fix\" | \"security\" | \"breaking\" | \"change\";\n\nexport interface ChangeItem {\n tag: ChangeTag;\n /** Plain user language, markdown links and backticks removed. */\n text: string;\n /** The pull request that made it, when the source names one. */\n pr?: { number: number; url: string };\n}\n\nexport interface Release {\n /** What was released: `@krizaka/ui`, `Orazaka`. */\n source: string;\n version: string;\n /** ISO date, `2026-10-17`. */\n date: string;\n /** The release's page (GitHub release, npm). */\n url?: string;\n changes: ChangeItem[];\n}\n\nexport const CHANGE_TAGS: readonly ChangeTag[] = [\"breaking\", \"security\", \"feature\", \"fix\", \"change\"];\n\nconst REPO_PR = /https:\\/\\/github\\.com\\/[\\w.-]+\\/[\\w.-]+\\/pull\\/(\\d+)/;\n\n/** A line of markdown as a reader reads it: links keep their words, backticks and emphasis go. */\nexport function plain(md: string): string {\n return md\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\")\n .replace(/`([^`]*)`/g, \"$1\")\n .replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/** The tag a sentence deserves when its source does not say (security and breaking words win). */\nexport function tagOf(text: string, fallback: ChangeTag): ChangeTag {\n if (/\\bBREAKING\\b|^\\w+(\\([^)]*\\))?!:/.test(text)) return \"breaking\";\n if (/\\b(security|vulnerabilit\\w*|CVE-\\d+|XSS|CSRF)\\b/i.test(text)) return \"security\";\n return fallback;\n}\n\n/** A highlight, not the whole note: the first sentence when it is short enough, else the text cut at a word. */\nconst clip = (s: string, max = 220) => {\n const first = /^(.{20,}?[.!?])(\\s|$)/.exec(s)?.[1];\n if (first && first.length <= max) return first;\n return s.length <= max ? s : `${s.slice(0, max).replace(/\\s+\\S*$/, \"\")}…`;\n};\n\n/** The first PR a line links to, read from its markdown (`[#293](…/pull/293)`) or a bare URL. */\nexport function prOf(line: string): ChangeItem[\"pr\"] {\n const url = REPO_PR.exec(line);\n return url ? { number: Number(url[1]), url: url[0] } : undefined;\n}\n\nconst CHANGESET_TAG: Record<string, ChangeTag> = { major: \"breaking\", minor: \"feature\", patch: \"fix\" };\n\n/** The releases of a changesets CHANGELOG.md, newest first as written. Dates are not in the file: `dateOf(version)`. */\nexport function parseChangesets(md: string, source: string, dateOf: (version: string) => string | undefined): Release[] {\n const releases: Release[] = [];\n let current: Release | undefined;\n let level: ChangeTag = \"change\";\n for (const raw of md.split(\"\\n\")) {\n const h2 = /^## (\\d+\\.\\d+\\.\\d+\\S*)\\s*$/.exec(raw);\n if (h2) {\n const date = dateOf(h2[1]);\n current = date ? { source, version: h2[1], date, changes: [] } : undefined;\n if (current) releases.push(current);\n continue;\n }\n const h3 = /^### (\\w+) Changes/.exec(raw);\n if (h3) {\n level = CHANGESET_TAG[h3[1].toLowerCase()] ?? \"change\";\n continue;\n }\n // top-level bullets only: \"Updated dependencies\" and its nested list are plumbing, not news\n const bullet = /^- (.+)$/.exec(raw);\n if (!current || !bullet || /^Updated dependencies/.test(bullet[1])) continue;\n const text = plain(bullet[1].replace(/^(\\[[^\\]]*\\]\\([^)]*\\)\\s*)+(Thanks \\[[^\\]]*\\]\\([^)]*\\)!\\s*)?-\\s*/, \"\"));\n if (!text) continue;\n current.changes.push({ tag: tagOf(text, level === \"feature\" ? \"feature\" : level), text: clip(text), pr: prOf(bullet[1]) });\n }\n return releases.filter((r) => r.changes.length > 0);\n}\n\nconst CONVENTIONAL = /^(feat|fix|perf|security|sec|revert|refactor|docs|chore|ci|test|build|style|deps)(\\([^)]*\\))?(!)?:\\s*(.+)$/i;\nconst TAG_OF_TYPE: Record<string, ChangeTag> = { feat: \"feature\", fix: \"fix\", perf: \"change\", security: \"security\", sec: \"security\", revert: \"change\" };\n/** Types that are the team's housekeeping, not news for a reader. */\nconst QUIET_TYPES = new Set([\"refactor\", \"docs\", \"chore\", \"ci\", \"test\", \"build\", \"style\", \"deps\"]);\n\n/** One conventional PR title as a change, or `null` when it is housekeeping (chore, ci, test, docs…). */\nexport function changeFromTitle(title: string, prUrl?: string): ChangeItem | null {\n const m = CONVENTIONAL.exec(title.trim());\n const type = m?.[1].toLowerCase();\n if (m && type && QUIET_TYPES.has(type) && !m[3]) return null;\n const body = (m ? m[4] : title).replace(/\\s*\\(#\\d+\\)\\s*$/, \"\").trim();\n const sentence = plain(body.replace(/^./, (c) => c.toUpperCase()));\n const tag = tagOf(m?.[3] ? `${type}!: ${body}` : sentence, type ? (TAG_OF_TYPE[type] ?? \"change\") : \"change\");\n const num = /\\(#(\\d+)\\)\\s*$/.exec(title)?.[1];\n const pr = prUrl ? prOf(prUrl) : num ? { number: Number(num), url: \"\" } : undefined;\n return { tag, text: sentence.replace(/[.\\s]*$/, \".\"), pr };\n}\n\n/** A GitHub Release body: bullets (`* feat: … by @x in <PR url>`, `- Fix …`), conventional titles tagged, the rest «change». */\nexport function parseReleaseBody(body: string): ChangeItem[] {\n const items: ChangeItem[] = [];\n for (const raw of body.split(\"\\n\")) {\n const bullet = /^\\s*[-*] (.+)$/.exec(raw);\n if (!bullet) continue;\n const line = bullet[1].replace(/\\s+by @[\\w-]+ in (https:\\/\\/\\S+)\\s*$/, \" $1\");\n const pr = prOf(line);\n const title = line.replace(/\\s*https:\\/\\/\\S+\\s*$/, \"\");\n const item = changeFromTitle(plain(title), pr?.url);\n if (item) items.push({ ...item, pr: pr ?? item.pr, text: clip(item.text) });\n }\n return items;\n}\n\n/** The draft generator: conventional PR titles → a plain-language draft entry (Markdown) for a human or an agent to polish. */\nexport function draftFromTitles(titles: readonly string[], heading: string): string {\n const groups = new Map<ChangeTag, string[]>();\n for (const title of titles) {\n const item = changeFromTitle(title);\n if (!item) continue;\n groups.set(item.tag, [...(groups.get(item.tag) ?? []), item.pr?.number ? `${item.text} (#${item.pr.number})` : item.text]);\n }\n const names: Record<ChangeTag, string> = { breaking: \"Breaking\", security: \"Security\", feature: \"New\", fix: \"Fixed\", change: \"Changed\" };\n const out = [`## ${heading}`];\n for (const tag of CHANGE_TAGS) {\n const lines = groups.get(tag);\n if (lines?.length) out.push(\"\", `### ${names[tag]}`, ...lines.map((l) => `- ${l}`));\n }\n return `${out.join(\"\\n\")}\\n`;\n}\n\n/** Semver-aware, newest first; falls back to the date. */\nexport function newestFirst(a: Release, b: Release): number {\n return b.date.localeCompare(a.date) || b.version.localeCompare(a.version, undefined, { numeric: true });\n}\n\n/** A stable anchor: `krizaka-ui-3-22-0`; the bare version is the anchor of the site's own entry. */\nexport const anchorOf = (r: Pick<Release, \"source\" | \"version\">): string =>\n `${r.source}-${r.version}`.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-|-$/g, \"\");\n\nconst esc = (s: string) => s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n\n/** The changelog as an RSS 2.0 feed. `tagLabel` words the tags in the feed's language. */\nexport function changelogRss(opts: {\n releases: readonly Release[];\n title: string;\n description: string;\n siteUrl: string;\n pageUrl: string;\n feedUrl: string;\n language: string;\n tagLabel: Record<ChangeTag, string>;\n}): string {\n const items = opts.releases\n .map((r) => {\n const list = r.changes.map((c) => `<li><b>${esc(opts.tagLabel[c.tag])}</b> ${esc(c.text)}</li>`).join(\"\");\n const link = `${opts.pageUrl}#${anchorOf(r)}`;\n return `<item><title>${esc(`${r.source} ${r.version}`)}</title><link>${esc(link)}</link><guid isPermaLink=\"true\">${esc(link)}</guid><pubDate>${new Date(`${r.date}T12:00:00Z`).toUTCString()}</pubDate><description>${esc(`<ul>${list}</ul>`)}</description></item>`;\n })\n .join(\"\");\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?><rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\"><channel><title>${esc(opts.title)}</title><link>${esc(opts.pageUrl)}</link><description>${esc(opts.description)}</description><language>${opts.language}</language><atom:link href=\"${esc(opts.feedUrl)}\" rel=\"self\" type=\"application/rss+xml\"/>${items}</channel></rss>`;\n}\n\n/** The template's kind for a tag: feature → added, fix → fixed, security and breaking stay themselves, the rest → changed. */\nexport const kindOfTag = (tag: ChangeTag): ChangeKind =>\n tag === \"feature\" ? \"added\" : tag === \"fix\" ? \"fixed\" : tag === \"change\" ? \"changed\" : tag;\n\nexport interface MergedPull {\n title: string;\n html_url: string;\n /** ISO timestamp, `null` for a pull request closed without merging. */\n merged_at: string | null;\n}\n\nconst mondayOf = (iso: string): string => {\n const d = new Date(`${iso.slice(0, 10)}T12:00:00Z`);\n d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 6) % 7));\n return d.toISOString().slice(0, 10);\n};\n\n/**\n * For a repository that publishes no releases (a product still in development): its merged pull requests, by week.\n * Each week is one entry (`version` = the Monday, `date` = the last merge), its changes the conventional titles in plain\n * language — housekeeping (chore, ci, test, docs…) is left out, weeks with nothing to say are dropped.\n */\nexport function releasesFromPulls(pulls: readonly MergedPull[], source: string, url?: string): Release[] {\n const weeks = new Map<string, { date: string; changes: ChangeItem[] }>();\n for (const p of pulls) {\n if (!p.merged_at) continue;\n const item = changeFromTitle(p.title, p.html_url);\n if (!item) continue;\n const key = mondayOf(p.merged_at);\n const week = weeks.get(key) ?? { date: p.merged_at.slice(0, 10), changes: [] };\n if (p.merged_at.slice(0, 10) > week.date) week.date = p.merged_at.slice(0, 10);\n week.changes.push(item);\n weeks.set(key, week);\n }\n return [...weeks].map(([version, w]) => ({ source, version, date: w.date, url, changes: w.changes })).sort(newestFirst);\n}\n","// Server-safe. What changed and why (blocks.css `.kz-tpl-log`): the hero, then the entries — the date and version\n// sticking beside them while they scroll, a title, the changes by kind (added · changed · fixed · removed · security · breaking, in words and\n// colour) — and, when a change was a decision, its reasons (a DecisionList) under it.\nimport { Page } from \"@krizaka/ui/page\";\nimport type { LinkComponent } from \"@krizaka/ui/page-hero\";\nimport { PageHero } from \"@krizaka/ui/page-hero\";\nimport type * as React from \"react\";\n\nexport type ChangeKind = \"added\" | \"changed\" | \"fixed\" | \"removed\" | \"security\" | \"breaking\";\n\nexport interface ChangelogEntry {\n /** A stable key (the entry's anchor). */\n id: string;\n /** Its date, ISO (`2026-10-11`): shown as `dateLabel`. */\n date: string;\n /** The date as the reader reads it (`11 October 2026`). */\n dateLabel: React.ReactNode;\n /** The version or the release (`@krizaka/ui 2.6.0`): a fact beside the date. */\n version?: React.ReactNode;\n /** The entry's title. */\n title: React.ReactNode;\n /** The changes, each with its kind. */\n changes: readonly { kind: ChangeKind; text: React.ReactNode }[];\n /** Under the changes: why (a DecisionList, a quote), a link to the pull request. */\n children?: React.ReactNode;\n}\n\nexport type ChangelogPageProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The way back. */\n back?: { href: string; label: string };\n /** A mono line above the title. */\n eyebrow?: React.ReactNode;\n /** The page's `h1`. */\n title: React.ReactNode;\n /** One sentence under it. */\n lead?: React.ReactNode;\n /** In the hero: a subscribe action, the feed. */\n actions?: React.ReactNode;\n /** The words of the kinds: `{ added: \"Added\", security: \"Security\", … }`. */\n kindLabels: Record<ChangeKind, string>;\n /** The log's accessible name (`Changes`). */\n logLabel: string;\n /** The entries, newest first. */\n entries: readonly ChangelogEntry[];\n /** The app's link component (Next's `Link`). */\n linkAs?: LinkComponent;\n};\n\n/** A changelog: entries with a sticky date and version, changes by kind, the reasons under them. */\nexport function ChangelogPage({ back, eyebrow, title, lead, actions, kindLabels, logLabel, entries, linkAs, ...props }: ChangelogPageProps) {\n return (\n <div {...props}>\n <PageHero back={back} linkAs={linkAs} eyebrow={eyebrow} title={title} lead={lead} backdrop=\"plain\">\n {actions}\n </PageHero>\n <Page className=\"kz-tpl-longform\">\n <ol className=\"kz-tpl-log\" aria-label={logLabel}>\n {entries.map((e) => (\n <li key={e.id} id={e.id} className=\"kz-tpl-log-entry\">\n <div className=\"kz-tpl-log-when\">\n <time dateTime={e.date}>{e.dateLabel}</time>\n {e.version && <span className=\"kz-fact\">{e.version}</span>}\n </div>\n <div>\n <h2>{e.title}</h2>\n <ul className=\"kz-tpl-log-items\">\n {e.changes.map((c, i) => (\n <li key={i}>\n <span className=\"kz-tpl-log-kind\" data-kind={c.kind}>\n {kindLabels[c.kind]}\n </span>\n <span>{c.text}</span>\n </li>\n ))}\n </ul>\n {e.children}\n </div>\n </li>\n ))}\n </ol>\n </Page>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -22,7 +22,7 @@ import { tv } from "tailwind-variants";
22
22
  import { jsx, jsxs } from "react/jsx-runtime";
23
23
  var menu = tv({
24
24
  slots: {
25
- content: cn(floating, "min-w-48 max-h-(--radix-dropdown-menu-content-available-height) overflow-y-auto p-1 origin-(--radix-dropdown-menu-content-transform-origin)"),
25
+ content: cn(floating, "min-w-48 max-h-(--radix-dropdown-menu-content-available-height) overflow-y-auto overflow-x-hidden overscroll-contain p-1 origin-(--radix-dropdown-menu-content-transform-origin)"),
26
26
  item: "relative flex cursor-pointer select-none items-center gap-2 rounded-md px-2.5 py-2 text-sm text-fg outline-hidden transition-colors data-highlighted:bg-surface-3 data-disabled:pointer-events-none data-disabled:opacity-40 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0 [&>svg]:text-fg-secondary",
27
27
  indicator: "ml-auto flex h-4 w-4 items-center justify-center text-fg-accent",
28
28
  label: "px-2.5 pb-1 pt-2 text-[11px] font-semibold uppercase tracking-wider text-fg-secondary",
@@ -48,6 +48,21 @@ function DropdownMenuCheckboxItem({ className, children, ...props }) {
48
48
  /* @__PURE__ */ jsx(MenuPrimitive.ItemIndicator, { className: s.indicator(), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) })
49
49
  ] });
50
50
  }
51
+ function DropdownMenuSubTrigger({ className, children, ...props }) {
52
+ return /* @__PURE__ */ jsxs(MenuPrimitive.SubTrigger, { className: s.item({ className: cn("data-[state=open]:bg-surface-3", className) }), ...props, children: [
53
+ children,
54
+ /* @__PURE__ */ jsx("svg", { className: "ml-auto !h-4 !w-4 text-fg-secondary", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) })
55
+ ] });
56
+ }
57
+ function DropdownMenuSubContent({ sideOffset = 4, collisionPadding = 8, className, ...props }) {
58
+ return /* @__PURE__ */ jsx(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(MenuPrimitive.SubContent, { sideOffset, collisionPadding, className: s.content({ className: cn("max-h-(--radix-dropdown-menu-content-available-height)", className) }), ...props }) });
59
+ }
60
+ function DropdownMenuRadioItem({ className, children, ...props }) {
61
+ return /* @__PURE__ */ jsxs(MenuPrimitive.RadioItem, { className: s.item({ className }), ...props, children: [
62
+ children,
63
+ /* @__PURE__ */ jsx(MenuPrimitive.ItemIndicator, { className: s.indicator(), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) })
64
+ ] });
65
+ }
51
66
  function DropdownMenuLabel({ className, ...props }) {
52
67
  return /* @__PURE__ */ jsx(MenuPrimitive.Label, { className: s.label({ className }), ...props });
53
68
  }
@@ -62,7 +77,12 @@ var DropdownMenu = {
62
77
  CheckboxItem: DropdownMenuCheckboxItem,
63
78
  Label: DropdownMenuLabel,
64
79
  Separator: DropdownMenuSeparator,
65
- Group: MenuPrimitive.Group
80
+ Group: MenuPrimitive.Group,
81
+ Sub: MenuPrimitive.Sub,
82
+ SubTrigger: DropdownMenuSubTrigger,
83
+ SubContent: DropdownMenuSubContent,
84
+ RadioGroup: MenuPrimitive.RadioGroup,
85
+ RadioItem: DropdownMenuRadioItem
66
86
  };
67
87
 
68
88
  // src/filter-bar/filter-bar.tsx
@@ -156,4 +176,4 @@ export {
156
176
  readFilterParams,
157
177
  writeFilterParams
158
178
  };
159
- //# sourceMappingURL=chunk-CEJDH6SA.js.map
179
+ //# sourceMappingURL=chunk-2PNLHZLT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/filter-bar/filter-bar.tsx","../src/dropdown-menu/dropdown-menu.tsx"],"sourcesContent":["// Client (menus in a portal). The bar above a list: the controls that narrow it (a SearchField, FilterMenus, a\n// DateRangePicker — any child), the filters in force as removable chips, \"Clear all\", and the count of results in a\n// polite live region. It holds no state: the app keeps the filters — in the address, ideally — and the\n// `readFilterParams` / `writeFilterParams` helpers move them between a `URLSearchParams` and an object.\nimport { DropdownMenu as MenuPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { Chip } from \"../chip\";\nimport { DropdownMenu, menu } from \"../dropdown-menu\";\nimport { ChevronGlyph } from \"../glyphs\";\n\nexport const filterBar = tv({\n slots: {\n root: \"flex w-full flex-col gap-3\",\n controls: \"flex w-full flex-wrap items-center gap-2 [&>*]:min-w-0\",\n active: \"flex flex-wrap items-center gap-2\",\n clear:\n \"rounded-md px-2 py-1 text-xs font-semibold text-fg-accent hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n results: \"ml-auto text-xs text-fg-secondary tabular-nums\",\n trigger:\n \"inline-flex h-11 shrink-0 items-center gap-2 rounded-lg border border-border-default bg-surface-1 px-3.5 text-sm font-semibold text-fg-secondary \" +\n \"transition-colors hover:border-border-strong hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n \"data-[active]:border-accent data-[active]:bg-accent-soft data-[active]:text-fg data-[state=open]:border-border-strong\",\n count: \"inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-accent px-1.5 text-[11px] font-bold tabular-nums text-on-accent\",\n optionCount: \"ml-auto pl-4 text-xs tabular-nums text-fg-secondary\",\n },\n});\n\nexport type ActiveFilter = {\n /** A stable key (`\"status:failed\"`). */\n id: string;\n /** What the chip says, passed translated (\"Status: Failed\"). */\n label: string;\n /** Removes this filter. */\n onRemove: () => void;\n};\n\nexport type FilterBarProps = Omit<React.ComponentProps<\"div\">, \"children\" | \"results\"> & {\n /** The accessible name of the bar (\"Filter jobs\"), passed translated. */\n label: string;\n /** The controls: `SearchField`, `FilterMenu`, `DateRangePicker`, a `Chip.Group`… */\n children?: React.ReactNode;\n /** The filters in force, each a removable chip. */\n active?: readonly ActiveFilter[];\n /** Clears every filter; the \"Clear all\" button shows when there is at least one. */\n onClearAll?: () => void;\n /** The \"Clear all\" button (\"Clear filters\"), passed translated. */\n clearLabel?: string;\n /** A chip's remove button: `(label) => \"Remove \" + label`, passed translated. */\n removeLabel?: (label: string) => string;\n /** The count of results (\"42 jobs\"), announced politely when it changes. */\n results?: string;\n};\n\n/** The bar of filters above a list: controls, active filters as chips, clear all, the count of results. */\nexport function FilterBar({\n label,\n children,\n active = [],\n onClearAll,\n clearLabel = \"Clear filters\",\n removeLabel = (text) => `Remove ${text}`,\n results,\n className,\n ...props\n}: FilterBarProps) {\n const s = filterBar();\n return (\n <div role=\"group\" aria-label={label} className={s.root({ className })} {...props}>\n {children ? <div className={s.controls()}>{children}</div> : null}\n {active.length > 0 || results !== undefined ? (\n <div className={s.active()}>\n {active.map((filter) => (\n <Chip key={filter.id} size=\"sm\" removable removeLabel={removeLabel(filter.label)} onRemove={filter.onRemove}>\n {filter.label}\n </Chip>\n ))}\n {active.length > 0 && onClearAll ? (\n <button type=\"button\" className={s.clear()} onClick={onClearAll}>\n {clearLabel}\n </button>\n ) : null}\n <p className={s.results()} aria-live=\"polite\" aria-atomic>\n {results}\n </p>\n </div>\n ) : null}\n </div>\n );\n}\n\nexport type FilterOption = {\n /** What the app stores (and puts in the address). */\n value: string;\n /** What the person reads, passed translated. */\n label: string;\n /** How many results it would give: shown on the right. */\n count?: number;\n /** Shown but not choosable. */\n disabled?: boolean;\n};\n\ntype FilterMenuBase = {\n /** The name of the filter on its button (\"Status\"), passed translated. */\n label: string;\n /** The choices. */\n options: readonly FilterOption[];\n /** Opens the menu at first (a story, a test). */\n defaultOpen?: boolean;\n /** Classes merged on the button. */\n className?: string;\n};\n\nexport type FilterMenuProps =\n | (FilterMenuBase & {\n /** Several values (checkboxes, default) or one (radios). */\n multiple?: true;\n /** The values chosen. */\n value: readonly string[];\n /** Called with the values chosen. */\n onValueChange: (value: string[]) => void;\n })\n | (FilterMenuBase & {\n /** One value: the options are radios. */\n multiple: false;\n /** The value chosen, `\"\"` for none. */\n value: string;\n /** Called with the value chosen. */\n onValueChange: (value: string) => void;\n });\n\n/** A filter's button and its menu of options — checkboxes (several values) or radios (one) — with a count of chosen ones. */\nexport function FilterMenu(props: FilterMenuProps) {\n const { label, options, defaultOpen, className } = props;\n const s = filterBar();\n const m = menu();\n const chosen = props.multiple === false ? (props.value ? [props.value] : []) : props.value;\n const single = props.multiple === false ? options.find((o) => o.value === props.value) : undefined;\n const content = (option: FilterOption) => (\n <>\n {option.label}\n {option.count !== undefined ? <span className={s.optionCount()}>{option.count}</span> : null}\n </>\n );\n return (\n <DropdownMenu.Root defaultOpen={defaultOpen} modal={false}>\n <DropdownMenu.Trigger className={s.trigger({ className })} data-active={chosen.length > 0 ? \"\" : undefined}>\n {single ? `${label}: ${single.label}` : label}\n {props.multiple !== false && chosen.length > 0 ? <span className={s.count()}>{chosen.length}</span> : null}\n <ChevronGlyph className=\"h-4 w-4\" />\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"start\" aria-label={label}>\n {props.multiple === false ? (\n <MenuPrimitive.RadioGroup value={props.value} onValueChange={props.onValueChange}>\n {options.map((option) => (\n <MenuPrimitive.RadioItem key={option.value} value={option.value} disabled={option.disabled} className={m.item()}>\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-border-strong\">\n <MenuPrimitive.ItemIndicator className=\"h-2 w-2 rounded-full bg-accent\" />\n </span>\n {content(option)}\n </MenuPrimitive.RadioItem>\n ))}\n </MenuPrimitive.RadioGroup>\n ) : (\n options.map((option) => (\n <DropdownMenu.CheckboxItem\n key={option.value}\n disabled={option.disabled}\n checked={props.value.includes(option.value)}\n onSelect={(event) => event.preventDefault()}\n onCheckedChange={(checked) =>\n props.onValueChange(checked ? [...props.value, option.value] : props.value.filter((v) => v !== option.value))\n }\n >\n {content(option)}\n </DropdownMenu.CheckboxItem>\n ))\n )}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n}\n\n/** Filters read from an address: `{ status: [\"failed\", \"running\"], q: [\"cat\"] }` for the keys asked (repeated or comma-separated values). */\nexport function readFilterParams(params: URLSearchParams, keys: readonly string[]): Record<string, string[]> {\n return Object.fromEntries(\n keys.map((key) => [key, params.getAll(key).flatMap((v) => v.split(\",\")).map((v) => v.trim()).filter(Boolean)]),\n );\n}\n\n/** Filters written into an address (a copy of `base`): empty filters removed, several values comma-separated, the page reset. */\nexport function writeFilterParams(base: URLSearchParams, filters: Record<string, string | readonly string[] | null | undefined>, resetKey = \"page\") {\n const next = new URLSearchParams(base);\n for (const [key, value] of Object.entries(filters)) {\n const list = value == null ? [] : typeof value === \"string\" ? [value] : [...value];\n if (list.filter(Boolean).length === 0) next.delete(key);\n else next.set(key, list.filter(Boolean).join(\",\"));\n }\n if (resetKey) next.delete(resetKey);\n return next;\n}\n","// Client (a portal). Radix does the roving focus, the arrows, Home/End, typeahead, Escape and the focus return.\nimport { DropdownMenu as MenuPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\nexport const menu = tv({\n slots: {\n content: cn(floating, \"min-w-48 max-h-(--radix-dropdown-menu-content-available-height) overflow-y-auto overflow-x-hidden overscroll-contain p-1 origin-(--radix-dropdown-menu-content-transform-origin)\"),\n item:\n \"relative flex cursor-pointer select-none items-center gap-2 rounded-md px-2.5 py-2 text-sm text-fg outline-hidden transition-colors \" +\n \"data-highlighted:bg-surface-3 data-disabled:pointer-events-none data-disabled:opacity-40 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0 \" +\n \"[&>svg]:text-fg-secondary\",\n indicator: \"ml-auto flex h-4 w-4 items-center justify-center text-fg-accent\",\n label: \"px-2.5 pb-1 pt-2 text-[11px] font-semibold uppercase tracking-wider text-fg-secondary\",\n separator: \"-mx-1 my-1 h-px bg-border-subtle\",\n },\n variants: {\n // The label reads in the danger text role (≥ 4.5:1 on the menu surface, both themes); the icon and the highlight\n // carry the danger fill.\n tone: { default: {}, danger: { item: \"text-fg-danger data-highlighted:bg-danger/15 [&>svg]:text-danger\" } },\n },\n defaultVariants: { tone: \"default\" },\n});\nconst s = menu();\n\nexport type DropdownMenuContentProps = React.ComponentProps<typeof MenuPrimitive.Content> & {\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function DropdownMenuContent({ sideOffset = 6, align = \"end\", collisionPadding = 8, container, className, ...props }: DropdownMenuContentProps) {\n return (\n <MenuPrimitive.Portal container={container}>\n <MenuPrimitive.Content sideOffset={sideOffset} align={align} collisionPadding={collisionPadding} className={s.content({ className })} {...props} />\n </MenuPrimitive.Portal>\n );\n}\n\nexport type DropdownMenuItemProps = React.ComponentProps<typeof MenuPrimitive.Item> & {\n /** `danger` for a destructive action: the icon and the highlight carry the danger, the label stays legible. */\n tone?: \"default\" | \"danger\";\n};\n\n/** An action. `tone=\"danger\"` for a destructive one; `onSelect` runs it (the menu closes). */\nexport function DropdownMenuItem({ tone, className, ...props }: DropdownMenuItemProps) {\n return <MenuPrimitive.Item data-tone={tone ?? \"default\"} className={menu({ tone }).item({ className })} {...props} />;\n}\n\n/** A toggled option: `checked` + `onCheckedChange`. */\nexport function DropdownMenuCheckboxItem({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.CheckboxItem>) {\n return (\n <MenuPrimitive.CheckboxItem className={s.item({ className })} {...props}>\n {children}\n <MenuPrimitive.ItemIndicator className={s.indicator()}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </MenuPrimitive.ItemIndicator>\n </MenuPrimitive.CheckboxItem>\n );\n}\n\n/** A submenu's trigger: an item that opens `DropdownMenu.SubContent`, with a chevron. */\nexport function DropdownMenuSubTrigger({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.SubTrigger>) {\n return (\n <MenuPrimitive.SubTrigger className={s.item({ className: cn(\"data-[state=open]:bg-surface-3\", className) })} {...props}>\n {children}\n <svg className=\"ml-auto !h-4 !w-4 text-fg-secondary\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </MenuPrimitive.SubTrigger>\n );\n}\n\n/** The submenu's panel (same material as the menu). */\nexport function DropdownMenuSubContent({ sideOffset = 4, collisionPadding = 8, className, ...props }: React.ComponentProps<typeof MenuPrimitive.SubContent>) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.SubContent sideOffset={sideOffset} collisionPadding={collisionPadding} className={s.content({ className: cn(\"max-h-(--radix-dropdown-menu-content-available-height)\", className) })} {...props} />\n </MenuPrimitive.Portal>\n );\n}\n\n/** One choice among several (`DropdownMenu.RadioGroup` holds the value): a language, a sort order. */\nexport function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof MenuPrimitive.RadioItem>) {\n return (\n <MenuPrimitive.RadioItem className={s.item({ className })} {...props}>\n {children}\n <MenuPrimitive.ItemIndicator className={s.indicator()}>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </MenuPrimitive.ItemIndicator>\n </MenuPrimitive.RadioItem>\n );\n}\n\nexport function DropdownMenuLabel({ className, ...props }: React.ComponentProps<typeof MenuPrimitive.Label>) {\n return <MenuPrimitive.Label className={s.label({ className })} {...props} />;\n}\n\nexport function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof MenuPrimitive.Separator>) {\n return <MenuPrimitive.Separator className={s.separator({ className })} {...props} />;\n}\n\n/** `DropdownMenu.Root/Trigger/Content/Item/CheckboxItem/Label/Separator/Group`. `open`/`defaultOpen` + `onOpenChange`. */\nexport const DropdownMenu = {\n Root: MenuPrimitive.Root,\n Trigger: MenuPrimitive.Trigger,\n Content: DropdownMenuContent,\n Item: DropdownMenuItem,\n CheckboxItem: DropdownMenuCheckboxItem,\n Label: DropdownMenuLabel,\n Separator: DropdownMenuSeparator,\n Group: MenuPrimitive.Group,\n Sub: MenuPrimitive.Sub,\n SubTrigger: DropdownMenuSubTrigger,\n SubContent: DropdownMenuSubContent,\n RadioGroup: MenuPrimitive.RadioGroup,\n RadioItem: DropdownMenuRadioItem,\n};\n"],"mappings":"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","names":["MenuPrimitive","tv","jsx","jsxs","tv","s","MenuPrimitive"]}
@@ -0,0 +1,21 @@
1
+ "use client";
2
+
3
+ // src/block-link.tsx
4
+ import { jsx } from "react/jsx-runtime";
5
+ var isExternal = (href) => /^[a-z][a-z0-9+.-]*:/i.test(href);
6
+ function BlockLink({
7
+ href,
8
+ linkAs: Link = "a",
9
+ external = isExternal(href),
10
+ rel,
11
+ ...props
12
+ }) {
13
+ if (external) return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
14
+ const Comp = Link;
15
+ return /* @__PURE__ */ jsx(Comp, { href, ...props });
16
+ }
17
+
18
+ export {
19
+ BlockLink
20
+ };
21
+ //# sourceMappingURL=chunk-C7LTF5CC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// 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"],"mappings":";;;AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,MAAa,GAAG,OAAO;AACtC;","names":[]}
@@ -13,7 +13,7 @@ import {
13
13
  DropdownMenu,
14
14
  FilterBar,
15
15
  FilterMenu
16
- } from "./chunk-CEJDH6SA.js";
16
+ } from "./chunk-2PNLHZLT.js";
17
17
  import {
18
18
  cn
19
19
  } from "./chunk-NSLXEDIS.js";
@@ -1077,4 +1077,4 @@ export {
1077
1077
  DataTableColumnsMenu,
1078
1078
  DataTableExport
1079
1079
  };
1080
- //# sourceMappingURL=chunk-F7FVPPBB.js.map
1080
+ //# sourceMappingURL=chunk-LYOPPBMC.js.map
@@ -26,6 +26,7 @@ var SearchGlyph = (p) => /* @__PURE__ */ jsxs(Glyph, { ...p, children: [
26
26
  var CloseGlyph = (p) => /* @__PURE__ */ jsx(Glyph, { ...p, children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) });
27
27
  var ChevronGlyph = ({ direction = "down", ...p }) => /* @__PURE__ */ jsx(Glyph, { ...p, children: /* @__PURE__ */ jsx("path", { d: { left: "m15 6-6 6 6 6", right: "m9 6 6 6-6 6", up: "m6 15 6-6 6 6", down: "m6 9 6 6 6-6" }[direction] }) });
28
28
  var CheckGlyph = (p) => /* @__PURE__ */ jsx(Glyph, { ...p, children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
29
+ var ArrowGlyph = ({ direction = "right", ...p }) => /* @__PURE__ */ jsx(Glyph, { ...p, children: /* @__PURE__ */ jsx("path", { d: direction === "left" ? "M19 12H5m0 0 6-6m-6 6 6 6" : "M5 12h14m0 0-6-6m6 6-6 6" }) });
29
30
  var CopyGlyph = (p) => /* @__PURE__ */ jsxs(Glyph, { ...p, children: [
30
31
  /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "11", height: "11", rx: "2" }),
31
32
  /* @__PURE__ */ jsx("path", { d: "M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3" })
@@ -36,6 +37,7 @@ export {
36
37
  CloseGlyph,
37
38
  ChevronGlyph,
38
39
  CheckGlyph,
40
+ ArrowGlyph,
39
41
  CopyGlyph
40
42
  };
41
- //# sourceMappingURL=chunk-AFY35UCB.js.map
43
+ //# sourceMappingURL=chunk-P7GZR5CU.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/glyphs.tsx"],"sourcesContent":["// The small line glyphs the data and media primitives draw (play, volume, search, chevrons…): decorative, 24-unit\n// box, `currentColor`, sized by the caller's class. Shared by the entries that need them; never exported on its own —\n// a product draws its own icons with @krizaka/icons.\nimport type * as React from \"react\";\n\ntype GlyphProps = { className?: string };\n\nfunction Glyph({ className = \"h-4 w-4\", fill, children }: GlyphProps & { fill?: boolean; children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n className={className}\n fill={fill ? \"currentColor\" : \"none\"}\n stroke={fill ? \"none\" : \"currentColor\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n focusable=\"false\"\n >\n {children}\n </svg>\n );\n}\n\nexport const PlayGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <path d=\"M8 5.5v13a1 1 0 0 0 1.5.86l10.4-6.5a1 1 0 0 0 0-1.72L9.5 4.64A1 1 0 0 0 8 5.5Z\" />\n </Glyph>\n);\nexport const PauseGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n </Glyph>\n);\nexport const VolumeGlyph = ({ muted, ...p }: GlyphProps & { muted?: boolean }) => (\n <Glyph {...p}>\n <path d=\"M11 5 6 9H3v6h3l5 4V5Z\" />\n {muted ? <path d=\"m22 9-6 6m0-6 6 6\" /> : <path d=\"M15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13\" />}\n </Glyph>\n);\nexport const FullscreenGlyph = ({ exit, ...p }: GlyphProps & { exit?: boolean }) => (\n <Glyph {...p}>\n {exit ? <path d=\"M9 4v5H4m11-5v5h5M9 20v-5H4m11 5v-5h5\" /> : <path d=\"M4 9V4h5m6 0h5v5M4 15v5h5m11-5v5h-5\" />}\n </Glyph>\n);\nexport const CaptionsGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"M10 10.5a2 2 0 1 0 0 3M17 10.5a2 2 0 1 0 0 3\" />\n </Glyph>\n);\nexport const PipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <rect x=\"12\" y=\"12\" width=\"6\" height=\"4\" rx=\"1\" />\n </Glyph>\n);\nexport const SearchGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <path d=\"m20 20-3.5-3.5\" />\n </Glyph>\n);\nexport const CloseGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </Glyph>\n);\nexport const ChevronGlyph = ({ direction = \"down\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" | \"up\" | \"down\" }) => (\n <Glyph {...p}>\n <path d={{ left: \"m15 6-6 6 6 6\", right: \"m9 6 6 6-6 6\", up: \"m6 15 6-6 6 6\", down: \"m6 9 6 6 6-6\" }[direction]} />\n </Glyph>\n);\nexport const CheckGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Glyph>\n);\nexport const PlusGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 5v14M5 12h14\" />\n </Glyph>\n);\nexport const CalendarGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\" />\n <path d=\"M3 10h18M8 3v4M16 3v4\" />\n </Glyph>\n);\nexport const UploadGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 16V4m0 0L7 9m5-5 5 5\" />\n <path d=\"M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\" />\n </Glyph>\n);\nexport const FileGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5Z\" />\n <path d=\"M14 3v5h5\" />\n </Glyph>\n);\nexport const CameraGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 8h3l2-3h6l2 3h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z\" />\n <circle cx=\"12\" cy=\"13.5\" r=\"3.5\" />\n </Glyph>\n);\nexport const FlipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 0 1 14-5.3M20 12a8 8 0 0 1-14 5.3\" />\n <path d=\"M18 3v4h-4M6 21v-4h4\" />\n </Glyph>\n);\nexport const RetryGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 1 0 2.3-5.7L4 8.5\" />\n <path d=\"M4 4v4.5h4.5\" />\n </Glyph>\n);\nexport const SortGlyph = ({ direction, ...p }: GlyphProps & { direction?: \"ascending\" | \"descending\" }) => (\n <Glyph {...p}>\n {direction === \"ascending\" ? <path d=\"m7 14 5-5 5 5\" /> : direction === \"descending\" ? <path d=\"m7 10 5 5 5-5\" /> : <path d=\"m8 9 4-4 4 4M8 15l4 4 4-4\" />}\n </Glyph>\n);\nexport const ArrowGlyph = ({ direction = \"right\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" }) => (\n <Glyph {...p}>\n <path d={direction === \"left\" ? \"M19 12H5m0 0 6-6m-6 6 6 6\" : \"M5 12h14m0 0-6-6m6 6-6 6\"} />\n </Glyph>\n);\nexport const ExternalGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 4h6v6M20 4l-9 9\" />\n <path d=\"M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4\" />\n </Glyph>\n);\nexport const WarningGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 4 2.5 20h19L12 4Z\" />\n <path d=\"M12 10v4M12 17.2v.1\" />\n </Glyph>\n);\nexport const CopyGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"9\" y=\"9\" width=\"11\" height=\"11\" rx=\"2\" />\n <path d=\"M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3\" />\n </Glyph>\n);\n"],"mappings":";;;AASI,cAsBF,YAtBE;AAFJ,SAAS,MAAM,EAAE,YAAY,WAAW,MAAM,SAAS,GAA+D;AACpH,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR;AAAA,MACA,MAAM,OAAO,iBAAiB;AAAA,MAC9B,QAAQ,OAAO,SAAS;AAAA,MACxB,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAW;AAAA,MACX,WAAU;AAAA,MAET;AAAA;AAAA,EACH;AAEJ;AAoCO,IAAM,cAAc,CAAC,MAC1B,qBAAC,SAAO,GAAG,GACT;AAAA,sBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,EAC9B,oBAAC,UAAK,GAAE,kBAAiB;AAAA,GAC3B;AAEK,IAAM,aAAa,CAAC,MACzB,oBAAC,SAAO,GAAG,GACT,8BAAC,UAAK,GAAE,wBAAuB,GACjC;AAEK,IAAM,eAAe,CAAC,EAAE,YAAY,QAAQ,GAAG,EAAE,MACtD,oBAAC,SAAO,GAAG,GACT,8BAAC,UAAK,GAAG,EAAE,MAAM,iBAAiB,OAAO,gBAAgB,IAAI,iBAAiB,MAAM,eAAe,EAAE,SAAS,GAAG,GACnH;AAEK,IAAM,aAAa,CAAC,MACzB,oBAAC,SAAO,GAAG,GACT,8BAAC,UAAK,GAAE,mBAAkB,GAC5B;AAiEK,IAAM,YAAY,CAAC,MACxB,qBAAC,SAAO,GAAG,GACT;AAAA,sBAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,EAChD,oBAAC,UAAK,GAAE,2DAA0D;AAAA,GACpE;","names":[]}
1
+ {"version":3,"sources":["../src/glyphs.tsx"],"sourcesContent":["// The small line glyphs the data and media primitives draw (play, volume, search, chevrons…): decorative, 24-unit\n// box, `currentColor`, sized by the caller's class. Shared by the entries that need them; never exported on its own —\n// a product draws its own icons with @krizaka/icons.\nimport type * as React from \"react\";\n\ntype GlyphProps = { className?: string };\n\nfunction Glyph({ className = \"h-4 w-4\", fill, children }: GlyphProps & { fill?: boolean; children: React.ReactNode }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n className={className}\n fill={fill ? \"currentColor\" : \"none\"}\n stroke={fill ? \"none\" : \"currentColor\"}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n focusable=\"false\"\n >\n {children}\n </svg>\n );\n}\n\nexport const PlayGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <path d=\"M8 5.5v13a1 1 0 0 0 1.5.86l10.4-6.5a1 1 0 0 0 0-1.72L9.5 4.64A1 1 0 0 0 8 5.5Z\" />\n </Glyph>\n);\nexport const PauseGlyph = (p: GlyphProps) => (\n <Glyph {...p} fill>\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n </Glyph>\n);\nexport const VolumeGlyph = ({ muted, ...p }: GlyphProps & { muted?: boolean }) => (\n <Glyph {...p}>\n <path d=\"M11 5 6 9H3v6h3l5 4V5Z\" />\n {muted ? <path d=\"m22 9-6 6m0-6 6 6\" /> : <path d=\"M15.5 8.5a5 5 0 0 1 0 7M18.5 5.5a9 9 0 0 1 0 13\" />}\n </Glyph>\n);\nexport const FullscreenGlyph = ({ exit, ...p }: GlyphProps & { exit?: boolean }) => (\n <Glyph {...p}>\n {exit ? <path d=\"M9 4v5H4m11-5v5h5M9 20v-5H4m11 5v-5h5\" /> : <path d=\"M4 9V4h5m6 0h5v5M4 15v5h5m11-5v5h-5\" />}\n </Glyph>\n);\nexport const CaptionsGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <path d=\"M10 10.5a2 2 0 1 0 0 3M17 10.5a2 2 0 1 0 0 3\" />\n </Glyph>\n);\nexport const PipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"2\" />\n <rect x=\"12\" y=\"12\" width=\"6\" height=\"4\" rx=\"1\" />\n </Glyph>\n);\nexport const SearchGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <path d=\"m20 20-3.5-3.5\" />\n </Glyph>\n);\nexport const CloseGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </Glyph>\n);\nexport const ChevronGlyph = ({ direction = \"down\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" | \"up\" | \"down\" }) => (\n <Glyph {...p}>\n <path d={{ left: \"m15 6-6 6 6 6\", right: \"m9 6 6 6-6 6\", up: \"m6 15 6-6 6 6\", down: \"m6 9 6 6 6-6\" }[direction]} />\n </Glyph>\n);\nexport const CheckGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Glyph>\n);\nexport const PlusGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 5v14M5 12h14\" />\n </Glyph>\n);\nexport const CalendarGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"16\" rx=\"2\" />\n <path d=\"M3 10h18M8 3v4M16 3v4\" />\n </Glyph>\n);\nexport const UploadGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 16V4m0 0L7 9m5-5 5 5\" />\n <path d=\"M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2\" />\n </Glyph>\n);\nexport const FileGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5Z\" />\n <path d=\"M14 3v5h5\" />\n </Glyph>\n);\nexport const CameraGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 8h3l2-3h6l2 3h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1Z\" />\n <circle cx=\"12\" cy=\"13.5\" r=\"3.5\" />\n </Glyph>\n);\nexport const FlipGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 0 1 14-5.3M20 12a8 8 0 0 1-14 5.3\" />\n <path d=\"M18 3v4h-4M6 21v-4h4\" />\n </Glyph>\n);\nexport const RetryGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M4 12a8 8 0 1 0 2.3-5.7L4 8.5\" />\n <path d=\"M4 4v4.5h4.5\" />\n </Glyph>\n);\nexport const SortGlyph = ({ direction, ...p }: GlyphProps & { direction?: \"ascending\" | \"descending\" }) => (\n <Glyph {...p}>\n {direction === \"ascending\" ? <path d=\"m7 14 5-5 5 5\" /> : direction === \"descending\" ? <path d=\"m7 10 5 5 5-5\" /> : <path d=\"m8 9 4-4 4 4M8 15l4 4 4-4\" />}\n </Glyph>\n);\nexport const ArrowGlyph = ({ direction = \"right\", ...p }: GlyphProps & { direction?: \"left\" | \"right\" }) => (\n <Glyph {...p}>\n <path d={direction === \"left\" ? \"M19 12H5m0 0 6-6m-6 6 6 6\" : \"M5 12h14m0 0-6-6m6 6-6 6\"} />\n </Glyph>\n);\nexport const ExternalGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M14 4h6v6M20 4l-9 9\" />\n <path d=\"M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4\" />\n </Glyph>\n);\nexport const WarningGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <path d=\"M12 4 2.5 20h19L12 4Z\" />\n <path d=\"M12 10v4M12 17.2v.1\" />\n </Glyph>\n);\nexport const CopyGlyph = (p: GlyphProps) => (\n <Glyph {...p}>\n <rect x=\"9\" y=\"9\" width=\"11\" height=\"11\" rx=\"2\" />\n <path d=\"M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3\" />\n </Glyph>\n);\n"],"mappings":";;;AASI,cAsBF,YAtBE;AAFJ,SAAS,MAAM,EAAE,YAAY,WAAW,MAAM,SAAS,GAA+D;AACpH,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR;AAAA,MACA,MAAM,OAAO,iBAAiB;AAAA,MAC9B,QAAQ,OAAO,SAAS;AAAA,MACxB,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAW;AAAA,MACX,WAAU;AAAA,MAET;AAAA;AAAA,EACH;AAEJ;AAoCO,IAAM,cAAc,CAAC,MAC1B,qBAAC,SAAO,GAAG,GACT;AAAA,sBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,EAC9B,oBAAC,UAAK,GAAE,kBAAiB;AAAA,GAC3B;AAEK,IAAM,aAAa,CAAC,MACzB,oBAAC,SAAO,GAAG,GACT,8BAAC,UAAK,GAAE,wBAAuB,GACjC;AAEK,IAAM,eAAe,CAAC,EAAE,YAAY,QAAQ,GAAG,EAAE,MACtD,oBAAC,SAAO,GAAG,GACT,8BAAC,UAAK,GAAG,EAAE,MAAM,iBAAiB,OAAO,gBAAgB,IAAI,iBAAiB,MAAM,eAAe,EAAE,SAAS,GAAG,GACnH;AAEK,IAAM,aAAa,CAAC,MACzB,oBAAC,SAAO,GAAG,GACT,8BAAC,UAAK,GAAE,mBAAkB,GAC5B;AAgDK,IAAM,aAAa,CAAC,EAAE,YAAY,SAAS,GAAG,EAAE,MACrD,oBAAC,SAAO,GAAG,GACT,8BAAC,UAAK,GAAG,cAAc,SAAS,8BAA8B,4BAA4B,GAC5F;AAcK,IAAM,YAAY,CAAC,MACxB,qBAAC,SAAO,GAAG,GACT;AAAA,sBAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,EAChD,oBAAC,UAAK,GAAE,2DAA0D;AAAA,GACpE;","names":[]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CheckGlyph,
4
4
  CopyGlyph
5
- } from "./chunk-AFY35UCB.js";
5
+ } from "./chunk-P7GZR5CU.js";
6
6
  import {
7
7
  cn
8
8
  } from "./chunk-WU4VLSEA.js";
@@ -0,0 +1,125 @@
1
+ import * as tailwind_variants from 'tailwind-variants';
2
+ import * as React from 'react';
3
+ import { L as LinkComponent } from './block-link-BAg4eoZk.js';
4
+
5
+ declare const coverHero: tailwind_variants.TVReturnType<{
6
+ [key: string]: {
7
+ [key: string]: tailwind_variants.ClassValue | {
8
+ body?: tailwind_variants.ClassValue;
9
+ title?: tailwind_variants.ClassValue;
10
+ media?: tailwind_variants.ClassValue;
11
+ root?: tailwind_variants.ClassValue;
12
+ eyebrow?: tailwind_variants.ClassValue;
13
+ lead?: tailwind_variants.ClassValue;
14
+ actions?: tailwind_variants.ClassValue;
15
+ veil?: tailwind_variants.ClassValue;
16
+ plain?: tailwind_variants.ClassValue;
17
+ back?: tailwind_variants.ClassValue;
18
+ facts?: tailwind_variants.ClassValue;
19
+ };
20
+ };
21
+ } | {
22
+ [x: string]: {
23
+ [x: string]: tailwind_variants.ClassValue | {
24
+ body?: tailwind_variants.ClassValue;
25
+ title?: tailwind_variants.ClassValue;
26
+ media?: tailwind_variants.ClassValue;
27
+ root?: tailwind_variants.ClassValue;
28
+ eyebrow?: tailwind_variants.ClassValue;
29
+ lead?: tailwind_variants.ClassValue;
30
+ actions?: tailwind_variants.ClassValue;
31
+ veil?: tailwind_variants.ClassValue;
32
+ plain?: tailwind_variants.ClassValue;
33
+ back?: tailwind_variants.ClassValue;
34
+ facts?: tailwind_variants.ClassValue;
35
+ };
36
+ };
37
+ } | {}, {
38
+ root: string;
39
+ media: string;
40
+ veil: string;
41
+ plain: string;
42
+ body: string;
43
+ back: string;
44
+ eyebrow: string;
45
+ title: string;
46
+ lead: string;
47
+ facts: string;
48
+ actions: string;
49
+ }, undefined, {
50
+ [key: string]: {
51
+ [key: string]: tailwind_variants.ClassValue | {
52
+ body?: tailwind_variants.ClassValue;
53
+ title?: tailwind_variants.ClassValue;
54
+ media?: tailwind_variants.ClassValue;
55
+ root?: tailwind_variants.ClassValue;
56
+ eyebrow?: tailwind_variants.ClassValue;
57
+ lead?: tailwind_variants.ClassValue;
58
+ actions?: tailwind_variants.ClassValue;
59
+ veil?: tailwind_variants.ClassValue;
60
+ plain?: tailwind_variants.ClassValue;
61
+ back?: tailwind_variants.ClassValue;
62
+ facts?: tailwind_variants.ClassValue;
63
+ };
64
+ };
65
+ } | {}, {
66
+ root: string;
67
+ media: string;
68
+ veil: string;
69
+ plain: string;
70
+ body: string;
71
+ back: string;
72
+ eyebrow: string;
73
+ title: string;
74
+ lead: string;
75
+ facts: string;
76
+ actions: string;
77
+ }, tailwind_variants.TVReturnTypeLike<unknown, {
78
+ root: string;
79
+ media: string;
80
+ veil: string;
81
+ plain: string;
82
+ body: string;
83
+ back: string;
84
+ eyebrow: string;
85
+ title: string;
86
+ lead: string;
87
+ facts: string;
88
+ actions: string;
89
+ }>>;
90
+ type CoverMedia = {
91
+ /** The still: the photo, or the poster of the loop (shown first, and alone under reduced motion). */
92
+ src: string;
93
+ /** What it shows, in words; empty when it only decorates. */
94
+ alt?: string;
95
+ /** A muted loop over the still: WebM first, MP4 for Safari. */
96
+ video?: {
97
+ webm?: string;
98
+ mp4?: string;
99
+ };
100
+ };
101
+ type CoverHeroProps = Omit<React.ComponentProps<"header">, "title"> & {
102
+ /** The cover. Without it the hero wears the brand's colours. */
103
+ cover?: CoverMedia;
104
+ /** A short mono line above the name (where the shop is: `Saint-Henri · Montréal`). */
105
+ eyebrow?: React.ReactNode;
106
+ /** The name: the page's `h1`. */
107
+ title: React.ReactNode;
108
+ /** One line: what it promises. */
109
+ lead?: React.ReactNode;
110
+ /** Chips under the lead: open now, the neighbourhood, a rating — only what is true. */
111
+ facts?: React.ReactNode;
112
+ /** The main action (`ButtonLink`). */
113
+ actions?: React.ReactNode;
114
+ /** The way back, above the eyebrow. */
115
+ back?: {
116
+ href: string;
117
+ label: string;
118
+ };
119
+ /** The app's link component for the back link. */
120
+ linkAs?: LinkComponent;
121
+ };
122
+ /** A shop's first screen: the cover, the name, the promise, the facts and the main action. */
123
+ declare function CoverHero({ cover, eyebrow, title, lead, facts, actions, back, linkAs, className, ...props }: CoverHeroProps): React.JSX.Element;
124
+
125
+ export { CoverHero, type CoverHeroProps, type CoverMedia, coverHero };
@@ -0,0 +1,82 @@
1
+ "use client";
2
+ import {
3
+ ArrowGlyph
4
+ } from "./chunk-P7GZR5CU.js";
5
+ import {
6
+ cn
7
+ } from "./chunk-WU4VLSEA.js";
8
+ import {
9
+ BlockLink
10
+ } from "./chunk-C7LTF5CC.js";
11
+
12
+ // src/cover-hero/cover-hero.tsx
13
+ import * as React2 from "react";
14
+ import { tv } from "tailwind-variants";
15
+
16
+ // src/page/page.tsx
17
+ import * as React from "react";
18
+ import { Fragment as Fragment2, jsx, jsxs } from "react/jsx-runtime";
19
+ function Page({ size = "default", as: Tag = "div", className, ...props }) {
20
+ return /* @__PURE__ */ jsx(Tag, { "data-size": size === "default" ? void 0 : size, className: cn("kz-frame", className), ...props });
21
+ }
22
+
23
+ // src/cover-hero/cover-hero.tsx
24
+ import { Fragment as Fragment3, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
25
+ var coverHero = tv({
26
+ slots: {
27
+ root: "relative isolate flex min-h-[26rem] items-end overflow-hidden bg-surface-1 text-fg data-[cover]:text-fg-on-media sm:min-h-[30rem] lg:min-h-[34rem]",
28
+ media: "absolute inset-0 -z-20 h-full w-full object-cover",
29
+ veil: "absolute inset-0 -z-10 bg-linear-to-t from-scrim-strong via-scrim/55 to-scrim/10",
30
+ plain: "absolute inset-0 -z-10 bg-linear-to-br from-accent/25 via-surface-1 to-accent-2/20",
31
+ body: "flex flex-col gap-4 pb-8 pt-24 sm:pb-12",
32
+ back: "inline-flex w-fit items-center gap-1.5 text-sm font-semibold text-current no-underline opacity-90 hover:opacity-100",
33
+ eyebrow: "m-0 font-mono text-xs font-semibold uppercase tracking-widest opacity-90",
34
+ title: "m-0 max-w-3xl font-display text-4xl font-black leading-[1.05] tracking-tight sm:text-5xl lg:text-6xl",
35
+ lead: "m-0 max-w-2xl text-base leading-relaxed opacity-95 sm:text-lg",
36
+ facts: "flex flex-wrap items-center gap-2",
37
+ actions: "flex flex-wrap items-center gap-3 pt-1"
38
+ }
39
+ });
40
+ var s = coverHero();
41
+ function usePlayLoop(enabled) {
42
+ const [play, setPlay] = React2.useState(false);
43
+ React2.useEffect(() => {
44
+ if (!enabled) return;
45
+ const q = window.matchMedia("(prefers-reduced-motion: reduce)");
46
+ const sync = () => setPlay(!q.matches);
47
+ sync();
48
+ q.addEventListener("change", sync);
49
+ return () => q.removeEventListener("change", sync);
50
+ }, [enabled]);
51
+ return play;
52
+ }
53
+ function CoverHero({ cover, eyebrow, title, lead, facts, actions, back, linkAs, className, ...props }) {
54
+ const play = usePlayLoop(Boolean(cover?.video));
55
+ return /* @__PURE__ */ jsxs2("header", { "data-cover": cover ? "" : void 0, className: s.root({ className }), ...props, children: [
56
+ cover ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
57
+ /* @__PURE__ */ jsx2("img", { src: cover.src, alt: cover.alt ?? "", className: s.media(), fetchPriority: "high", decoding: "async" }),
58
+ play && cover.video && /* @__PURE__ */ jsxs2("video", { className: s.media(), poster: cover.src, autoPlay: true, muted: true, loop: true, playsInline: true, preload: "metadata", "aria-hidden": true, tabIndex: -1, children: [
59
+ cover.video.webm && /* @__PURE__ */ jsx2("source", { src: cover.video.webm, type: "video/webm" }),
60
+ cover.video.mp4 && /* @__PURE__ */ jsx2("source", { src: cover.video.mp4, type: "video/mp4" })
61
+ ] }),
62
+ /* @__PURE__ */ jsx2("div", { "aria-hidden": true, className: s.veil() })
63
+ ] }) : /* @__PURE__ */ jsx2("div", { "aria-hidden": true, className: s.plain() }),
64
+ /* @__PURE__ */ jsx2(Page, { children: /* @__PURE__ */ jsxs2("div", { className: s.body(), children: [
65
+ back && /* @__PURE__ */ jsxs2(BlockLink, { href: back.href, linkAs, className: s.back(), children: [
66
+ /* @__PURE__ */ jsx2(ArrowGlyph, { direction: "left", className: "h-3.5 w-3.5" }),
67
+ " ",
68
+ back.label
69
+ ] }),
70
+ eyebrow && /* @__PURE__ */ jsx2("p", { className: s.eyebrow(), children: eyebrow }),
71
+ /* @__PURE__ */ jsx2("h1", { className: s.title(), children: title }),
72
+ lead && /* @__PURE__ */ jsx2("p", { className: s.lead(), children: lead }),
73
+ facts && /* @__PURE__ */ jsx2("div", { className: s.facts(), children: facts }),
74
+ actions && /* @__PURE__ */ jsx2("div", { className: s.actions(), children: actions })
75
+ ] }) })
76
+ ] });
77
+ }
78
+ export {
79
+ CoverHero,
80
+ coverHero
81
+ };
82
+ //# sourceMappingURL=cover-hero.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cover-hero/cover-hero.tsx","../src/page/page.tsx"],"sourcesContent":["// Client (the reader's motion preference). The first screen of a shop or a place: its cover — a photo, or a muted loop that\n// stays a still under reduced motion — behind the name, a one-line promise, a few facts and the main action. The words sit\n// on a veil that reads in both themes; without a cover the brand's colours take its place.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { ArrowGlyph } from \"../glyphs\";\nimport { Page } from \"../page/page\";\n\nexport const coverHero = tv({\n slots: {\n root: \"relative isolate flex min-h-[26rem] items-end overflow-hidden bg-surface-1 text-fg data-[cover]:text-fg-on-media sm:min-h-[30rem] lg:min-h-[34rem]\",\n media: \"absolute inset-0 -z-20 h-full w-full object-cover\",\n veil: \"absolute inset-0 -z-10 bg-linear-to-t from-scrim-strong via-scrim/55 to-scrim/10\",\n plain: \"absolute inset-0 -z-10 bg-linear-to-br from-accent/25 via-surface-1 to-accent-2/20\",\n body: \"flex flex-col gap-4 pb-8 pt-24 sm:pb-12\",\n back: \"inline-flex w-fit items-center gap-1.5 text-sm font-semibold text-current no-underline opacity-90 hover:opacity-100\",\n eyebrow: \"m-0 font-mono text-xs font-semibold uppercase tracking-widest opacity-90\",\n title: \"m-0 max-w-3xl font-display text-4xl font-black leading-[1.05] tracking-tight sm:text-5xl lg:text-6xl\",\n lead: \"m-0 max-w-2xl text-base leading-relaxed opacity-95 sm:text-lg\",\n facts: \"flex flex-wrap items-center gap-2\",\n actions: \"flex flex-wrap items-center gap-3 pt-1\",\n },\n});\nconst s = coverHero();\n\nexport type CoverMedia = {\n /** The still: the photo, or the poster of the loop (shown first, and alone under reduced motion). */\n src: string;\n /** What it shows, in words; empty when it only decorates. */\n alt?: string;\n /** A muted loop over the still: WebM first, MP4 for Safari. */\n video?: { webm?: string; mp4?: string };\n};\n\nexport type CoverHeroProps = Omit<React.ComponentProps<\"header\">, \"title\"> & {\n /** The cover. Without it the hero wears the brand's colours. */\n cover?: CoverMedia;\n /** A short mono line above the name (where the shop is: `Saint-Henri · Montréal`). */\n eyebrow?: React.ReactNode;\n /** The name: the page's `h1`. */\n title: React.ReactNode;\n /** One line: what it promises. */\n lead?: React.ReactNode;\n /** Chips under the lead: open now, the neighbourhood, a rating — only what is true. */\n facts?: React.ReactNode;\n /** The main action (`ButtonLink`). */\n actions?: React.ReactNode;\n /** The way back, above the eyebrow. */\n back?: { href: string; label: string };\n /** The app's link component for the back link. */\n linkAs?: LinkComponent;\n};\n\nfunction usePlayLoop(enabled: boolean) {\n const [play, setPlay] = React.useState(false);\n React.useEffect(() => {\n if (!enabled) return;\n const q = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const sync = () => setPlay(!q.matches);\n sync();\n q.addEventListener(\"change\", sync);\n return () => q.removeEventListener(\"change\", sync);\n }, [enabled]);\n return play;\n}\n\n/** A shop's first screen: the cover, the name, the promise, the facts and the main action. */\nexport function CoverHero({ cover, eyebrow, title, lead, facts, actions, back, linkAs, className, ...props }: CoverHeroProps) {\n const play = usePlayLoop(Boolean(cover?.video));\n return (\n <header data-cover={cover ? \"\" : undefined} className={s.root({ className })} {...props}>\n {cover ? (\n <>\n <img src={cover.src} alt={cover.alt ?? \"\"} className={s.media()} fetchPriority=\"high\" decoding=\"async\" />\n {play && cover.video && (\n <video className={s.media()} poster={cover.src} autoPlay muted loop playsInline preload=\"metadata\" aria-hidden tabIndex={-1}>\n {cover.video.webm && <source src={cover.video.webm} type=\"video/webm\" />}\n {cover.video.mp4 && <source src={cover.video.mp4} type=\"video/mp4\" />}\n </video>\n )}\n <div aria-hidden className={s.veil()} />\n </>\n ) : (\n <div aria-hidden className={s.plain()} />\n )}\n <Page>\n <div className={s.body()}>\n {back && (\n <BlockLink href={back.href} linkAs={linkAs} className={s.back()}>\n <ArrowGlyph direction=\"left\" className=\"h-3.5 w-3.5\" /> {back.label}\n </BlockLink>\n )}\n {eyebrow && <p className={s.eyebrow()}>{eyebrow}</p>}\n <h1 className={s.title()}>{title}</h1>\n {lead && <p className={s.lead()}>{lead}</p>}\n {facts && <div className={s.facts()}>{facts}</div>}\n {actions && <div className={s.actions()}>{actions}</div>}\n </div>\n </Page>\n </header>\n );\n}\n","// Server-safe. The frame of every page (blocks.css): one width, one pair of gutters, one vertical rhythm — so the\n// navigation, the hero and every section line up on the same edges, at any width.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { SectionBackdrop, type SectionBackdropProps } from \"../section-backdrop/section-backdrop\";\n\nexport type PageSize = \"narrow\" | \"default\" | \"wide\" | \"full\";\n\nexport type PageProps = React.HTMLAttributes<HTMLElement> & {\n /**\n * The width of the content: `default` (72rem, `--kz-page-max`), `narrow` (48rem, a reading column), `wide`\n * (88rem, documentation with a sidebar), `full` (the gutters only).\n * @default \"default\"\n */\n size?: PageSize;\n /** The element: `div` (default), `main`, `header`, `footer`, `section` or `article`. */\n as?: \"div\" | \"main\" | \"header\" | \"footer\" | \"section\" | \"article\";\n};\n\n/** The page frame: centred, at most `--kz-page-max` wide, with the gutters of `--kz-page-gutter` (16 → 32 px). */\nexport function Page({ size = \"default\", as: Tag = \"div\", className, ...props }: PageProps) {\n return <Tag data-size={size === \"default\" ? undefined : size} className={cn(\"kz-frame\", className)} {...props} />;\n}\n\nexport type SectionHeadingProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> & {\n /** The id of the title: the section's anchor and its accessible name. */\n id?: string;\n /** A short mono line above the title (the section's subject). */\n eyebrow?: React.ReactNode;\n /** The title. */\n title: React.ReactNode;\n /** One or two sentences under the title. */\n lead?: React.ReactNode;\n /** Actions on the right of the heading (a link to everything, a filter). */\n actions?: React.ReactNode;\n /**\n * The level of the title.\n * @default 2\n */\n level?: 2 | 3;\n /**\n * `md` for a section that argues, `sm` for a section of a reading page.\n * @default \"md\"\n */\n size?: \"sm\" | \"md\";\n /**\n * `center` for a heading that stands alone above a grid.\n * @default \"start\"\n */\n align?: \"start\" | \"center\";\n /** Rises into place once, as it enters the viewport (`[data-reveal]`, MotionObserver). Never on the first screen. */\n reveal?: boolean;\n};\n\n/** The head of a section: eyebrow (mono, the accent), title, lead — and its actions on the right. */\nexport function SectionHeading({ id, eyebrow, title, lead, actions, level = 2, size = \"md\", align = \"start\", reveal, className, ...props }: SectionHeadingProps) {\n const H = level === 2 ? \"h2\" : \"h3\";\n return (\n <div\n className={cn(\"kz-heading\", className)}\n data-size={size === \"md\" ? undefined : size}\n data-align={align === \"start\" ? undefined : align}\n data-actions={actions ? \"\" : undefined}\n data-reveal={reveal ? \"\" : undefined}\n {...props}\n >\n {eyebrow && <p className=\"kz-eyebrow\">{eyebrow}</p>}\n <H id={id} className=\"kz-heading-title\">\n {title}\n </H>\n {lead && <p className=\"kz-heading-lead\">{lead}</p>}\n {actions && <div className=\"kz-heading-actions\">{actions}</div>}\n </div>\n );\n}\n\nexport type SectionProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The id of the title (and the anchor of the section). Required with a `title`. */\n id?: string;\n /** The heading's eyebrow. */\n eyebrow?: React.ReactNode;\n /** The section's title: an `h2` (a `SectionHeading`), which names the section for assistive technology. */\n title?: React.ReactNode;\n /** The heading's lead. */\n lead?: React.ReactNode;\n /** The heading's actions. */\n actions?: React.ReactNode;\n /**\n * The heading's size: `md` for a page that argues, `sm` for a reading page.\n * @default \"md\"\n */\n headingSize?: \"sm\" | \"md\";\n /**\n * The heading's alignment.\n * @default \"start\"\n */\n headingAlign?: \"start\" | \"center\";\n /** The heading rises into place once (never on the first screen). */\n reveal?: boolean;\n /** A hairline above the section, inside the gutters: the transition between two sections of the same surface. */\n divider?: boolean;\n /**\n * The vertical space above and below: `sm` (a reading page), `md`, `lg` (a page's main moments).\n * @default \"md\"\n */\n spacing?: \"sm\" | \"md\" | \"lg\";\n /**\n * The width of the content.\n * @default \"default\"\n */\n size?: PageSize;\n /** The brand's colour transition behind the section (SectionBackdrop): `true`, or its props (`direction`, `grid`…). */\n backdrop?: boolean | Omit<SectionBackdropProps, \"as\" | \"children\">;\n};\n\n/**\n * A section of a page: full-bleed (its backdrop reaches the edges), its content in the page frame, its heading on top.\n * Sections follow each other on one rhythm; a `divider` or a `backdrop` marks the transition.\n */\nexport function Section({\n id,\n eyebrow,\n title,\n lead,\n actions,\n headingSize,\n headingAlign,\n reveal,\n divider,\n spacing = \"md\",\n size,\n backdrop,\n className,\n children,\n ...props\n}: SectionProps) {\n const body = (\n <Page size={size}>\n {title && <SectionHeading id={id} eyebrow={eyebrow} title={title} lead={lead} actions={actions} size={headingSize} align={headingAlign} reveal={reveal} />}\n {children}\n </Page>\n );\n const shared = {\n \"aria-labelledby\": title && id ? id : undefined,\n \"data-divider\": divider ? \"\" : undefined,\n \"data-spacing\": spacing === \"md\" ? undefined : spacing,\n ...props,\n };\n if (backdrop) {\n const backdropProps = backdrop === true ? {} : backdrop;\n return (\n <SectionBackdrop {...backdropProps} {...shared} className={cn(\"kz-section\", className)}>\n {body}\n </SectionBackdrop>\n );\n }\n return (\n <section {...shared} className={cn(\"kz-section\", className)}>\n {body}\n </section>\n );\n}\n\nexport type TicksProps = {\n /** A sentence where words between backticks are code: \"Every request carries a `requestId`.\" */\n children: string;\n};\n\n/** A sentence of a message catalogue where words between backticks read as code — no markup in the translations. */\nexport function Ticks({ children }: TicksProps) {\n const parts = children.split(\"`\");\n return (\n <>\n {parts.map((part, i) =>\n i % 2 ? (\n <code key={i} className=\"kz-ic\">\n {part}\n </code>\n ) : (\n <React.Fragment key={i}>{part}</React.Fragment>\n ),\n )}\n </>\n );\n}\n\nexport interface Fact {\n /** A few words: `npm 2.5.0`, `Maven Central`, `in progress`. */\n label: string;\n /**\n * `ok` — published, usable today; `wip` — in progress, said honestly; `neutral` — a fact.\n * @default \"neutral\"\n */\n tone?: \"ok\" | \"wip\" | \"neutral\";\n /** Where the fact is proven (a registry page): the fact becomes a link. */\n href?: string;\n}\n\nexport type FactsProps = React.HTMLAttributes<HTMLUListElement> & {\n /** The facts, in reading order. */\n items: readonly Fact[];\n};\n\n/** Compact facts on one line — a dot that says the state, a few mono words. Links open in a new tab. */\nexport function Facts({ items, className, ...props }: FactsProps) {\n return (\n <ul className={cn(\"kz-facts\", className)} {...props}>\n {items.map((fact) => {\n const body = (\n <>\n <span className=\"kz-fact-dot\" aria-hidden /> {fact.label}\n </>\n );\n const tone = fact.tone && fact.tone !== \"neutral\" ? fact.tone : undefined;\n return (\n <li key={fact.label}>\n {fact.href ? (\n <a href={fact.href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"kz-fact\" data-tone={tone}>\n {body}\n </a>\n ) : (\n <span className=\"kz-fact\" data-tone={tone}>\n {body}\n </span>\n )}\n </li>\n );\n })}\n </ul>\n );\n}\n"],"mappings":"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","names":["React","Fragment","Fragment","jsx","jsxs"]}
@@ -9,12 +9,12 @@ import {
9
9
  dataTableCsv,
10
10
  dataTableLabels,
11
11
  useDataTable
12
- } from "./chunk-F7FVPPBB.js";
12
+ } from "./chunk-LYOPPBMC.js";
13
13
  import "./chunk-7Z4KHPFC.js";
14
14
  import "./chunk-JXLDUDTD.js";
15
15
  import "./chunk-DZU6RMYD.js";
16
16
  import "./chunk-KVDB4GXV.js";
17
- import "./chunk-CEJDH6SA.js";
17
+ import "./chunk-2PNLHZLT.js";
18
18
  import "./chunk-7UCPGXKN.js";
19
19
  import "./chunk-D3T54RSL.js";
20
20
  import "./chunk-J3NC6ER4.js";
package/dist/docs-nav.js CHANGED
@@ -1,19 +1,6 @@
1
- // src/cn.ts
2
- import { clsx } from "clsx";
3
- import { cnMerge } from "tailwind-variants";
4
- var twMergeConfig = {
5
- extend: {
6
- classGroups: {
7
- "bg-image": ["bg-sheen", "bg-fill-shade", "bg-halo"],
8
- shadow: ["shadow-raised", "shadow-floating", "shadow-overlay", "shadow-glow", "shadow-glow-lg"],
9
- "inset-shadow": ["inset-shadow-edge", "inset-shadow-edge-fill", "inset-shadow-well"]
10
- }
11
- }
12
- };
13
- var mergeConfig = { twMergeConfig };
14
- function cn(...inputs) {
15
- return cnMerge(clsx(inputs))(mergeConfig) ?? "";
16
- }
1
+ import {
2
+ cn
3
+ } from "./chunk-KH3JOEPY.js";
17
4
 
18
5
  // src/docs-nav/docs-nav.tsx
19
6
  import { jsx, jsxs } from "react/jsx-runtime";