@krizaka/ui 3.24.0 → 3.26.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 (236) hide show
  1. package/README.md +9 -1
  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-3S4GHSPZ.js +109 -0
  12. package/dist/chunk-3S4GHSPZ.js.map +1 -0
  13. package/dist/{chunk-FTX66XZY.js → chunk-BCGJZ5PG.js} +3 -3
  14. package/dist/{chunk-FTX66XZY.js.map → chunk-BCGJZ5PG.js.map} +1 -1
  15. package/dist/chunk-C7LTF5CC.js +21 -0
  16. package/dist/chunk-C7LTF5CC.js.map +1 -0
  17. package/dist/{chunk-F7FVPPBB.js → chunk-LYOPPBMC.js} +2 -2
  18. package/dist/{chunk-AFY35UCB.js → chunk-P7GZR5CU.js} +3 -1
  19. package/dist/{chunk-AFY35UCB.js.map → chunk-P7GZR5CU.js.map} +1 -1
  20. package/dist/code-block.js +1 -1
  21. package/dist/cover-hero.d.ts +125 -0
  22. package/dist/cover-hero.js +82 -0
  23. package/dist/cover-hero.js.map +1 -0
  24. package/dist/data-table.js +2 -2
  25. package/dist/docs-nav.js +3 -16
  26. package/dist/docs-nav.js.map +1 -1
  27. package/dist/dropdown-menu.d.ts +12 -1
  28. package/dist/dropdown-menu.js +25 -2
  29. package/dist/dropdown-menu.js.map +1 -1
  30. package/dist/filter-bar.js +1 -1
  31. package/dist/genui.js +2 -2
  32. package/dist/language-switch.d.ts +120 -0
  33. package/dist/language-switch.js +32 -0
  34. package/dist/language-switch.js.map +1 -0
  35. package/dist/media-gallery.d.ts +73 -0
  36. package/dist/media-gallery.js +42 -0
  37. package/dist/media-gallery.js.map +1 -0
  38. package/dist/nav-bar.d.ts +40 -2
  39. package/dist/nav-bar.js +68 -12
  40. package/dist/nav-bar.js.map +1 -1
  41. package/dist/opening-hours.d.ts +124 -0
  42. package/dist/opening-hours.js +48 -0
  43. package/dist/opening-hours.js.map +1 -0
  44. package/dist/rail-nav.js +1 -1
  45. package/dist/service-card.d.ts +168 -0
  46. package/dist/service-card.js +112 -0
  47. package/dist/service-card.js.map +1 -0
  48. package/dist/site-footer.js +1 -1
  49. package/dist/sites.js +2 -2
  50. package/dist/sites.js.map +1 -1
  51. package/dist/slot-picker.d.ts +119 -0
  52. package/dist/slot-picker.js +46 -0
  53. package/dist/slot-picker.js.map +1 -0
  54. package/dist/sticky-action.d.ts +12 -0
  55. package/dist/sticky-action.js +14 -0
  56. package/dist/sticky-action.js.map +1 -0
  57. package/package.json +121 -7
  58. package/registry/account-menu.json +280 -0
  59. package/registry/achievement.json +1 -1
  60. package/registry/action-bar.json +1 -1
  61. package/registry/activity-feed.json +3 -3
  62. package/registry/alert.json +1 -1
  63. package/registry/app-header.json +1 -1
  64. package/registry/app-shell.json +1 -1
  65. package/registry/argument-card.json +1 -1
  66. package/registry/audio-player.json +1 -1
  67. package/registry/auth-layout.json +1 -1
  68. package/registry/avatar.json +1 -1
  69. package/registry/badge.json +1 -1
  70. package/registry/button.json +1 -1
  71. package/registry/captcha.json +1 -1
  72. package/registry/card-grid.json +1 -1
  73. package/registry/card.json +3 -3
  74. package/registry/catalogue-page.json +1 -1
  75. package/registry/changelog-page.json +3 -3
  76. package/registry/chat.json +1 -1
  77. package/registry/checkbox.json +1 -1
  78. package/registry/chip-link.json +1 -1
  79. package/registry/chip.json +1 -1
  80. package/registry/choice-grid.json +1 -1
  81. package/registry/code-block.json +1 -1
  82. package/registry/combobox.json +1 -1
  83. package/registry/command.json +1 -1
  84. package/registry/comparison-table.json +1 -1
  85. package/registry/component-page.json +1 -1
  86. package/registry/confirm-button.json +1 -1
  87. package/registry/contact-page.json +1 -1
  88. package/registry/continue-prompt.json +1 -1
  89. package/registry/countdown.json +1 -1
  90. package/registry/cover-hero.json +246 -0
  91. package/registry/cta-panel.json +1 -1
  92. package/registry/dashboard-layout.json +1 -1
  93. package/registry/data-table.json +1 -1
  94. package/registry/date-picker.json +1 -1
  95. package/registry/decision-list.json +1 -1
  96. package/registry/description-list.json +1 -1
  97. package/registry/detail-layout.json +1 -1
  98. package/registry/dialog.json +1 -1
  99. package/registry/docs-article-page.json +1 -1
  100. package/registry/docs-hub-page.json +1 -1
  101. package/registry/docs-layout.json +1 -1
  102. package/registry/docs-nav.json +1 -1
  103. package/registry/document-viewer.json +1 -1
  104. package/registry/dropdown-menu.json +33 -3
  105. package/registry/empty-state.json +1 -1
  106. package/registry/error-page.json +1 -1
  107. package/registry/examples/account-menu/default.d.ts +4 -0
  108. package/registry/examples/account-menu/default.js +28 -0
  109. package/registry/examples/account-menu/default.tsx +22 -0
  110. package/registry/examples/cover-hero/plain.d.ts +4 -0
  111. package/registry/examples/cover-hero/plain.js +12 -0
  112. package/registry/examples/cover-hero/plain.tsx +7 -0
  113. package/registry/examples/cover-hero/shop.d.ts +4 -0
  114. package/registry/examples/cover-hero/shop.js +27 -0
  115. package/registry/examples/cover-hero/shop.tsx +20 -0
  116. package/registry/examples/language-switch/inline.d.ts +4 -0
  117. package/registry/examples/language-switch/inline.js +11 -0
  118. package/registry/examples/language-switch/inline.tsx +6 -0
  119. package/registry/examples/language-switch/menu.d.ts +4 -0
  120. package/registry/examples/language-switch/menu.js +11 -0
  121. package/registry/examples/language-switch/menu.tsx +6 -0
  122. package/registry/examples/media-gallery/shop.d.ts +4 -0
  123. package/registry/examples/media-gallery/shop.js +22 -0
  124. package/registry/examples/media-gallery/shop.tsx +18 -0
  125. package/registry/examples/nav-bar/family-product.js +18 -10
  126. package/registry/examples/nav-bar/family-product.tsx +28 -27
  127. package/registry/examples/opening-hours/week.d.ts +4 -0
  128. package/registry/examples/opening-hours/week.js +28 -0
  129. package/registry/examples/opening-hours/week.tsx +22 -0
  130. package/registry/examples/service-card/services.d.ts +4 -0
  131. package/registry/examples/service-card/services.js +15 -0
  132. package/registry/examples/service-card/services.tsx +12 -0
  133. package/registry/examples/slot-picker/times.d.ts +4 -0
  134. package/registry/examples/slot-picker/times.js +27 -0
  135. package/registry/examples/slot-picker/times.tsx +23 -0
  136. package/registry/examples/sticky-action/phone.d.ts +4 -0
  137. package/registry/examples/sticky-action/phone.js +15 -0
  138. package/registry/examples/sticky-action/phone.tsx +14 -0
  139. package/registry/field.json +1 -1
  140. package/registry/file-upload.json +1 -1
  141. package/registry/filter-bar.json +1 -1
  142. package/registry/force-update-screen.json +1 -1
  143. package/registry/form.json +3 -3
  144. package/registry/gallery-page.json +1 -1
  145. package/registry/genui.json +1 -1
  146. package/registry/glow-card.json +1 -1
  147. package/registry/goal-gauge.json +1 -1
  148. package/registry/how-it-works-page.json +1 -1
  149. package/registry/image-cropper.json +1 -1
  150. package/registry/index.json +258 -5
  151. package/registry/iso.json +1 -1
  152. package/registry/kanban.json +1 -1
  153. package/registry/kbd.json +1 -1
  154. package/registry/landing-page.json +1 -1
  155. package/registry/landscape.json +1 -1
  156. package/registry/language-switch.json +246 -0
  157. package/registry/legal-page.json +1 -1
  158. package/registry/link-card.json +3 -3
  159. package/registry/list.json +1 -1
  160. package/registry/loader.json +1 -1
  161. package/registry/longform-page.json +1 -1
  162. package/registry/maintenance-screen.json +1 -1
  163. package/registry/map.json +2 -2
  164. package/registry/markdown.json +1 -1
  165. package/registry/marketing-layout.json +1 -1
  166. package/registry/marquee.json +1 -1
  167. package/registry/mascot-quote.json +1 -1
  168. package/registry/mascot-state.json +1 -1
  169. package/registry/mascots.json +1 -1
  170. package/registry/match-dialog.json +1 -1
  171. package/registry/media-capture.json +3 -3
  172. package/registry/media-gallery.json +144 -0
  173. package/registry/media-grid.json +3 -3
  174. package/registry/meta-row.json +1 -1
  175. package/registry/meter.json +1 -1
  176. package/registry/nav-bar.json +138 -8
  177. package/registry/number-ticker.json +1 -1
  178. package/registry/opening-hours.json +178 -0
  179. package/registry/page-header.json +1 -1
  180. package/registry/page-hero.json +3 -3
  181. package/registry/page.json +7 -7
  182. package/registry/pagination.json +1 -1
  183. package/registry/photo-grid.json +1 -1
  184. package/registry/pointer-light.json +1 -1
  185. package/registry/popover.json +1 -1
  186. package/registry/pricing-page.json +1 -1
  187. package/registry/product-page.json +1 -1
  188. package/registry/profile-card.json +1 -1
  189. package/registry/progress.json +1 -1
  190. package/registry/promise-card.json +1 -1
  191. package/registry/radio-group.json +1 -1
  192. package/registry/rail-nav.json +2 -2
  193. package/registry/recipes.json +1 -1
  194. package/registry/scroll-stage.json +1 -1
  195. package/registry/search-field.json +1 -1
  196. package/registry/section-backdrop.json +1 -1
  197. package/registry/separator.json +1 -1
  198. package/registry/service-card.json +358 -0
  199. package/registry/settings-layout.json +1 -1
  200. package/registry/showcase.json +1 -1
  201. package/registry/site-footer.json +2 -2
  202. package/registry/sites.json +2 -2
  203. package/registry/skeleton.json +3 -3
  204. package/registry/skip-link.json +1 -1
  205. package/registry/slider.json +1 -1
  206. package/registry/slot-picker.json +222 -0
  207. package/registry/slot.json +1 -1
  208. package/registry/spinner.json +1 -1
  209. package/registry/split-view.json +1 -1
  210. package/registry/stage-banner.json +1 -1
  211. package/registry/stat.json +1 -1
  212. package/registry/status-page.json +1 -1
  213. package/registry/step-progress.json +1 -1
  214. package/registry/step-showcase.json +1 -1
  215. package/registry/stepper.json +1 -1
  216. package/registry/sticky-action.json +108 -0
  217. package/registry/swipe-deck.json +1 -1
  218. package/registry/switch.json +1 -1
  219. package/registry/tabs.json +1 -1
  220. package/registry/tag-input.json +1 -1
  221. package/registry/tag-selector.json +1 -1
  222. package/registry/terminal-replay.json +1 -1
  223. package/registry/theme.json +1 -1
  224. package/registry/toast.json +1 -1
  225. package/registry/toc.json +1 -1
  226. package/registry/tooltip.json +1 -1
  227. package/registry/tree-view.json +1 -1
  228. package/registry/update-prompt.json +1 -1
  229. package/registry/verified-badge.json +1 -1
  230. package/registry/vertical-video.json +5 -5
  231. package/registry/video-player.json +3 -3
  232. package/registry/video-trimmer.json +1 -1
  233. package/registry/virtual.json +1 -1
  234. package/registry/waveform.json +1 -1
  235. package/dist/chunk-CEJDH6SA.js.map +0 -1
  236. /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":";AA2BO,IAAM,cAAoC,CAAC,YAAY,YAAY,WAAW,OAAO,QAAQ;AAEpG,IAAM,UAAU;AAGT,SAAS,MAAM,IAAoB;AACxC,SAAO,GACJ,QAAQ,0BAA0B,IAAI,EACtC,QAAQ,cAAc,IAAI,EAC1B,QAAQ,oBAAoB,IAAI,EAChC,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAGO,SAAS,MAAM,MAAc,UAAgC;AAClE,MAAI,kCAAkC,KAAK,IAAI,EAAG,QAAO;AACzD,MAAI,mDAAmD,KAAK,IAAI,EAAG,QAAO;AAC1E,SAAO;AACT;AAGA,IAAM,OAAO,CAAC,GAAW,MAAM,QAAQ;AACrC,QAAM,QAAQ,wBAAwB,KAAK,CAAC,IAAI,CAAC;AACjD,MAAI,SAAS,MAAM,UAAU,IAAK,QAAO;AACzC,SAAO,EAAE,UAAU,MAAM,IAAI,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,QAAQ,WAAW,EAAE,CAAC;AACxE;AAGO,SAAS,KAAK,MAAgC;AACnD,QAAM,MAAM,QAAQ,KAAK,IAAI;AAC7B,SAAO,MAAM,EAAE,QAAQ,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,EAAE,IAAI;AACzD;AAEA,IAAM,gBAA2C,EAAE,OAAO,YAAY,OAAO,WAAW,OAAO,MAAM;AAG9F,SAAS,gBAAgB,IAAY,QAAgB,QAA4D;AACtH,QAAM,WAAsB,CAAC;AAC7B,MAAI;AACJ,MAAI,QAAmB;AACvB,aAAW,OAAO,GAAG,MAAM,IAAI,GAAG;AAChC,UAAM,KAAK,6BAA6B,KAAK,GAAG;AAChD,QAAI,IAAI;AACN,YAAM,OAAO,OAAO,GAAG,CAAC,CAAC;AACzB,gBAAU,OAAO,EAAE,QAAQ,SAAS,GAAG,CAAC,GAAG,MAAM,SAAS,CAAC,EAAE,IAAI;AACjE,UAAI,QAAS,UAAS,KAAK,OAAO;AAClC;AAAA,IACF;AACA,UAAM,KAAK,qBAAqB,KAAK,GAAG;AACxC,QAAI,IAAI;AACN,cAAQ,cAAc,GAAG,CAAC,EAAE,YAAY,CAAC,KAAK;AAC9C;AAAA,IACF;AAEA,UAAM,SAAS,WAAW,KAAK,GAAG;AAClC,QAAI,CAAC,WAAW,CAAC,UAAU,wBAAwB,KAAK,OAAO,CAAC,CAAC,EAAG;AACpE,UAAM,OAAO,MAAM,OAAO,CAAC,EAAE,QAAQ,mEAAmE,EAAE,CAAC;AAC3G,QAAI,CAAC,KAAM;AACX,YAAQ,QAAQ,KAAK,EAAE,KAAK,MAAM,MAAM,UAAU,YAAY,YAAY,KAAK,GAAG,MAAM,KAAK,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC;AAAA,EAC3H;AACA,SAAO,SAAS,OAAO,CAAC,MAAM,EAAE,QAAQ,SAAS,CAAC;AACpD;AAEA,IAAM,eAAe;AACrB,IAAM,cAAyC,EAAE,MAAM,WAAW,KAAK,OAAO,MAAM,UAAU,UAAU,YAAY,KAAK,YAAY,QAAQ,SAAS;AAEtJ,IAAM,cAAc,oBAAI,IAAI,CAAC,YAAY,QAAQ,SAAS,MAAM,QAAQ,SAAS,SAAS,MAAM,CAAC;AAG1F,SAAS,gBAAgB,OAAe,OAAmC;AAChF,QAAM,IAAI,aAAa,KAAK,MAAM,KAAK,CAAC;AACxC,QAAM,OAAO,IAAI,CAAC,EAAE,YAAY;AAChC,MAAI,KAAK,QAAQ,YAAY,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,EAAG,QAAO;AACxD,QAAM,QAAQ,IAAI,EAAE,CAAC,IAAI,OAAO,QAAQ,mBAAmB,EAAE,EAAE,KAAK;AACpE,QAAM,WAAW,MAAM,KAAK,QAAQ,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AACjE,QAAM,MAAM,MAAM,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,IAAI,KAAK,UAAU,OAAQ,YAAY,IAAI,KAAK,WAAY,QAAQ;AAC5G,QAAM,MAAM,iBAAiB,KAAK,KAAK,IAAI,CAAC;AAC5C,QAAM,KAAK,QAAQ,KAAK,KAAK,IAAI,MAAM,EAAE,QAAQ,OAAO,GAAG,GAAG,KAAK,GAAG,IAAI;AAC1E,SAAO,EAAE,KAAK,MAAM,SAAS,QAAQ,WAAW,GAAG,GAAG,GAAG;AAC3D;AAGO,SAAS,iBAAiB,MAA4B;AAC3D,QAAM,QAAsB,CAAC;AAC7B,aAAW,OAAO,KAAK,MAAM,IAAI,GAAG;AAClC,UAAM,SAAS,iBAAiB,KAAK,GAAG;AACxC,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,OAAO,CAAC,EAAE,QAAQ,wCAAwC,KAAK;AAC5E,UAAM,KAAK,KAAK,IAAI;AACpB,UAAM,QAAQ,KAAK,QAAQ,wBAAwB,EAAE;AACrD,UAAM,OAAO,gBAAgB,MAAM,KAAK,GAAG,IAAI,GAAG;AAClD,QAAI,KAAM,OAAM,KAAK,EAAE,GAAG,MAAM,IAAI,MAAM,KAAK,IAAI,MAAM,KAAK,KAAK,IAAI,EAAE,CAAC;AAAA,EAC5E;AACA,SAAO;AACT;AAGO,SAAS,gBAAgB,QAA2B,SAAyB;AAClF,QAAM,SAAS,oBAAI,IAAyB;AAC5C,aAAW,SAAS,QAAQ;AAC1B,UAAM,OAAO,gBAAgB,KAAK;AAClC,QAAI,CAAC,KAAM;AACX,WAAO,IAAI,KAAK,KAAK,CAAC,GAAI,OAAO,IAAI,KAAK,GAAG,KAAK,CAAC,GAAI,KAAK,IAAI,SAAS,GAAG,KAAK,IAAI,MAAM,KAAK,GAAG,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,EAC3H;AACA,QAAM,QAAmC,EAAE,UAAU,YAAY,UAAU,YAAY,SAAS,OAAO,KAAK,SAAS,QAAQ,UAAU;AACvI,QAAM,MAAM,CAAC,MAAM,OAAO,EAAE;AAC5B,aAAW,OAAO,aAAa;AAC7B,UAAM,QAAQ,OAAO,IAAI,GAAG;AAC5B,QAAI,OAAO,OAAQ,KAAI,KAAK,IAAI,OAAO,MAAM,GAAG,CAAC,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AAAA,EACpF;AACA,SAAO,GAAG,IAAI,KAAK,IAAI,CAAC;AAAA;AAC1B;AAGO,SAAS,YAAY,GAAY,GAAoB;AAC1D,SAAO,EAAE,KAAK,cAAc,EAAE,IAAI,KAAK,EAAE,QAAQ,cAAc,EAAE,SAAS,QAAW,EAAE,SAAS,KAAK,CAAC;AACxG;AAGO,IAAM,WAAW,CAAC,MACvB,GAAG,EAAE,MAAM,IAAI,EAAE,OAAO,GAAG,YAAY,EAAE,QAAQ,eAAe,GAAG,EAAE,QAAQ,UAAU,EAAE;AAE3F,IAAM,MAAM,CAAC,MAAc,EAAE,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,QAAQ;AAG/G,SAAS,aAAa,MASlB;AACT,QAAM,QAAQ,KAAK,SAChB,IAAI,CAAC,MAAM;AACV,UAAM,OAAO,EAAE,QAAQ,IAAI,CAAC,MAAM,UAAU,IAAI,KAAK,SAAS,EAAE,GAAG,CAAC,CAAC,QAAQ,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE;AACxG,UAAM,OAAO,GAAG,KAAK,OAAO,IAAI,SAAS,CAAC,CAAC;AAC3C,WAAO,gBAAgB,IAAI,GAAG,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,CAAC,iBAAiB,IAAI,IAAI,CAAC,mCAAmC,IAAI,IAAI,CAAC,oBAAmB,oBAAI,KAAK,GAAG,EAAE,IAAI,YAAY,GAAE,YAAY,CAAC,0BAA0B,IAAI,OAAO,IAAI,OAAO,CAAC;AAAA,EAC/O,CAAC,EACA,KAAK,EAAE;AACV,SAAO,qHAAqH,IAAI,KAAK,KAAK,CAAC,iBAAiB,IAAI,KAAK,OAAO,CAAC,uBAAuB,IAAI,KAAK,WAAW,CAAC,2BAA2B,KAAK,QAAQ,+BAA+B,IAAI,KAAK,OAAO,CAAC,4CAA4C,KAAK;AACpW;AAGO,IAAM,YAAY,CAAC,QACxB,QAAQ,YAAY,UAAU,QAAQ,QAAQ,UAAU,QAAQ,WAAW,YAAY;;;AC5KzF,SAAS,YAAY;AAErB,SAAS,gBAAgB;AA+CnB,cAOQ,YAPR;AAHC,SAAS,cAAc,EAAE,MAAM,SAAS,OAAO,MAAM,SAAS,YAAY,UAAU,SAAS,QAAQ,GAAG,MAAM,GAAuB;AAC1I,SACE,qBAAC,SAAK,GAAG,OACP;AAAA,wBAAC,YAAS,MAAY,QAAgB,SAAkB,OAAc,MAAY,UAAS,SACxF,mBACH;AAAA,IACA,oBAAC,QAAK,WAAU,mBACd,8BAAC,QAAG,WAAU,cAAa,cAAY,UACpC,kBAAQ,IAAI,CAAC,MACZ,qBAAC,QAAc,IAAI,EAAE,IAAI,WAAU,oBACjC;AAAA,2BAAC,SAAI,WAAU,mBACb;AAAA,4BAAC,UAAK,UAAU,EAAE,MAAO,YAAE,WAAU;AAAA,QACpC,EAAE,WAAW,oBAAC,UAAK,WAAU,WAAW,YAAE,SAAQ;AAAA,SACrD;AAAA,MACA,qBAAC,SACC;AAAA,4BAAC,QAAI,YAAE,OAAM;AAAA,QACb,oBAAC,QAAG,WAAU,oBACX,YAAE,QAAQ,IAAI,CAAC,GAAG,MACjB,qBAAC,QACC;AAAA,8BAAC,UAAK,WAAU,mBAAkB,aAAW,EAAE,MAC5C,qBAAW,EAAE,IAAI,GACpB;AAAA,UACA,oBAAC,UAAM,YAAE,MAAK;AAAA,aAJP,CAKT,CACD,GACH;AAAA,QACC,EAAE;AAAA,SACL;AAAA,SAlBO,EAAE,EAmBX,CACD,GACH,GACF;AAAA,KACF;AAEJ;","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,109 @@
1
+ "use client";
2
+
3
+ // src/language-switch/language-switch.tsx
4
+ import * as React from "react";
5
+ import { tv } from "tailwind-variants";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ var languageSwitch = tv({
8
+ slots: {
9
+ root: "relative inline-flex",
10
+ trigger: "group/language inline-flex h-9 shrink-0 select-none items-center gap-1.5 rounded-full px-2.5 font-mono text-xs font-semibold uppercase tracking-wide text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg aria-expanded:bg-surface-3 aria-expanded:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
11
+ glyph: "h-4 w-4 shrink-0",
12
+ panel: "kz-pop absolute right-0 top-full z-50 mt-2 grid min-w-44 max-w-[calc(100vw-2rem)] gap-0.5 rounded-xl border border-border-default bg-surface-1 p-1.5 shadow-lg",
13
+ heading: "px-2.5 pb-1 pt-1.5 text-[11px] font-semibold uppercase tracking-wider text-fg-secondary",
14
+ item: "flex min-h-9 items-center justify-between gap-6 rounded-lg px-2.5 py-2 text-sm font-medium text-fg no-underline outline-hidden transition-colors hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring aria-[current=true]:bg-accent-soft",
15
+ check: "h-4 w-4 shrink-0 text-fg-accent",
16
+ inline: "inline-flex items-center gap-1 rounded-full border border-border-subtle bg-surface-2/60 p-0.5",
17
+ inlineLink: "inline-flex min-h-9 items-center rounded-full px-3 text-sm font-medium text-fg-secondary no-underline transition-colors hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=true]:bg-surface-3 aria-[current=true]:text-fg"
18
+ }
19
+ });
20
+ var s = languageSwitch();
21
+ var Globe = ({ className }) => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", className, fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
22
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "9" }),
23
+ /* @__PURE__ */ jsx("path", { d: "M3 12h18M12 3c2.5 2.6 3.8 5.6 3.8 9S14.5 18.4 12 21c-2.5-2.6-3.8-5.6-3.8-9S9.5 5.6 12 3Z" })
24
+ ] });
25
+ function LanguageSwitch({ label, current, languages, variant = "menu", linkAs, defaultOpen = false, className }) {
26
+ const Link = linkAs ?? "a";
27
+ const id = React.useId();
28
+ const [open, setOpen] = React.useState(defaultOpen);
29
+ const root = React.useRef(null);
30
+ const trigger = React.useRef(null);
31
+ const active = languages.find((l) => l.code === current);
32
+ React.useEffect(() => {
33
+ if (!open) return;
34
+ const onPress = (e) => {
35
+ if (e.target instanceof Node && !root.current?.contains(e.target)) setOpen(false);
36
+ };
37
+ document.addEventListener("pointerdown", onPress);
38
+ return () => document.removeEventListener("pointerdown", onPress);
39
+ }, [open]);
40
+ if (variant === "inline") {
41
+ return /* @__PURE__ */ jsx("div", { role: "group", "aria-label": label, className: s.inline({ className }), children: languages.map((l) => /* @__PURE__ */ jsx(Link, { href: l.href, hrefLang: l.code, lang: l.code, "aria-current": l.code === current ? "true" : void 0, className: s.inlineLink(), children: l.name }, l.code)) });
42
+ }
43
+ const links = () => [...root.current?.querySelectorAll("[data-language]") ?? []];
44
+ const close = (focus) => {
45
+ setOpen(false);
46
+ if (focus) trigger.current?.focus();
47
+ };
48
+ return /* @__PURE__ */ jsxs(
49
+ "div",
50
+ {
51
+ ref: root,
52
+ className: s.root({ className }),
53
+ onKeyDown: (e) => {
54
+ if (e.key === "Escape" && open) {
55
+ e.stopPropagation();
56
+ close(true);
57
+ }
58
+ if (open && (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Home" || e.key === "End")) {
59
+ e.preventDefault();
60
+ const all = links();
61
+ const at = all.indexOf(document.activeElement);
62
+ const next = e.key === "Home" ? 0 : e.key === "End" ? all.length - 1 : (at + (e.key === "ArrowDown" ? 1 : -1) + all.length) % all.length;
63
+ all[next]?.focus();
64
+ }
65
+ },
66
+ onBlur: (e) => {
67
+ if (open && !root.current?.contains(e.relatedTarget)) setOpen(false);
68
+ },
69
+ children: [
70
+ /* @__PURE__ */ jsxs(
71
+ "button",
72
+ {
73
+ ref: trigger,
74
+ type: "button",
75
+ "aria-label": active ? `${label}: ${active.name}` : label,
76
+ "aria-expanded": open,
77
+ "aria-controls": id,
78
+ onClick: () => setOpen(!open),
79
+ onKeyDown: (e) => {
80
+ if (e.key === "ArrowDown") {
81
+ e.preventDefault();
82
+ setOpen(true);
83
+ requestAnimationFrame(() => (links().find((l) => l.getAttribute("aria-current") === "true") ?? links()[0])?.focus());
84
+ }
85
+ },
86
+ className: s.trigger(),
87
+ children: [
88
+ /* @__PURE__ */ jsx(Globe, { className: s.glyph() }),
89
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, "data-code": current, className: "after:content-[attr(data-code)]" })
90
+ ]
91
+ }
92
+ ),
93
+ open && /* @__PURE__ */ jsxs("div", { id, role: "group", "aria-label": label, className: s.panel(), children: [
94
+ /* @__PURE__ */ jsx("p", { "aria-hidden": true, className: s.heading(), children: label }),
95
+ languages.map((l) => /* @__PURE__ */ jsxs(Link, { "data-language": "", href: l.href, hrefLang: l.code, lang: l.code, "aria-current": l.code === current ? "true" : void 0, className: s.item(), children: [
96
+ l.name,
97
+ l.code === current && /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: s.check(), 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" }) })
98
+ ] }, l.code))
99
+ ] })
100
+ ]
101
+ }
102
+ );
103
+ }
104
+
105
+ export {
106
+ languageSwitch,
107
+ LanguageSwitch
108
+ };
109
+ //# sourceMappingURL=chunk-3S4GHSPZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/language-switch/language-switch.tsx"],"sourcesContent":["// Client (a disclosure). The one language switch of the family: a globe and the current code (FR), opening a short list of\n// the languages by their own names — links with `hreflang` that keep the page. A disclosure, not a Radix menu: the items\n// are navigation, and the bar must not pay for a menu engine (Escape, outside press, focus-out and the arrows are here).\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport type { Language } from \"./href\";\n\nexport const languageSwitch = tv({\n slots: {\n root: \"relative inline-flex\",\n trigger:\n \"group/language inline-flex h-9 shrink-0 select-none items-center gap-1.5 rounded-full px-2.5 font-mono text-xs font-semibold uppercase tracking-wide text-fg-secondary transition-colors \" +\n \"hover:bg-surface-3 hover:text-fg aria-expanded:bg-surface-3 aria-expanded:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n glyph: \"h-4 w-4 shrink-0\",\n panel:\n \"kz-pop absolute right-0 top-full z-50 mt-2 grid min-w-44 max-w-[calc(100vw-2rem)] gap-0.5 rounded-xl border border-border-default bg-surface-1 p-1.5 shadow-lg\",\n heading: \"px-2.5 pb-1 pt-1.5 text-[11px] font-semibold uppercase tracking-wider text-fg-secondary\",\n item:\n \"flex min-h-9 items-center justify-between gap-6 rounded-lg px-2.5 py-2 text-sm font-medium text-fg no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring aria-[current=true]:bg-accent-soft\",\n check: \"h-4 w-4 shrink-0 text-fg-accent\",\n inline: \"inline-flex items-center gap-1 rounded-full border border-border-subtle bg-surface-2/60 p-0.5\",\n inlineLink:\n \"inline-flex min-h-9 items-center rounded-full px-3 text-sm font-medium text-fg-secondary no-underline transition-colors hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=true]:bg-surface-3 aria-[current=true]:text-fg\",\n },\n});\nconst s = languageSwitch();\n\nexport type LanguageSwitchProps = {\n /** The control's accessible name (“Language”, “Langue”) — passed translated. */\n label: string;\n /** The code of the page's language (`fr`). */\n current: string;\n /** The languages offered, each with its name in its own language and the address of the same page (`languagesFor`). */\n languages: readonly Language[];\n /**\n * `menu`: a globe and the code, opening a menu (the bar). `inline`: every language in a row (a mobile panel, a settings page).\n * @default \"menu\"\n */\n variant?: \"menu\" | \"inline\";\n /** Your router's `<Link>` (it receives `href`, `hrefLang`, `lang`). A plain `<a>` otherwise. */\n linkAs?: React.ElementType;\n /** Opens the menu at first render (a story, a screenshot). */\n defaultOpen?: boolean;\n /** Classes of the control. */\n className?: string;\n};\n\nconst Globe = ({ className }: { className?: string }) => (\n <svg viewBox=\"0 0 24 24\" className={className} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M3 12h18M12 3c2.5 2.6 3.8 5.6 3.8 9S14.5 18.4 12 21c-2.5-2.6-3.8-5.6-3.8-9S9.5 5.6 12 3Z\" />\n </svg>\n);\n\n/**\n * The language switch, the same on every Krizaka site and app: a compact control — a globe and the current code\n * (`FR`) — that opens a menu of the languages named in their own language (Français · English), each a link with\n * `hreflang` to the same page. It shows the language you are in, never the “other” one. `variant=\"inline\"` lays the\n * languages in a row for a phone's panel or a settings page.\n */\nexport function LanguageSwitch({ label, current, languages, variant = \"menu\", linkAs, defaultOpen = false, className }: LanguageSwitchProps) {\n const Link = linkAs ?? \"a\";\n const id = React.useId();\n const [open, setOpen] = React.useState(defaultOpen);\n const root = React.useRef<HTMLDivElement>(null);\n const trigger = React.useRef<HTMLButtonElement>(null);\n const active = languages.find((l) => l.code === current);\n\n React.useEffect(() => {\n if (!open) return;\n // A press outside closes it (the page under it stays usable).\n const onPress = (e: PointerEvent) => {\n if (e.target instanceof Node && !root.current?.contains(e.target)) setOpen(false);\n };\n document.addEventListener(\"pointerdown\", onPress);\n return () => document.removeEventListener(\"pointerdown\", onPress);\n }, [open]);\n\n if (variant === \"inline\") {\n return (\n <div role=\"group\" aria-label={label} className={s.inline({ className })}>\n {languages.map((l) => (\n <Link key={l.code} href={l.href} hrefLang={l.code} lang={l.code} aria-current={l.code === current ? \"true\" : undefined} className={s.inlineLink()}>\n {l.name}\n </Link>\n ))}\n </div>\n );\n }\n\n const links = () => [...(root.current?.querySelectorAll<HTMLElement>(\"[data-language]\") ?? [])];\n const close = (focus: boolean) => {\n setOpen(false);\n if (focus) trigger.current?.focus();\n };\n return (\n <div\n ref={root}\n className={s.root({ className })}\n onKeyDown={(e) => {\n if (e.key === \"Escape\" && open) {\n e.stopPropagation();\n close(true);\n }\n if (open && (e.key === \"ArrowDown\" || e.key === \"ArrowUp\" || e.key === \"Home\" || e.key === \"End\")) {\n e.preventDefault();\n const all = links();\n const at = all.indexOf(document.activeElement as HTMLElement);\n const next = e.key === \"Home\" ? 0 : e.key === \"End\" ? all.length - 1 : (at + (e.key === \"ArrowDown\" ? 1 : -1) + all.length) % all.length;\n all[next]?.focus();\n }\n }}\n // Tab out of the switch closes it.\n onBlur={(e) => {\n if (open && !root.current?.contains(e.relatedTarget as Node | null)) setOpen(false);\n }}\n >\n <button\n ref={trigger}\n type=\"button\"\n aria-label={active ? `${label}: ${active.name}` : label}\n aria-expanded={open}\n aria-controls={id}\n onClick={() => setOpen(!open)}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setOpen(true);\n requestAnimationFrame(() => (links().find((l) => l.getAttribute(\"aria-current\") === \"true\") ?? links()[0])?.focus());\n }\n }}\n className={s.trigger()}\n >\n <Globe className={s.glyph()} />\n {/* Drawn by CSS: the code is no text of the button, so its name (`Language: English`) never mismatches what is visible. */}\n <span aria-hidden data-code={current} className=\"after:content-[attr(data-code)]\" />\n </button>\n {open && (\n <div id={id} role=\"group\" aria-label={label} className={s.panel()}>\n <p aria-hidden className={s.heading()}>\n {label}\n </p>\n {languages.map((l) => (\n <Link key={l.code} data-language=\"\" href={l.href} hrefLang={l.code} lang={l.code} aria-current={l.code === current ? \"true\" : undefined} className={s.item()}>\n {l.name}\n {l.code === current && (\n <svg viewBox=\"0 0 24 24\" className={s.check()} 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 )}\n </Link>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -50,7 +50,7 @@ var familyLabels = {
50
50
  orochia: "A video platform for creators.",
51
51
  yasakia: "The dating app where you talk first.",
52
52
  yororis: "A listening space with a face and a voice.",
53
- yomizaka: "Your documents, read and checked by Orazaka.",
53
+ yomizaka: "Yomizaka reads your leases, contracts and invoices.",
54
54
  kachizaka: "Predictions among friends \u2014 live data, in real time.",
55
55
  akinaza: "Running a shop in Qu\xE9bec, for less \u2014 Loi 25 by design.",
56
56
  ui: "Components, tokens, icons and charts \u2014 web and React Native.",
@@ -72,7 +72,7 @@ var familyLabels = {
72
72
  orochia: "Une plateforme vid\xE9o pour les cr\xE9ateurs.",
73
73
  yasakia: "L\u2019app de rencontre o\xF9 l\u2019on se parle d\u2019abord.",
74
74
  yororis: "Un espace d\u2019\xE9coute avec un visage et une voix.",
75
- yomizaka: "Vos documents, lus et v\xE9rifi\xE9s par Orazaka.",
75
+ yomizaka: "Yomizaka lit vos baux, contrats et factures.",
76
76
  kachizaka: "Les pronostics entre amis \u2014 des donn\xE9es en direct.",
77
77
  akinaza: "Tenir une boutique au Qu\xE9bec, pour moins cher \u2014 Loi 25 d\xE8s la conception.",
78
78
  ui: "Composants, jetons, ic\xF4nes et graphiques \u2014 web et React Native.",
@@ -92,4 +92,4 @@ export {
92
92
  sitesByGroup,
93
93
  familyLabels
94
94
  };
95
- //# sourceMappingURL=chunk-FTX66XZY.js.map
95
+ //# sourceMappingURL=chunk-BCGJZ5PG.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/family-mark.tsx","../src/sites/sites.ts"],"sourcesContent":["// The mark of a site of the family (`@krizaka/ui/sites`): its brand's `ProductLogo`, still (a list of marks never\n// moves), or GitHub's, in the text colour. Shared by `NavBar.Family` and `SiteFooter` — not an entry of its own.\nimport type * as React from \"react\";\n\nimport { ProductLogo } from \"./marks/ProductLogo\";\nimport type { SiteMark } from \"./sites/sites\";\n\n/** GitHub's mark, in the text colour (both themes). */\nexport function GitHubGlyph({ size = 16, className }: { size?: number; className?: string }) {\n return (\n <svg viewBox=\"0 0 16 16\" width={size} height={size} fill=\"currentColor\" aria-hidden className={className}>\n <path d=\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8Z\" />\n </svg>\n );\n}\n\n/** A site's mark, decorative (its name is always written beside it). */\nexport function FamilyMark({ mark, size }: { mark: SiteMark; size: number }): React.ReactElement {\n if (mark === \"github\") return <GitHubGlyph size={Math.round(size * 0.8)} />;\n return <ProductLogo id={mark} size={size} animated={false} />;\n}\n","// Server-safe: plain data. The Krizaka family — every site Krizaka runs, once. The family switcher of the bar\n// (`NavBar.Family`) and the common footer (`SiteFooter`) both read it, so adding a site is one release of this package:\n// every bar and every footer of the family follow.\n//\n// The words of the family (a site's one line, the groups, the statuses, the footer's signature) are brand data, written\n// here in English and French (`familyLabels`) — a site passes the set of its locale, or its own translation.\n\n/** A site of the family. */\nexport type SiteId = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"ui\" | \"java\" | \"github\";\n\n/** What a site is: the company, a product, or an open-source project. It chooses the footer's signature line. */\nexport type SiteKind = \"company\" | \"product\" | \"open-source\";\n\n/**\n * `released`: open to visit. `upcoming`: announced, not released yet (said \"Coming soon\"). `construction`: under\n * construction — nothing deployed beyond its page, nothing offered. `development`: being built in the open, nothing\n * deployed yet — its address is its repository (said \"In development\").\n */\nexport type SiteStatus = \"released\" | \"upcoming\" | \"construction\" | \"development\";\n\n/** The groups of the family, in reading order: Krizaka · Products · Open source · GitHub. */\nexport type SiteGroup = \"krizaka\" | \"products\" | \"open-source\" | \"github\";\n\n/** The mark a site wears: a brand of `ProductLogo` (Krizaka UI and Krizaka Java wear Krizaka's), or GitHub's. */\nexport type SiteMark = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"github\";\n\nexport interface Site {\n readonly id: SiteId;\n /** The name, never translated. */\n readonly name: string;\n /** The address of the site (its home). */\n readonly url: string;\n /** The address without the scheme, as people say it (`ui.krizaka.com`). */\n readonly host: string;\n readonly kind: SiteKind;\n readonly group: SiteGroup;\n readonly status: SiteStatus;\n readonly mark: SiteMark;\n /** The repository the site is built from. */\n readonly repo: string;\n}\n\nconst site = (s: Omit<Site, \"host\">): Site => ({ ...s, host: s.url.replace(/^https?:\\/\\//, \"\").replace(/\\/$/, \"\") });\n\n/** Every site of the family, in reading order (the group order, then the order inside each group). */\nexport const sites: readonly Site[] = [\n site({ id: \"krizaka\", name: \"Krizaka\", url: \"https://www.krizaka.com\", kind: \"company\", group: \"krizaka\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-com\" }),\n site({ id: \"orazaka\", name: \"Orazaka\", url: \"https://dev.orazaka.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orazaka\", repo: \"https://github.com/krizaka/orazaka\" }),\n site({ id: \"orochia\", name: \"Orochia\", url: \"https://dev.orochia.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orochia\", repo: \"https://github.com/krizaka/orochia\" }),\n site({ id: \"yasakia\", name: \"Yasakia\", url: \"https://dev.yasakia.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yasakia\", repo: \"https://github.com/krizaka/yasakia\" }),\n site({ id: \"yororis\", name: \"Yororis\", url: \"https://dev.yororis.com\", kind: \"product\", group: \"products\", status: \"construction\", mark: \"yororis\", repo: \"https://github.com/krizaka/yororis\" }),\n site({ id: \"yomizaka\", name: \"Yomizaka\", url: \"https://dev.yomizaka.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yomizaka\", repo: \"https://github.com/krizaka/yomizaka\" }),\n // In development: nothing deployed yet, so the address is the repository (never a dead link to an unborn dev site).\n site({ id: \"kachizaka\", name: \"Kachizaka\", url: \"https://github.com/krizaka/kachizaka\", kind: \"product\", group: \"products\", status: \"development\", mark: \"kachizaka\", repo: \"https://github.com/krizaka/kachizaka\" }),\n site({ id: \"akinaza\", name: \"Akinaza\", url: \"https://github.com/krizaka/akinaza\", kind: \"product\", group: \"products\", status: \"development\", mark: \"akinaza\", repo: \"https://github.com/krizaka/akinaza\" }),\n site({ id: \"ui\", name: \"Krizaka UI\", url: \"https://ui.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-ui\" }),\n site({ id: \"java\", name: \"Krizaka Java\", url: \"https://java.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-build\" }),\n site({ id: \"github\", name: \"GitHub\", url: \"https://github.com/krizaka\", kind: \"open-source\", group: \"github\", status: \"released\", mark: \"github\", repo: \"https://github.com/krizaka\" }),\n];\n\n/** The groups, in reading order. */\nexport const siteGroups: readonly SiteGroup[] = [\"krizaka\", \"products\", \"open-source\", \"github\"];\n\n/** A site by id. */\nexport function siteById(id: SiteId): Site {\n const found = sites.find((s) => s.id === id);\n if (!found) throw new Error(`Unknown Krizaka site \"${id}\".`);\n return found;\n}\n\n/** The family grouped, in reading order: `[{ group, sites }]`, empty groups left out. */\nexport function sitesByGroup(): { group: SiteGroup; sites: Site[] }[] {\n return siteGroups.map((group) => ({ group, sites: sites.filter((s) => s.group === group) })).filter((g) => g.sites.length > 0);\n}\n\n/** The languages the family's words are written in. */\nexport type SiteLocale = \"en\" | \"fr\";\n\n/** The words of the family: the switcher, the footer, each site's one line. */\nexport interface FamilyLabels {\n /** The family's name: the switcher's navigation and its button, the footer's navigation (“Krizaka family”). */\n family: string;\n /** The heading of each group. */\n groups: Record<SiteGroup, string>;\n /** The badge of a site that is not released. */\n status: Record<Exclude<SiteStatus, \"released\">, string>;\n /** Says which site is the current one (“You are here”). */\n current: string;\n /** One line per site: what it is. */\n descriptions: Record<SiteId, string>;\n /** The footer's signature, by the kind of the current site (“A Krizaka product”). */\n signature: Record<SiteKind, string>;\n /** The footer's place line (“Made in Montréal”). */\n place: string;\n /** The accessible name of the version (“Version”). */\n version: string;\n}\n\n/** The family's words in English and French. Pass `familyLabels[locale]`, or your own translation of the same shape. */\nexport const familyLabels: Record<SiteLocale, FamilyLabels> = {\n en: {\n family: \"Krizaka family\",\n groups: { krizaka: \"Krizaka\", products: \"Products\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Coming soon\", construction: \"Under construction\", development: \"In development\" },\n current: \"You are here\",\n descriptions: {\n krizaka: \"The company: our products, our open source, our story.\",\n orazaka: \"Sovereign AI, on your own servers.\",\n orochia: \"A video platform for creators.\",\n yasakia: \"The dating app where you talk first.\",\n yororis: \"A listening space with a face and a voice.\",\n yomizaka: \"Your documents, read and checked by Orazaka.\",\n kachizaka: \"Predictions among friends — live data, in real time.\",\n akinaza: \"Running a shop in Québec, for less — Loi 25 by design.\",\n ui: \"Components, tokens, icons and charts — web and React Native.\",\n java: \"Spring Boot building blocks on Maven Central.\",\n github: \"Every repository, in the open.\",\n },\n signature: { company: \"A Krizaka company\", product: \"A Krizaka product\", \"open-source\": \"A Krizaka open-source project\" },\n place: \"Made in Montréal\",\n version: \"Version\",\n },\n fr: {\n family: \"Famille Krizaka\",\n groups: { krizaka: \"Krizaka\", products: \"Produits\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Bientôt\", construction: \"En construction\", development: \"En développement\" },\n current: \"Vous êtes ici\",\n descriptions: {\n krizaka: \"La compagnie : nos produits, notre open source, notre histoire.\",\n orazaka: \"L’IA souveraine, sur vos propres serveurs.\",\n orochia: \"Une plateforme vidéo pour les créateurs.\",\n yasakia: \"L’app de rencontre où l’on se parle d’abord.\",\n yororis: \"Un espace d’écoute avec un visage et une voix.\",\n yomizaka: \"Vos documents, lus et vérifiés par Orazaka.\",\n kachizaka: \"Les pronostics entre amis — des données en direct.\",\n akinaza: \"Tenir une boutique au Québec, pour moins cher — Loi 25 dès la conception.\",\n ui: \"Composants, jetons, icônes et graphiques — web et React Native.\",\n java: \"Des briques Spring Boot sur Maven Central.\",\n github: \"Tous les dépôts, au grand jour.\",\n },\n signature: { company: \"Une compagnie Krizaka\", product: \"Un produit Krizaka\", \"open-source\": \"Un projet open source de Krizaka\" },\n place: \"Fait à Montréal\",\n version: \"Version\",\n },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/family-mark.tsx","../src/sites/sites.ts"],"sourcesContent":["// The mark of a site of the family (`@krizaka/ui/sites`): its brand's `ProductLogo`, still (a list of marks never\n// moves), or GitHub's, in the text colour. Shared by `NavBar.Family` and `SiteFooter` — not an entry of its own.\nimport type * as React from \"react\";\n\nimport { ProductLogo } from \"./marks/ProductLogo\";\nimport type { SiteMark } from \"./sites/sites\";\n\n/** GitHub's mark, in the text colour (both themes). */\nexport function GitHubGlyph({ size = 16, className }: { size?: number; className?: string }) {\n return (\n <svg viewBox=\"0 0 16 16\" width={size} height={size} fill=\"currentColor\" aria-hidden className={className}>\n <path d=\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8Z\" />\n </svg>\n );\n}\n\n/** A site's mark, decorative (its name is always written beside it). */\nexport function FamilyMark({ mark, size }: { mark: SiteMark; size: number }): React.ReactElement {\n if (mark === \"github\") return <GitHubGlyph size={Math.round(size * 0.8)} />;\n return <ProductLogo id={mark} size={size} animated={false} />;\n}\n","// Server-safe: plain data. The Krizaka family — every site Krizaka runs, once. The family switcher of the bar\n// (`NavBar.Family`) and the common footer (`SiteFooter`) both read it, so adding a site is one release of this package:\n// every bar and every footer of the family follow.\n//\n// The words of the family (a site's one line, the groups, the statuses, the footer's signature) are brand data, written\n// here in English and French (`familyLabels`) — a site passes the set of its locale, or its own translation.\n\n/** A site of the family. */\nexport type SiteId = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"ui\" | \"java\" | \"github\";\n\n/** What a site is: the company, a product, or an open-source project. It chooses the footer's signature line. */\nexport type SiteKind = \"company\" | \"product\" | \"open-source\";\n\n/**\n * `released`: open to visit. `upcoming`: announced, not released yet (said \"Coming soon\"). `construction`: under\n * construction — nothing deployed beyond its page, nothing offered. `development`: being built in the open, nothing\n * deployed yet — its address is its repository (said \"In development\").\n */\nexport type SiteStatus = \"released\" | \"upcoming\" | \"construction\" | \"development\";\n\n/** The groups of the family, in reading order: Krizaka · Products · Open source · GitHub. */\nexport type SiteGroup = \"krizaka\" | \"products\" | \"open-source\" | \"github\";\n\n/** The mark a site wears: a brand of `ProductLogo` (Krizaka UI and Krizaka Java wear Krizaka's), or GitHub's. */\nexport type SiteMark = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"github\";\n\nexport interface Site {\n readonly id: SiteId;\n /** The name, never translated. */\n readonly name: string;\n /** The address of the site (its home). */\n readonly url: string;\n /** The address without the scheme, as people say it (`ui.krizaka.com`). */\n readonly host: string;\n readonly kind: SiteKind;\n readonly group: SiteGroup;\n readonly status: SiteStatus;\n readonly mark: SiteMark;\n /** The repository the site is built from. */\n readonly repo: string;\n}\n\nconst site = (s: Omit<Site, \"host\">): Site => ({ ...s, host: s.url.replace(/^https?:\\/\\//, \"\").replace(/\\/$/, \"\") });\n\n/** Every site of the family, in reading order (the group order, then the order inside each group). */\nexport const sites: readonly Site[] = [\n site({ id: \"krizaka\", name: \"Krizaka\", url: \"https://www.krizaka.com\", kind: \"company\", group: \"krizaka\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-com\" }),\n site({ id: \"orazaka\", name: \"Orazaka\", url: \"https://dev.orazaka.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orazaka\", repo: \"https://github.com/krizaka/orazaka\" }),\n site({ id: \"orochia\", name: \"Orochia\", url: \"https://dev.orochia.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orochia\", repo: \"https://github.com/krizaka/orochia\" }),\n site({ id: \"yasakia\", name: \"Yasakia\", url: \"https://dev.yasakia.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yasakia\", repo: \"https://github.com/krizaka/yasakia\" }),\n site({ id: \"yororis\", name: \"Yororis\", url: \"https://dev.yororis.com\", kind: \"product\", group: \"products\", status: \"construction\", mark: \"yororis\", repo: \"https://github.com/krizaka/yororis\" }),\n site({ id: \"yomizaka\", name: \"Yomizaka\", url: \"https://dev.yomizaka.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yomizaka\", repo: \"https://github.com/krizaka/yomizaka\" }),\n // In development: nothing deployed yet, so the address is the repository (never a dead link to an unborn dev site).\n site({ id: \"kachizaka\", name: \"Kachizaka\", url: \"https://github.com/krizaka/kachizaka\", kind: \"product\", group: \"products\", status: \"development\", mark: \"kachizaka\", repo: \"https://github.com/krizaka/kachizaka\" }),\n site({ id: \"akinaza\", name: \"Akinaza\", url: \"https://github.com/krizaka/akinaza\", kind: \"product\", group: \"products\", status: \"development\", mark: \"akinaza\", repo: \"https://github.com/krizaka/akinaza\" }),\n site({ id: \"ui\", name: \"Krizaka UI\", url: \"https://ui.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-ui\" }),\n site({ id: \"java\", name: \"Krizaka Java\", url: \"https://java.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-build\" }),\n site({ id: \"github\", name: \"GitHub\", url: \"https://github.com/krizaka\", kind: \"open-source\", group: \"github\", status: \"released\", mark: \"github\", repo: \"https://github.com/krizaka\" }),\n];\n\n/** The groups, in reading order. */\nexport const siteGroups: readonly SiteGroup[] = [\"krizaka\", \"products\", \"open-source\", \"github\"];\n\n/** A site by id. */\nexport function siteById(id: SiteId): Site {\n const found = sites.find((s) => s.id === id);\n if (!found) throw new Error(`Unknown Krizaka site \"${id}\".`);\n return found;\n}\n\n/** The family grouped, in reading order: `[{ group, sites }]`, empty groups left out. */\nexport function sitesByGroup(): { group: SiteGroup; sites: Site[] }[] {\n return siteGroups.map((group) => ({ group, sites: sites.filter((s) => s.group === group) })).filter((g) => g.sites.length > 0);\n}\n\n/** The languages the family's words are written in. */\nexport type SiteLocale = \"en\" | \"fr\";\n\n/** The words of the family: the switcher, the footer, each site's one line. */\nexport interface FamilyLabels {\n /** The family's name: the switcher's navigation and its button, the footer's navigation (“Krizaka family”). */\n family: string;\n /** The heading of each group. */\n groups: Record<SiteGroup, string>;\n /** The badge of a site that is not released. */\n status: Record<Exclude<SiteStatus, \"released\">, string>;\n /** Says which site is the current one (“You are here”). */\n current: string;\n /** One line per site: what it is. */\n descriptions: Record<SiteId, string>;\n /** The footer's signature, by the kind of the current site (“A Krizaka product”). */\n signature: Record<SiteKind, string>;\n /** The footer's place line (“Made in Montréal”). */\n place: string;\n /** The accessible name of the version (“Version”). */\n version: string;\n}\n\n/** The family's words in English and French. Pass `familyLabels[locale]`, or your own translation of the same shape. */\nexport const familyLabels: Record<SiteLocale, FamilyLabels> = {\n en: {\n family: \"Krizaka family\",\n groups: { krizaka: \"Krizaka\", products: \"Products\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Coming soon\", construction: \"Under construction\", development: \"In development\" },\n current: \"You are here\",\n descriptions: {\n krizaka: \"The company: our products, our open source, our story.\",\n orazaka: \"Sovereign AI, on your own servers.\",\n orochia: \"A video platform for creators.\",\n yasakia: \"The dating app where you talk first.\",\n yororis: \"A listening space with a face and a voice.\",\n yomizaka: \"Yomizaka reads your leases, contracts and invoices.\",\n kachizaka: \"Predictions among friends — live data, in real time.\",\n akinaza: \"Running a shop in Québec, for less — Loi 25 by design.\",\n ui: \"Components, tokens, icons and charts — web and React Native.\",\n java: \"Spring Boot building blocks on Maven Central.\",\n github: \"Every repository, in the open.\",\n },\n signature: { company: \"A Krizaka company\", product: \"A Krizaka product\", \"open-source\": \"A Krizaka open-source project\" },\n place: \"Made in Montréal\",\n version: \"Version\",\n },\n fr: {\n family: \"Famille Krizaka\",\n groups: { krizaka: \"Krizaka\", products: \"Produits\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Bientôt\", construction: \"En construction\", development: \"En développement\" },\n current: \"Vous êtes ici\",\n descriptions: {\n krizaka: \"La compagnie : nos produits, notre open source, notre histoire.\",\n orazaka: \"L’IA souveraine, sur vos propres serveurs.\",\n orochia: \"Une plateforme vidéo pour les créateurs.\",\n yasakia: \"L’app de rencontre où l’on se parle d’abord.\",\n yororis: \"Un espace d’écoute avec un visage et une voix.\",\n yomizaka: \"Yomizaka lit vos baux, contrats et factures.\",\n kachizaka: \"Les pronostics entre amis — des données en direct.\",\n akinaza: \"Tenir une boutique au Québec, pour moins cher — Loi 25 dès la conception.\",\n ui: \"Composants, jetons, icônes et graphiques — web et React Native.\",\n java: \"Des briques Spring Boot sur Maven Central.\",\n github: \"Tous les dépôts, au grand jour.\",\n },\n signature: { company: \"Une compagnie Krizaka\", product: \"Un produit Krizaka\", \"open-source\": \"Un projet open source de Krizaka\" },\n place: \"Fait à Montréal\",\n version: \"Version\",\n },\n};\n"],"mappings":"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","names":[]}
@@ -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";