@krizaka/ui 3.46.0 → 3.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/dist/account-menu.d.ts +2 -111
  2. package/dist/account-menu.js +39 -118
  3. package/dist/account-menu.js.map +1 -1
  4. package/dist/account-settings.d.ts +163 -0
  5. package/dist/account-settings.js +354 -0
  6. package/dist/account-settings.js.map +1 -0
  7. package/dist/agenda.d.ts +136 -0
  8. package/dist/agenda.js +90 -0
  9. package/dist/agenda.js.map +1 -0
  10. package/dist/avatar-iajODANU.d.ts +114 -0
  11. package/dist/chunk-3D2YI63L.js +27 -0
  12. package/dist/chunk-3D2YI63L.js.map +1 -0
  13. package/dist/chunk-3RVFD3UX.js +85 -0
  14. package/dist/chunk-3RVFD3UX.js.map +1 -0
  15. package/dist/chunk-S6NYGOJT.js +22 -0
  16. package/dist/chunk-S6NYGOJT.js.map +1 -0
  17. package/dist/docs-layout.js +13 -32
  18. package/dist/docs-layout.js.map +1 -1
  19. package/dist/docs-nav.js +1 -1
  20. package/dist/drop-overlay.d.ts +31 -0
  21. package/dist/drop-overlay.js +86 -0
  22. package/dist/drop-overlay.js.map +1 -0
  23. package/dist/motion.css +27 -0
  24. package/dist/settings-layout.d.ts +59 -4
  25. package/dist/settings-layout.js +229 -24
  26. package/dist/settings-layout.js.map +1 -1
  27. package/dist/upload-queue.d.ts +67 -0
  28. package/dist/upload-queue.js +76 -0
  29. package/dist/upload-queue.js.map +1 -0
  30. package/package.json +33 -7
  31. package/registry/account-menu.json +2 -2
  32. package/registry/account-settings.json +721 -0
  33. package/registry/achievement.json +1 -1
  34. package/registry/action-bar.json +1 -1
  35. package/registry/activity-feed.json +1 -1
  36. package/registry/agenda.json +293 -0
  37. package/registry/alert.json +1 -1
  38. package/registry/anatomy-plate.json +1 -1
  39. package/registry/app-header.json +1 -1
  40. package/registry/app-shell.json +1 -1
  41. package/registry/argument-card.json +1 -1
  42. package/registry/audio-player.json +1 -1
  43. package/registry/auth-layout.json +1 -1
  44. package/registry/avatar.json +1 -1
  45. package/registry/badge.json +1 -1
  46. package/registry/bird-plate.json +1 -1
  47. package/registry/button.json +1 -1
  48. package/registry/captcha.json +1 -1
  49. package/registry/card-grid.json +1 -1
  50. package/registry/card.json +1 -1
  51. package/registry/catalogue-page.json +1 -1
  52. package/registry/changelog-page.json +1 -1
  53. package/registry/chat.json +3 -3
  54. package/registry/checkbox.json +1 -1
  55. package/registry/chip-link.json +1 -1
  56. package/registry/chip-row.json +1 -1
  57. package/registry/chip.json +1 -1
  58. package/registry/choice-grid.json +1 -1
  59. package/registry/code-block.json +1 -1
  60. package/registry/combobox.json +1 -1
  61. package/registry/command.json +1 -1
  62. package/registry/comparison-table.json +1 -1
  63. package/registry/component-page.json +1 -1
  64. package/registry/confirm-button.json +1 -1
  65. package/registry/contact-page.json +1 -1
  66. package/registry/continue-prompt.json +1 -1
  67. package/registry/countdown.json +1 -1
  68. package/registry/cover-hero.json +1 -1
  69. package/registry/cta-panel.json +1 -1
  70. package/registry/dashboard-layout.json +1 -1
  71. package/registry/data-table.json +3 -3
  72. package/registry/date-picker.json +1 -1
  73. package/registry/decision-list.json +1 -1
  74. package/registry/description-list.json +1 -1
  75. package/registry/detail-layout.json +1 -1
  76. package/registry/dialog.json +1 -1
  77. package/registry/docs-article-page.json +1 -1
  78. package/registry/docs-hub-page.json +1 -1
  79. package/registry/docs-layout.json +1 -1
  80. package/registry/docs-nav.json +1 -1
  81. package/registry/document-viewer.json +1 -1
  82. package/registry/drop-overlay.json +182 -0
  83. package/registry/dropdown-menu.json +1 -1
  84. package/registry/elephant.json +2 -2
  85. package/registry/empty-state.json +1 -1
  86. package/registry/engine-flow.json +1 -1
  87. package/registry/error-page.json +1 -1
  88. package/registry/examples/account-settings/avatar-picker.d.ts +4 -0
  89. package/registry/examples/account-settings/avatar-picker.js +15 -0
  90. package/registry/examples/account-settings/avatar-picker.tsx +15 -0
  91. package/registry/examples/account-settings/choice-cards.d.ts +4 -0
  92. package/registry/examples/account-settings/choice-cards.js +24 -0
  93. package/registry/examples/account-settings/choice-cards.tsx +20 -0
  94. package/registry/examples/account-settings/language-picker.d.ts +4 -0
  95. package/registry/examples/account-settings/language-picker.js +25 -0
  96. package/registry/examples/account-settings/language-picker.tsx +21 -0
  97. package/registry/examples/account-settings/patterns.d.ts +4 -0
  98. package/registry/examples/account-settings/patterns.js +29 -0
  99. package/registry/examples/account-settings/patterns.tsx +39 -0
  100. package/registry/examples/account-settings/profile.d.ts +4 -0
  101. package/registry/examples/account-settings/profile.js +70 -0
  102. package/registry/examples/account-settings/profile.tsx +80 -0
  103. package/registry/examples/agenda/day.d.ts +4 -0
  104. package/registry/examples/agenda/day.js +43 -0
  105. package/registry/examples/agenda/day.tsx +35 -0
  106. package/registry/examples/drop-overlay/default.d.ts +4 -0
  107. package/registry/examples/drop-overlay/default.js +20 -0
  108. package/registry/examples/drop-overlay/default.tsx +18 -0
  109. package/registry/examples/upload-queue/default.d.ts +4 -0
  110. package/registry/examples/upload-queue/default.js +22 -0
  111. package/registry/examples/upload-queue/default.tsx +20 -0
  112. package/registry/examples/upload-queue/tray.d.ts +4 -0
  113. package/registry/examples/upload-queue/tray.js +21 -0
  114. package/registry/examples/upload-queue/tray.tsx +19 -0
  115. package/registry/field.json +1 -1
  116. package/registry/file-upload.json +1 -1
  117. package/registry/filter-bar.json +1 -1
  118. package/registry/flock.json +1 -1
  119. package/registry/footnote.json +1 -1
  120. package/registry/force-update-screen.json +1 -1
  121. package/registry/form.json +3 -3
  122. package/registry/gallery-page.json +1 -1
  123. package/registry/genui.json +1 -1
  124. package/registry/glow-card.json +1 -1
  125. package/registry/goal-gauge.json +1 -1
  126. package/registry/how-it-works-page.json +1 -1
  127. package/registry/image-cropper.json +1 -1
  128. package/registry/index.json +147 -7
  129. package/registry/iso.json +1 -1
  130. package/registry/kanban.json +1 -1
  131. package/registry/kbd.json +1 -1
  132. package/registry/landing-page.json +1 -1
  133. package/registry/landscape.json +1 -1
  134. package/registry/language-switch.json +1 -1
  135. package/registry/legal-page.json +1 -1
  136. package/registry/link-card.json +1 -1
  137. package/registry/list.json +3 -3
  138. package/registry/loader.json +1 -1
  139. package/registry/longform-page.json +1 -1
  140. package/registry/maintenance-screen.json +1 -1
  141. package/registry/map.json +2 -2
  142. package/registry/markdown.json +1 -1
  143. package/registry/marketing-layout.json +1 -1
  144. package/registry/marquee.json +1 -1
  145. package/registry/mascot-quote.json +3 -3
  146. package/registry/mascot-state.json +3 -3
  147. package/registry/mascots.json +3 -3
  148. package/registry/match-dialog.json +1 -1
  149. package/registry/media-capture.json +1 -1
  150. package/registry/media-gallery.json +1 -1
  151. package/registry/media-grid.json +1 -1
  152. package/registry/meta-row.json +1 -1
  153. package/registry/meter.json +1 -1
  154. package/registry/nav-bar.json +2 -2
  155. package/registry/number-ticker.json +1 -1
  156. package/registry/opening-hours.json +1 -1
  157. package/registry/page-header.json +1 -1
  158. package/registry/page-hero.json +1 -1
  159. package/registry/page-index.json +1 -1
  160. package/registry/page.json +1 -1
  161. package/registry/pagination.json +1 -1
  162. package/registry/photo-grid.json +1 -1
  163. package/registry/pointer-light.json +1 -1
  164. package/registry/popover.json +1 -1
  165. package/registry/pricing-page.json +1 -1
  166. package/registry/product-page.json +1 -1
  167. package/registry/profile-card.json +1 -1
  168. package/registry/progress.json +1 -1
  169. package/registry/promise-card.json +1 -1
  170. package/registry/radio-group.json +93 -5
  171. package/registry/rail-nav.json +2 -2
  172. package/registry/recipes.json +1 -1
  173. package/registry/router.json +1 -1
  174. package/registry/scroll-stage.json +1 -1
  175. package/registry/search-field.json +1 -1
  176. package/registry/section-backdrop.json +1 -1
  177. package/registry/separator.json +1 -1
  178. package/registry/service-card.json +1 -1
  179. package/registry/settings-layout.json +34 -4
  180. package/registry/showcase.json +1 -1
  181. package/registry/site-footer.json +2 -2
  182. package/registry/sites.json +1 -1
  183. package/registry/skeleton.json +1 -1
  184. package/registry/skip-link.json +1 -1
  185. package/registry/slider.json +1 -1
  186. package/registry/slot-picker.json +1 -1
  187. package/registry/slot.json +1 -1
  188. package/registry/specimen-tag.json +1 -1
  189. package/registry/spinner.json +1 -1
  190. package/registry/split-view.json +1 -1
  191. package/registry/stage-banner.json +1 -1
  192. package/registry/stat.json +1 -1
  193. package/registry/status-page.json +1 -1
  194. package/registry/step-progress.json +1 -1
  195. package/registry/step-showcase.json +1 -1
  196. package/registry/stepper.json +1 -1
  197. package/registry/sticky-action.json +1 -1
  198. package/registry/swipe-deck.json +1 -1
  199. package/registry/switch.json +1 -1
  200. package/registry/tabs.json +1 -1
  201. package/registry/tag-input.json +3 -3
  202. package/registry/tag-selector.json +1 -1
  203. package/registry/terminal-replay.json +1 -1
  204. package/registry/theme.json +1 -1
  205. package/registry/toast.json +1 -1
  206. package/registry/toc.json +1 -1
  207. package/registry/tooltip.json +1 -1
  208. package/registry/tree-view.json +1 -1
  209. package/registry/update-prompt.json +1 -1
  210. package/registry/upload-queue.json +243 -0
  211. package/registry/verified-badge.json +1 -1
  212. package/registry/vertical-video.json +1 -1
  213. package/registry/video-player.json +1 -1
  214. package/registry/video-trimmer.json +1 -1
  215. package/registry/virtual.json +1 -1
  216. package/registry/waveform.json +1 -1
package/dist/agenda.js ADDED
@@ -0,0 +1,90 @@
1
+ // src/agenda/agenda.tsx
2
+ import { tv } from "tailwind-variants";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ var agenda = tv({
5
+ slots: {
6
+ root: "m-0 flex list-none flex-col p-0",
7
+ item: "relative flex items-stretch gap-1 border-b border-border-subtle last:border-b-0",
8
+ main: "group flex min-w-0 flex-1 items-center gap-3 rounded-md px-2 py-3 text-left outline-none transition-colors hover:bg-surface-1 focus-visible:ring-2 focus-visible:ring-focus data-[selected=true]:bg-surface-2",
9
+ times: "flex w-16 shrink-0 flex-col text-sm tabular-nums text-fg",
10
+ start: "font-semibold",
11
+ end: "text-xs text-fg-secondary",
12
+ marker: "h-2.5 w-2.5 shrink-0 rounded-full bg-[var(--kz-ag-tone)] ring-4 ring-surface-0",
13
+ leading: "shrink-0",
14
+ text: "flex min-w-0 flex-1 flex-col",
15
+ title: "truncate text-sm font-semibold text-fg",
16
+ description: "truncate text-xs text-fg-secondary",
17
+ status: "shrink-0",
18
+ action: "flex shrink-0 items-center pr-1",
19
+ now: "relative flex items-center gap-2 py-1 text-xs font-semibold text-fg-accent",
20
+ nowLine: "h-px flex-1 bg-accent",
21
+ nowDot: "h-2 w-2 shrink-0 rounded-full bg-accent",
22
+ empty: "py-6"
23
+ },
24
+ variants: {
25
+ past: { true: { times: "text-fg-secondary", title: "font-medium text-fg-secondary", marker: "opacity-60" } }
26
+ }
27
+ });
28
+ var TONE = {
29
+ neutral: "var(--kz-border-strong)",
30
+ accent: "var(--kz-accent)",
31
+ success: "var(--kz-success)",
32
+ warning: "var(--kz-warning)",
33
+ danger: "var(--kz-danger)",
34
+ info: "var(--kz-info)"
35
+ };
36
+ var agendaLabels = { now: (time) => `Now \xB7 ${time}` };
37
+ var stamp = (value) => Date.parse(value);
38
+ function Agenda({ items, locale = "en-US", timeZone, now, selectedId, onSelect, linkAs, action, labels: given, empty, className, "aria-label": label }) {
39
+ const labels = { ...agendaLabels, ...given };
40
+ const s = agenda();
41
+ const clock = new Intl.DateTimeFormat(locale, { hour: "numeric", minute: "2-digit", timeZone });
42
+ const time = (value) => clock.format(typeof value === "string" ? new Date(value) : value);
43
+ const sorted = [...items].sort((a, b) => stamp(a.start) - stamp(b.start));
44
+ if (sorted.length === 0) return empty ? /* @__PURE__ */ jsx("div", { className: s.empty(), children: empty }) : null;
45
+ const at = now ? now.getTime() : null;
46
+ const upcoming = at === null ? -1 : sorted.findIndex((i) => stamp(i.start) > at);
47
+ const lineBefore = at === null ? -1 : upcoming === -1 ? sorted.length : upcoming;
48
+ const Link = linkAs ?? "a";
49
+ const row = (item) => {
50
+ const begun = at !== null && stamp(item.start) <= at;
51
+ const over = begun && item.end !== void 0 && stamp(item.end) <= at;
52
+ const rowStyle = agenda({ past: over });
53
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
54
+ /* @__PURE__ */ jsxs("span", { className: rowStyle.times(), children: [
55
+ /* @__PURE__ */ jsx("span", { className: s.start(), children: time(item.start) }),
56
+ item.end ? /* @__PURE__ */ jsx("span", { className: s.end(), children: time(item.end) }) : null
57
+ ] }),
58
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: rowStyle.marker(), style: { ["--kz-ag-tone"]: TONE[item.tone ?? "neutral"] } }),
59
+ item.leading ? /* @__PURE__ */ jsx("span", { className: s.leading(), children: item.leading }) : null,
60
+ /* @__PURE__ */ jsxs("span", { className: s.text(), children: [
61
+ /* @__PURE__ */ jsx("span", { className: rowStyle.title(), children: item.title }),
62
+ item.description ? /* @__PURE__ */ jsx("span", { className: s.description(), children: item.description }) : null
63
+ ] }),
64
+ item.status ? /* @__PURE__ */ jsx("span", { className: s.status(), children: item.status }) : null
65
+ ] });
66
+ const common = { className: s.main(), "data-selected": selectedId === item.id, "data-current": begun && !over, "aria-current": selectedId === item.id ? "true" : void 0 };
67
+ return /* @__PURE__ */ jsxs("li", { className: s.item(), children: [
68
+ item.href ? /* @__PURE__ */ jsx(Link, { href: item.href, ...common, children: inner }) : /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onSelect?.(item), ...common, children: inner }),
69
+ action ? /* @__PURE__ */ jsx("div", { className: s.action(), children: action(item) }) : null
70
+ ] }, item.id);
71
+ };
72
+ const nowLine = at === null ? null : /* @__PURE__ */ jsxs("li", { className: s.now(), "data-agenda-now": true, children: [
73
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: s.nowDot() }),
74
+ /* @__PURE__ */ jsx("span", { children: labels.now(time(now)) }),
75
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: s.nowLine() })
76
+ ] }, "now");
77
+ const rows = [];
78
+ sorted.forEach((item, index) => {
79
+ if (index === lineBefore) rows.push(nowLine);
80
+ rows.push(row(item));
81
+ });
82
+ if (lineBefore === sorted.length) rows.push(nowLine);
83
+ return /* @__PURE__ */ jsx("ol", { "aria-label": label, className: s.root({ className }), children: rows });
84
+ }
85
+ export {
86
+ Agenda,
87
+ agenda,
88
+ agendaLabels
89
+ };
90
+ //# sourceMappingURL=agenda.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agenda/agenda.tsx"],"sourcesContent":["// Server-safe. One day's agenda: the appointments in time order, the times in tabular sans figures, a « now » line\n// placed between them, the past dimmed. The row is one link or button (the app's selection, its URL); its action is a\n// sibling control, never nested. Words are props; the app passes `now` (null hides the line).\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const agenda = tv({\n slots: {\n root: \"m-0 flex list-none flex-col p-0\",\n item: \"relative flex items-stretch gap-1 border-b border-border-subtle last:border-b-0\",\n main: \"group flex min-w-0 flex-1 items-center gap-3 rounded-md px-2 py-3 text-left outline-none transition-colors hover:bg-surface-1 focus-visible:ring-2 focus-visible:ring-focus data-[selected=true]:bg-surface-2\",\n times: \"flex w-16 shrink-0 flex-col text-sm tabular-nums text-fg\",\n start: \"font-semibold\",\n end: \"text-xs text-fg-secondary\",\n marker: \"h-2.5 w-2.5 shrink-0 rounded-full bg-[var(--kz-ag-tone)] ring-4 ring-surface-0\",\n leading: \"shrink-0\",\n text: \"flex min-w-0 flex-1 flex-col\",\n title: \"truncate text-sm font-semibold text-fg\",\n description: \"truncate text-xs text-fg-secondary\",\n status: \"shrink-0\",\n action: \"flex shrink-0 items-center pr-1\",\n now: \"relative flex items-center gap-2 py-1 text-xs font-semibold text-fg-accent\",\n nowLine: \"h-px flex-1 bg-accent\",\n nowDot: \"h-2 w-2 shrink-0 rounded-full bg-accent\",\n empty: \"py-6\",\n },\n variants: {\n past: { true: { times: \"text-fg-secondary\", title: \"font-medium text-fg-secondary\", marker: \"opacity-60\" } },\n },\n});\n\nexport type AgendaTone = \"neutral\" | \"accent\" | \"success\" | \"warning\" | \"danger\" | \"info\";\nconst TONE: Record<AgendaTone, string> = {\n neutral: \"var(--kz-border-strong)\",\n accent: \"var(--kz-accent)\",\n success: \"var(--kz-success)\",\n warning: \"var(--kz-warning)\",\n danger: \"var(--kz-danger)\",\n info: \"var(--kz-info)\",\n};\n\nexport type AgendaItem = {\n id: string;\n /** ISO instant. */\n start: string;\n /** ISO instant; shown under the start and used to know which one is current. */\n end?: string;\n /** The client, the subject. */\n title: React.ReactNode;\n /** The service, the stylist: one muted line. */\n description?: React.ReactNode;\n /** The colour of the rail's dot; the status chip carries the word. */\n tone?: AgendaTone;\n /** Before the text: an `Avatar`. */\n leading?: React.ReactNode;\n /** After the text: a `Badge` with the status, in words. */\n status?: React.ReactNode;\n /** An address for the row (the app's URL state, `?appointment=…`); rendered with `linkAs`. */\n href?: string;\n};\n\nexport type AgendaLabels = {\n /** The « now » line: `(time) => \"Now · 10:42\"`. */\n now: (time: string) => string;\n};\nexport const agendaLabels: AgendaLabels = { now: (time) => `Now · ${time}` };\n\nexport type AgendaProps<T extends AgendaItem> = {\n /** The day's appointments, in any order: the agenda sorts them by start. */\n items: readonly T[];\n /** The agenda's accessible name (« Appointments of Monday »). */\n \"aria-label\": string;\n /** The locale of the times. Default `en-US`. */\n locale?: string;\n /** The time zone of the shop, so the times read the same on the server and on the phone. */\n timeZone?: string;\n /** The instant of the « now » line; `null` or absent hides it (a day that is not today). */\n now?: Date | null;\n /** The open item: marked `aria-current`. */\n selectedId?: string | null;\n /** Called with the item pressed, for items with no `href`. */\n onSelect?: (item: T) => void;\n /** The router's link for items with an `href` (`next/link`). Default `a`. */\n linkAs?: React.ElementType;\n /** A small control after the row (Start, End), outside the row's link. */\n action?: (item: T) => React.ReactNode;\n /** The words, passed translated (the « now » line). */\n labels?: Partial<AgendaLabels>;\n /** Shown when there is no item (an `EmptyState`). */\n empty?: React.ReactNode;\n /** Classes merged on the list. */\n className?: string;\n};\n\nconst stamp = (value: string) => Date.parse(value);\n\nexport function Agenda<T extends AgendaItem>({ items, locale = \"en-US\", timeZone, now, selectedId, onSelect, linkAs, action, labels: given, empty, className, \"aria-label\": label }: AgendaProps<T>) {\n const labels = { ...agendaLabels, ...given };\n const s = agenda();\n const clock = new Intl.DateTimeFormat(locale, { hour: \"numeric\", minute: \"2-digit\", timeZone });\n const time = (value: string | Date) => clock.format(typeof value === \"string\" ? new Date(value) : value);\n const sorted = [...items].sort((a, b) => stamp(a.start) - stamp(b.start));\n if (sorted.length === 0) return empty ? <div className={s.empty()}>{empty}</div> : null;\n const at = now ? now.getTime() : null;\n // The line goes before the first item still to come, and after the last when every one has begun.\n const upcoming = at === null ? -1 : sorted.findIndex((i) => stamp(i.start) > at);\n const lineBefore = at === null ? -1 : upcoming === -1 ? sorted.length : upcoming;\n const Link = (linkAs ?? \"a\") as React.ElementType;\n\n const row = (item: T) => {\n const begun = at !== null && stamp(item.start) <= at;\n const over = begun && item.end !== undefined && stamp(item.end) <= at!;\n const rowStyle = agenda({ past: over });\n const inner = (\n <>\n <span className={rowStyle.times()}>\n <span className={s.start()}>{time(item.start)}</span>\n {item.end ? <span className={s.end()}>{time(item.end)}</span> : null}\n </span>\n <span aria-hidden className={rowStyle.marker()} style={{ [\"--kz-ag-tone\" as string]: TONE[item.tone ?? \"neutral\"] }} />\n {item.leading ? <span className={s.leading()}>{item.leading}</span> : null}\n <span className={s.text()}>\n <span className={rowStyle.title()}>{item.title}</span>\n {item.description ? <span className={s.description()}>{item.description}</span> : null}\n </span>\n {item.status ? <span className={s.status()}>{item.status}</span> : null}\n </>\n );\n const common = { className: s.main(), \"data-selected\": selectedId === item.id, \"data-current\": begun && !over, \"aria-current\": selectedId === item.id ? (\"true\" as const) : undefined };\n return (\n <li key={item.id} className={s.item()}>\n {item.href ? (\n <Link href={item.href} {...common}>\n {inner}\n </Link>\n ) : (\n <button type=\"button\" onClick={() => onSelect?.(item)} {...common}>\n {inner}\n </button>\n )}\n {action ? <div className={s.action()}>{action(item)}</div> : null}\n </li>\n );\n };\n\n const nowLine =\n at === null ? null : (\n <li key=\"now\" className={s.now()} data-agenda-now>\n <span aria-hidden className={s.nowDot()} />\n <span>{labels.now(time(now!))}</span>\n <span aria-hidden className={s.nowLine()} />\n </li>\n );\n\n const rows: React.ReactNode[] = [];\n sorted.forEach((item, index) => {\n if (index === lineBefore) rows.push(nowLine);\n rows.push(row(item));\n });\n if (lineBefore === sorted.length) rows.push(nowLine);\n\n return (\n <ol aria-label={label} className={s.root({ className })}>\n {rows}\n </ol>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,114 @@
1
+ import * as tailwind_variants from 'tailwind-variants';
2
+ import { VariantProps } from 'tailwind-variants';
3
+ import * as React from 'react';
4
+
5
+ type DefaultAvatarBrand = "krizaka" | "orazaka" | "orochia" | "yasakia" | "yororis" | "yomizaka" | "kachizaka" | "akinaza";
6
+ /** `person`: a neutral silhouette. `plain`: the brand's gradient alone, ready for initials. */
7
+ type DefaultAvatarKind = "person" | "plain";
8
+ interface DefaultAvatar {
9
+ /** The brand of the product showing the avatar: its gradient, its hues. */
10
+ brand: DefaultAvatarBrand;
11
+ /** Any stable text or number of the person (their id): the same seed gives the same tone everywhere. */
12
+ seed?: string | number;
13
+ /** Force a tone, 1 to 6, instead of deriving it from `seed`. */
14
+ tone?: number;
15
+ /**
16
+ * `person` (default): a silhouette. `plain`: the gradient alone.
17
+ * @default "person"
18
+ */
19
+ kind?: DefaultAvatarKind;
20
+ }
21
+
22
+ declare const avatar: tailwind_variants.TVReturnType<{
23
+ size: {
24
+ xs: {
25
+ root: string;
26
+ };
27
+ sm: {
28
+ root: string;
29
+ };
30
+ md: {
31
+ root: string;
32
+ };
33
+ lg: {
34
+ root: string;
35
+ };
36
+ xl: {
37
+ root: string;
38
+ };
39
+ };
40
+ }, {
41
+ root: string;
42
+ image: string;
43
+ fallback: string;
44
+ group: string;
45
+ }, undefined, {
46
+ size: {
47
+ xs: {
48
+ root: string;
49
+ };
50
+ sm: {
51
+ root: string;
52
+ };
53
+ md: {
54
+ root: string;
55
+ };
56
+ lg: {
57
+ root: string;
58
+ };
59
+ xl: {
60
+ root: string;
61
+ };
62
+ };
63
+ }, {
64
+ root: string;
65
+ image: string;
66
+ fallback: string;
67
+ group: string;
68
+ }, tailwind_variants.TVReturnTypeLike<{
69
+ size: {
70
+ xs: {
71
+ root: string;
72
+ };
73
+ sm: {
74
+ root: string;
75
+ };
76
+ md: {
77
+ root: string;
78
+ };
79
+ lg: {
80
+ root: string;
81
+ };
82
+ xl: {
83
+ root: string;
84
+ };
85
+ };
86
+ }, {
87
+ root: string;
88
+ image: string;
89
+ fallback: string;
90
+ group: string;
91
+ }>>;
92
+ type AvatarSize = NonNullable<VariantProps<typeof avatar>["size"]>;
93
+ type AvatarProps = Omit<React.ComponentProps<"span">, "children"> & {
94
+ /** The image's URL; `null` or nothing shows the `fallback`. */
95
+ src?: string | null;
96
+ /** The image's text alternative (the person's name); empty when a visible name sits next to the avatar. */
97
+ alt?: string;
98
+ /** Shown while the image loads, when it fails or when there is none: initials, an icon. */
99
+ fallback?: React.ReactNode;
100
+ /** The picture to show instead when `src` is missing or fails to load (an image URL). The `fallback` still covers its own loading. */
101
+ fallbackSrc?: string;
102
+ /**
103
+ * The Krizaka default picture when the person has no photo (or it fails): their brand's gradient and a silhouette,
104
+ * one of six tones from `seed` — `defaultAvatar={{ brand: "orochia", seed: user.id }}`. `fallbackSrc` wins over it.
105
+ */
106
+ defaultAvatar?: DefaultAvatar;
107
+ /**
108
+ * xs · sm · md · lg · xl.
109
+ * @default "md"
110
+ */
111
+ size?: AvatarSize;
112
+ };
113
+
114
+ export type { AvatarProps as A, DefaultAvatar as D };
@@ -0,0 +1,27 @@
1
+ // src/glyphs.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function Glyph({ className = "h-4 w-4", fill, children }) {
4
+ return /* @__PURE__ */ jsx(
5
+ "svg",
6
+ {
7
+ viewBox: "0 0 24 24",
8
+ className,
9
+ fill: fill ? "currentColor" : "none",
10
+ stroke: fill ? "none" : "currentColor",
11
+ strokeWidth: "2",
12
+ strokeLinecap: "round",
13
+ strokeLinejoin: "round",
14
+ "aria-hidden": true,
15
+ focusable: "false",
16
+ children
17
+ }
18
+ );
19
+ }
20
+ 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] }) });
21
+ var CheckGlyph = (p) => /* @__PURE__ */ jsx(Glyph, { ...p, children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
22
+
23
+ export {
24
+ ChevronGlyph,
25
+ CheckGlyph
26
+ };
27
+ //# sourceMappingURL=chunk-3D2YI63L.js.map
@@ -0,0 +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;AA+CO,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;","names":[]}
@@ -0,0 +1,85 @@
1
+ // src/avatar/default-avatar.ts
2
+ var DEFAULT_AVATAR_TONES = 6;
3
+ var DEFAULT_AVATAR_BASE = "https://krizaka-assets.b-cdn.net/people/defaults/v1";
4
+ var clampTone = (tone) => Math.min(DEFAULT_AVATAR_TONES, Math.max(1, Math.round(tone)));
5
+ function defaultAvatarToneOf(seed) {
6
+ if (seed === void 0) return 1;
7
+ let h = 2166136261;
8
+ for (const ch of String(seed)) {
9
+ h ^= ch.codePointAt(0) ?? 0;
10
+ h = Math.imul(h, 16777619) >>> 0;
11
+ }
12
+ return h % DEFAULT_AVATAR_TONES + 1;
13
+ }
14
+ var resolveTone = (a) => a.tone === void 0 ? defaultAvatarToneOf(a.seed) : clampTone(a.tone);
15
+ function defaultAvatarFile(kind, tone, size) {
16
+ return size === "svg" ? `${kind}-${tone}.svg` : `${kind}-${tone}-${size}.webp`;
17
+ }
18
+ function trimTrailingSlashes(value) {
19
+ let end = value.length;
20
+ while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
21
+ return value.slice(0, end);
22
+ }
23
+ function defaultAvatarUrl(avatar2, { size = 256, base = DEFAULT_AVATAR_BASE } = {}) {
24
+ return `${trimTrailingSlashes(base)}/${avatar2.brand}/${defaultAvatarFile(avatar2.kind ?? "person", resolveTone(avatar2), size)}`;
25
+ }
26
+
27
+ // src/avatar/avatar.tsx
28
+ import { Avatar as AvatarPrimitive } from "radix-ui";
29
+ import * as React from "react";
30
+ import { tv } from "tailwind-variants";
31
+ import { jsx, jsxs } from "react/jsx-runtime";
32
+ var avatar = tv({
33
+ slots: {
34
+ root: "relative inline-flex shrink-0 overflow-hidden rounded-full bg-surface-3 align-middle",
35
+ image: "h-full w-full object-cover",
36
+ fallback: "flex h-full w-full items-center justify-center font-semibold uppercase text-fg-secondary",
37
+ group: "flex items-center -space-x-2 [&>*]:ring-2 [&>*]:ring-surface-0"
38
+ },
39
+ variants: {
40
+ size: {
41
+ xs: { root: "h-5 w-5 text-[9px]" },
42
+ sm: { root: "h-8 w-8 text-xs" },
43
+ md: { root: "h-10 w-10 text-sm" },
44
+ lg: { root: "h-14 w-14 text-base" },
45
+ xl: { root: "h-20 w-20 text-lg" }
46
+ }
47
+ },
48
+ defaultVariants: { size: "md" }
49
+ });
50
+ function AvatarRoot({ src, alt = "", fallback, fallbackSrc, defaultAvatar, size, className, ...props }) {
51
+ const s = avatar({ size });
52
+ const [failed, setFailed] = React.useState(null);
53
+ const backup = fallbackSrc ?? (defaultAvatar ? defaultAvatarUrl(defaultAvatar, { size: size === "xl" || size === "lg" ? 512 : 256 }) : void 0);
54
+ const shown = src && failed !== src ? src : backup;
55
+ return /* @__PURE__ */ jsxs(AvatarPrimitive.Root, { "data-size": size ?? "md", className: s.root({ className }), ...props, children: [
56
+ shown && /* @__PURE__ */ jsx(
57
+ AvatarPrimitive.Image,
58
+ {
59
+ src: shown,
60
+ alt,
61
+ className: s.image(),
62
+ onLoadingStatusChange: (status) => {
63
+ if (status === "error" && shown === src) setFailed(src);
64
+ }
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsx(AvatarPrimitive.Fallback, { delayMs: shown ? 300 : 0, className: s.fallback(), children: fallback })
68
+ ] });
69
+ }
70
+ function AvatarGroup({ max, size, className, children, ...props }) {
71
+ const items = React.Children.toArray(children);
72
+ const shown = max === void 0 ? items : items.slice(0, max);
73
+ const rest = items.length - shown.length;
74
+ return /* @__PURE__ */ jsxs("div", { className: avatar().group({ className }), ...props, children: [
75
+ shown,
76
+ rest > 0 && /* @__PURE__ */ jsx(AvatarRoot, { size, fallback: `+${rest}` })
77
+ ] });
78
+ }
79
+ var Avatar = Object.assign(AvatarRoot, { Group: AvatarGroup });
80
+
81
+ export {
82
+ defaultAvatarUrl,
83
+ Avatar
84
+ };
85
+ //# sourceMappingURL=chunk-3RVFD3UX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/avatar/default-avatar.ts","../src/avatar/avatar.tsx"],"sourcesContent":["// The default profile pictures of the Krizaka family: what a product shows when a person has no photo.\n// They are generated from this file (tools/export-brand.mjs renders them to SVG and WebP and uploads them to Bunny,\n// `people/defaults/v1/<brand>/…`), so the pictures and the URLs that name them cannot drift apart.\n\nexport type DefaultAvatarBrand = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\";\n/** `person`: a neutral silhouette. `plain`: the brand's gradient alone, ready for initials. */\nexport type DefaultAvatarKind = \"person\" | \"plain\";\nexport type DefaultAvatarSize = 256 | 512;\n\nexport const DEFAULT_AVATAR_BRANDS: readonly DefaultAvatarBrand[] = [\"krizaka\", \"orazaka\", \"orochia\", \"yasakia\", \"yororis\", \"yomizaka\", \"kachizaka\", \"akinaza\"];\nexport const DEFAULT_AVATAR_KINDS: readonly DefaultAvatarKind[] = [\"person\", \"plain\"];\nexport const DEFAULT_AVATAR_SIZES: readonly DefaultAvatarSize[] = [256, 512];\n/** How many tones each brand has: a person always gets the same one from their seed, so a list is not one colour. */\nexport const DEFAULT_AVATAR_TONES = 6;\n\n/** Where the set lives. `v1` is the set's version: a changed picture is a new version folder, never an overwrite. */\nexport const DEFAULT_AVATAR_BASE = \"https://krizaka-assets.b-cdn.net/people/defaults/v1\";\n\nexport interface DefaultAvatar {\n /** The brand of the product showing the avatar: its gradient, its hues. */\n brand: DefaultAvatarBrand;\n /** Any stable text or number of the person (their id): the same seed gives the same tone everywhere. */\n seed?: string | number;\n /** Force a tone, 1 to 6, instead of deriving it from `seed`. */\n tone?: number;\n /**\n * `person` (default): a silhouette. `plain`: the gradient alone.\n * @default \"person\"\n */\n kind?: DefaultAvatarKind;\n}\n\n/** The mark gradient of each brand (BRAND.md, `$extensions[\"com.krizaka\"].mark`) as [hue, saturation %, lightness %] and the hue spread of its tones. */\nconst BRANDS: Record<DefaultAvatarBrand, { from: [number, number, number]; to: [number, number, number]; spread: number }> = {\n krizaka: { from: [217, 92, 53], to: [217, 92, 68], spread: 14 },\n orazaka: { from: [26, 90.5, 37.1], to: [26, 92, 45], spread: 7 },\n orochia: { from: [262.1, 83.3, 57.8], to: [328.6, 85.5, 70.2], spread: 12 },\n yasakia: { from: [156, 92, 32], to: [178, 90, 32], spread: 12 },\n yororis: { from: [34, 46, 44], to: [104, 28, 42], spread: 10 },\n yomizaka: { from: [232, 50, 55], to: [248, 50, 58], spread: 10 },\n kachizaka: { from: [226, 80, 56], to: [44, 92, 33], spread: 10 },\n akinaza: { from: [140, 48, 34], to: [22, 60, 46], spread: 10 },\n};\n\n/** White on top of a stop must stay visible: a stop is darkened until the contrast reaches this (WCAG 1.4.11, non-text). */\nconst MIN_CONTRAST = 3.2;\nconst OFFSETS = [0, -1, 1, -2, 2, 3] as const;\n\nfunction hslToHex([h, s, l]: [number, number, number]): string {\n const sat = s / 100;\n const light = l / 100;\n const k = (n: number) => (n + (((h % 360) + 360) % 360) / 30) % 12;\n const a = sat * Math.min(light, 1 - light);\n const channel = (n: number) => Math.round(255 * (light - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)))));\n return `#${[0, 8, 4].map((n) => channel(n).toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\nconst channelLuminance = (v: number) => (v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4);\nconst whiteContrast = (hex: string) => {\n const [r, g, b] = [1, 3, 5].map((i) => channelLuminance(Number.parseInt(hex.slice(i, i + 2), 16) / 255));\n return 1.05 / (0.2126 * r! + 0.7152 * g! + 0.0722 * b! + 0.05);\n};\n/** The stop, darkened one point of lightness at a time until white reads on it. */\nfunction readable([h, s, l]: [number, number, number]): string {\n let hex = hslToHex([h, s, l]);\n for (let light = l; whiteContrast(hex) < MIN_CONTRAST && light > 10; light -= 1) hex = hslToHex([h, s, light]);\n return hex;\n}\n\n/** The two stops (hex) of tone `tone` (1 to 6) of a brand. */\nexport function defaultAvatarTone(brand: DefaultAvatarBrand, tone: number): readonly [string, string] {\n const b = BRANDS[brand];\n const o = OFFSETS[(clampTone(tone) - 1) % OFFSETS.length] * b.spread;\n return [readable([b.from[0] + o, b.from[1], b.from[2]]), readable([b.to[0] + o, b.to[1], b.to[2]])];\n}\n\nconst clampTone = (tone: number) => Math.min(DEFAULT_AVATAR_TONES, Math.max(1, Math.round(tone)));\n\n/** 1 to 6 from a seed (FNV-1a): stable across renders, devices and products. */\nexport function defaultAvatarToneOf(seed: string | number | undefined): number {\n if (seed === undefined) return 1;\n let h = 0x811c9dc5;\n for (const ch of String(seed)) {\n h ^= ch.codePointAt(0) ?? 0;\n h = Math.imul(h, 0x01000193) >>> 0;\n }\n return (h % DEFAULT_AVATAR_TONES) + 1;\n}\n\nconst resolveTone = (a: DefaultAvatar) => (a.tone === undefined ? defaultAvatarToneOf(a.seed) : clampTone(a.tone));\n\n/** The file name of a picture in the set: `person-3` + 256 → `person-3-256.webp`; `svg` has no size. */\nexport function defaultAvatarFile(kind: DefaultAvatarKind, tone: number, size: DefaultAvatarSize | \"svg\"): string {\n return size === \"svg\" ? `${kind}-${tone}.svg` : `${kind}-${tone}-${size}.webp`;\n}\n\n/** Linear on purpose: a `/\\/+$/` regex backtracks quadratically on a long run of slashes. */\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) end--;\n return value.slice(0, end);\n}\n\n/**\n * The URL of a default avatar: `defaultAvatarUrl({ brand: \"orochia\", seed: user.id })`.\n * @param size 256 for lists, 512 for a profile; `\"svg\"` for the vector.\n * @param base Another host or version of the set (a self-hosted copy); the default is the Krizaka CDN.\n */\nexport function defaultAvatarUrl(avatar: DefaultAvatar, { size = 256, base = DEFAULT_AVATAR_BASE }: { size?: DefaultAvatarSize | \"svg\"; base?: string } = {}): string {\n return `${trimTrailingSlashes(base)}/${avatar.brand}/${defaultAvatarFile(avatar.kind ?? \"person\", resolveTone(avatar), size)}`;\n}\n\n/** The SVG source of a default avatar, 512 × 512 and square (the Avatar clips it round). */\nexport function defaultAvatarSvg(avatar: DefaultAvatar): string {\n const [from, to] = defaultAvatarTone(avatar.brand, resolveTone(avatar));\n const person =\n (avatar.kind ?? \"person\") === \"person\"\n ? `<circle cx=\"256\" cy=\"200\" r=\"86\" fill=\"#fff\" fill-opacity=\".92\"/><path d=\"M84 512c0-108 78-182 172-182s172 74 172 182z\" fill=\"#fff\" fill-opacity=\".92\"/>`\n : \"\";\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" width=\"512\" height=\"512\"><defs><linearGradient id=\"g\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\"><stop offset=\"0\" stop-color=\"${from}\"/><stop offset=\"1\" stop-color=\"${to}\"/></linearGradient><radialGradient id=\"l\" cx=\".28\" cy=\".18\" r=\".85\"><stop offset=\"0\" stop-color=\"#fff\" stop-opacity=\".24\"/><stop offset=\"1\" stop-color=\"#fff\" stop-opacity=\"0\"/></radialGradient></defs><rect width=\"512\" height=\"512\" fill=\"url(#g)\"/><rect width=\"512\" height=\"512\" fill=\"url(#l)\"/>${person}</svg>`;\n}\n","// Client: Radix tracks the image's loading state and shows the fallback until it has loaded (or when it fails).\nimport { Avatar as AvatarPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { type DefaultAvatar, defaultAvatarUrl } from \"./default-avatar\";\n\nconst avatar = tv({\n slots: {\n root: \"relative inline-flex shrink-0 overflow-hidden rounded-full bg-surface-3 align-middle\",\n image: \"h-full w-full object-cover\",\n fallback: \"flex h-full w-full items-center justify-center font-semibold uppercase text-fg-secondary\",\n group: \"flex items-center -space-x-2 [&>*]:ring-2 [&>*]:ring-surface-0\",\n },\n variants: {\n size: {\n xs: { root: \"h-5 w-5 text-[9px]\" },\n sm: { root: \"h-8 w-8 text-xs\" },\n md: { root: \"h-10 w-10 text-sm\" },\n lg: { root: \"h-14 w-14 text-base\" },\n xl: { root: \"h-20 w-20 text-lg\" },\n },\n },\n defaultVariants: { size: \"md\" },\n});\n\nexport type AvatarSize = NonNullable<VariantProps<typeof avatar>[\"size\"]>;\n\nexport type AvatarProps = Omit<React.ComponentProps<\"span\">, \"children\"> & {\n /** The image's URL; `null` or nothing shows the `fallback`. */\n src?: string | null;\n /** The image's text alternative (the person's name); empty when a visible name sits next to the avatar. */\n alt?: string;\n /** Shown while the image loads, when it fails or when there is none: initials, an icon. */\n fallback?: React.ReactNode;\n /** The picture to show instead when `src` is missing or fails to load (an image URL). The `fallback` still covers its own loading. */\n fallbackSrc?: string;\n /**\n * The Krizaka default picture when the person has no photo (or it fails): their brand's gradient and a silhouette,\n * one of six tones from `seed` — `defaultAvatar={{ brand: \"orochia\", seed: user.id }}`. `fallbackSrc` wins over it.\n */\n defaultAvatar?: DefaultAvatar;\n /**\n * xs · sm · md · lg · xl.\n * @default \"md\"\n */\n size?: AvatarSize;\n};\n\nexport function AvatarRoot({ src, alt = \"\", fallback, fallbackSrc, defaultAvatar, size, className, ...props }: AvatarProps) {\n const s = avatar({ size });\n const [failed, setFailed] = React.useState<string | null>(null);\n // 512 px for the big sizes, 256 for the others: sharp on a 2x screen either way.\n const backup = fallbackSrc ?? (defaultAvatar ? defaultAvatarUrl(defaultAvatar, { size: size === \"xl\" || size === \"lg\" ? 512 : 256 }) : undefined);\n const shown = src && failed !== src ? src : backup;\n return (\n <AvatarPrimitive.Root data-size={size ?? \"md\"} className={s.root({ className })} {...props}>\n {shown && (\n <AvatarPrimitive.Image\n src={shown}\n alt={alt}\n className={s.image()}\n onLoadingStatusChange={(status) => {\n if (status === \"error\" && shown === src) setFailed(src);\n }}\n />\n )}\n <AvatarPrimitive.Fallback delayMs={shown ? 300 : 0} className={s.fallback()}>\n {fallback}\n </AvatarPrimitive.Fallback>\n </AvatarPrimitive.Root>\n );\n}\n\nexport type AvatarGroupProps = React.ComponentProps<\"div\"> & {\n /** How many avatars are shown; the rest becomes a `+n` avatar. */\n max?: number;\n /** The size of the `+n` avatar (match the avatars of the group). */\n size?: AvatarSize;\n};\n\n/** Overlapping avatars; past `max`, a `+n` avatar counts the rest. */\nexport function AvatarGroup({ max, size, className, children, ...props }: AvatarGroupProps) {\n const items = React.Children.toArray(children);\n const shown = max === undefined ? items : items.slice(0, max);\n const rest = items.length - shown.length;\n return (\n <div className={avatar().group({ className })} {...props}>\n {shown}\n {rest > 0 && <AvatarRoot size={size} fallback={`+${rest}`} />}\n </div>\n );\n}\n\n/** `Avatar` (an image with a fallback) and `Avatar.Group`. */\nexport const Avatar = Object.assign(AvatarRoot, { Group: AvatarGroup });\n"],"mappings":"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","names":["avatar"]}
@@ -0,0 +1,22 @@
1
+ // src/cn.ts
2
+ import { clsx } from "clsx";
3
+ import { cnMerge } from "tailwind-variants";
4
+ var twMergeConfig = {
5
+ extend: {
6
+ classGroups: {
7
+ "bg-image": ["bg-sheen", "bg-fill-shade", "bg-halo"],
8
+ shadow: ["shadow-raised", "shadow-floating", "shadow-overlay", "shadow-glow", "shadow-glow-lg"],
9
+ "inset-shadow": ["inset-shadow-edge", "inset-shadow-edge-fill", "inset-shadow-well"]
10
+ }
11
+ }
12
+ };
13
+ var mergeConfig = { twMergeConfig };
14
+ function cn(...inputs) {
15
+ return cnMerge(clsx(inputs))(mergeConfig) ?? "";
16
+ }
17
+
18
+ export {
19
+ twMergeConfig,
20
+ cn
21
+ };
22
+ //# sourceMappingURL=chunk-S6NYGOJT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cn.ts"],"sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { cnMerge, type TWMergeConfig } from \"tailwind-variants\";\n\nexport type { ClassValue };\n\n/**\n * The preset's own utilities, told to the merge engine: the material (BRAND.md §6: `bg-sheen`, `bg-fill-shade`,\n * `bg-halo` are background images; `shadow-raised` · `-floating` · `-overlay` · `-glow` are shadows; `inset-shadow-edge`\n * · `-edge-fill` · `-well` are inset shadows). Unknown, tailwind-merge would take `bg-sheen` for a colour and drop the\n * `bg-surface-2` it lies on.\n */\nexport const twMergeConfig: TWMergeConfig = {\n extend: {\n classGroups: {\n \"bg-image\": [\"bg-sheen\", \"bg-fill-shade\", \"bg-halo\"],\n shadow: [\"shadow-raised\", \"shadow-floating\", \"shadow-overlay\", \"shadow-glow\", \"shadow-glow-lg\"],\n \"inset-shadow\": [\"inset-shadow-edge\", \"inset-shadow-edge-fill\", \"inset-shadow-well\"],\n },\n },\n};\n\nconst mergeConfig = { twMergeConfig };\n\n/**\n * Merges Tailwind classes: the last one wins — a product's `className` overrides the primitive's. The merge engine is\n * tailwind-merge as tailwind-variants ships it (the one `tv` uses), so the platform carries a single copy of it.\n * tailwind-variants bundles that engine since 3.3 (it never imports the `tailwind-merge` package, an optional peer):\n * hence `tailwind-variants ^3.3.1` and no `tailwind-merge` dependency — `scripts/consumer.mjs` checks it on a clean\n * install of the packed package.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return cnMerge(clsx(inputs))(mergeConfig) ?? \"\";\n}\n\n"],"mappings":";AAAA,SAA0B,YAAY;AACtC,SAAS,eAAmC;AAUrC,IAAM,gBAA+B;AAAA,EAC1C,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,YAAY,CAAC,YAAY,iBAAiB,SAAS;AAAA,MACnD,QAAQ,CAAC,iBAAiB,mBAAmB,kBAAkB,eAAe,gBAAgB;AAAA,MAC9F,gBAAgB,CAAC,qBAAqB,0BAA0B,mBAAmB;AAAA,IACrF;AAAA,EACF;AACF;AAEA,IAAM,cAAc,EAAE,cAAc;AAS7B,SAAS,MAAM,QAA8B;AAClD,SAAO,QAAQ,KAAK,MAAM,CAAC,EAAE,WAAW,KAAK;AAC/C;","names":[]}
@@ -1,29 +1,10 @@
1
+ import {
2
+ ChevronGlyph
3
+ } from "./chunk-3D2YI63L.js";
4
+
1
5
  // src/docs-layout/docs-layout.tsx
2
6
  import { tv } from "tailwind-variants";
3
-
4
- // src/glyphs.tsx
5
7
  import { jsx, jsxs } from "react/jsx-runtime";
6
- function Glyph({ className = "h-4 w-4", fill, children }) {
7
- return /* @__PURE__ */ jsx(
8
- "svg",
9
- {
10
- viewBox: "0 0 24 24",
11
- className,
12
- fill: fill ? "currentColor" : "none",
13
- stroke: fill ? "none" : "currentColor",
14
- strokeWidth: "2",
15
- strokeLinecap: "round",
16
- strokeLinejoin: "round",
17
- "aria-hidden": true,
18
- focusable: "false",
19
- children
20
- }
21
- );
22
- }
23
- 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] }) });
24
-
25
- // src/docs-layout/docs-layout.tsx
26
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
27
8
  var docsLayout = tv({
28
9
  slots: {
29
10
  root: "mx-auto grid w-full max-w-[calc(var(--kz-page-max-docs,88rem)+2*var(--kz-page-gutter,24px))] grid-cols-1 gap-8 px-(--kz-page-gutter,16px) pt-(--kz-hero-top,6rem) pb-16 lg:grid-cols-[15rem_minmax(0,1fr)] xl:grid-cols-[15rem_minmax(0,1fr)_13rem]",
@@ -37,20 +18,20 @@ var docsLayout = tv({
37
18
  });
38
19
  var s = docsLayout();
39
20
  function DocsLayout({ sidebar, sidebarLabel, toc, className, children, ...props }) {
40
- return /* @__PURE__ */ jsxs2("div", { className: s.root({ className }), ...props, children: [
41
- /* @__PURE__ */ jsx2("div", { className: s.sidebar(), children: sidebar }),
42
- /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 flex-col gap-6", children: [
43
- /* @__PURE__ */ jsxs2("details", { className: s.mobileNav(), children: [
44
- /* @__PURE__ */ jsxs2("summary", { className: s.mobileSummary(), children: [
21
+ return /* @__PURE__ */ jsxs("div", { className: s.root({ className }), ...props, children: [
22
+ /* @__PURE__ */ jsx("div", { className: s.sidebar(), children: sidebar }),
23
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-6", children: [
24
+ /* @__PURE__ */ jsxs("details", { className: s.mobileNav(), children: [
25
+ /* @__PURE__ */ jsxs("summary", { className: s.mobileSummary(), children: [
45
26
  sidebarLabel,
46
27
  " ",
47
- /* @__PURE__ */ jsx2(ChevronGlyph, { className: "h-4 w-4 transition-transform motion-reduce:transition-none" })
28
+ /* @__PURE__ */ jsx(ChevronGlyph, { className: "h-4 w-4 transition-transform motion-reduce:transition-none" })
48
29
  ] }),
49
- /* @__PURE__ */ jsx2("div", { className: s.mobileBody(), children: sidebar })
30
+ /* @__PURE__ */ jsx("div", { className: s.mobileBody(), children: sidebar })
50
31
  ] }),
51
- /* @__PURE__ */ jsx2("article", { className: s.article(), children })
32
+ /* @__PURE__ */ jsx("article", { className: s.article(), children })
52
33
  ] }),
53
- toc && /* @__PURE__ */ jsx2("div", { className: s.toc(), children: toc })
34
+ toc && /* @__PURE__ */ jsx("div", { className: s.toc(), children: toc })
54
35
  ] });
55
36
  }
56
37
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/docs-layout/docs-layout.tsx","../src/glyphs.tsx"],"sourcesContent":["// Server-safe. A documentation page in the site's frame (--kz-page-max-docs): the sidebar of pages, the article, the\n// table of contents — the three columns of the frame on a wide screen, the sidebar folded into a disclosure above the\n// article on a phone, the contents under the title as chips (a `Toc`). Its edges are the bar's: no column runs to the\n// window's edge.\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { ChevronGlyph } from \"../glyphs\";\n\nexport const docsLayout = tv({\n slots: {\n root:\n \"mx-auto grid w-full max-w-[calc(var(--kz-page-max-docs,88rem)+2*var(--kz-page-gutter,24px))] grid-cols-1 gap-8 px-(--kz-page-gutter,16px) \" +\n \"pt-(--kz-hero-top,6rem) pb-16 lg:grid-cols-[15rem_minmax(0,1fr)] xl:grid-cols-[15rem_minmax(0,1fr)_13rem]\",\n sidebar: \"hidden lg:block lg:sticky lg:top-24 lg:max-h-[calc(100dvh-7rem)] lg:self-start lg:overflow-y-auto\",\n mobileNav: \"rounded-xl border border-border-default bg-surface-1 lg:hidden\",\n mobileSummary:\n \"flex min-h-11 cursor-pointer list-none items-center justify-between gap-2 px-4 text-sm font-semibold text-fg [&::-webkit-details-marker]:hidden \" +\n \"rounded-xl focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring [[open]>&>svg]:rotate-180\",\n mobileBody: \"border-t border-border-subtle px-2 py-2\",\n article: \"min-w-0 max-w-3xl\",\n toc: \"hidden xl:block xl:sticky xl:top-24 xl:self-start\",\n },\n});\nconst s = docsLayout();\n\nexport type DocsLayoutProps = React.ComponentProps<\"div\"> & {\n /** The pages of the documentation (a nav of links, grouped). */\n sidebar: React.ReactNode;\n /** On a phone the sidebar is folded: the words that open it (`Pages of the documentation`). */\n sidebarLabel: string;\n /** The page's table of contents (a `Toc` of @krizaka/ui/toc): beside the article from `xl`. */\n toc?: React.ReactNode;\n /** The article: its title, its body. */\n children: React.ReactNode;\n};\n\n/** A documentation page: pages · article · contents, in the site's frame. */\nexport function DocsLayout({ sidebar, sidebarLabel, toc, className, children, ...props }: DocsLayoutProps) {\n return (\n <div className={s.root({ className })} {...props}>\n <div className={s.sidebar()}>{sidebar}</div>\n <div className=\"flex min-w-0 flex-col gap-6\">\n <details className={s.mobileNav()}>\n <summary className={s.mobileSummary()}>\n {sidebarLabel} <ChevronGlyph className=\"h-4 w-4 transition-transform motion-reduce:transition-none\" />\n </summary>\n <div className={s.mobileBody()}>{sidebar}</div>\n </details>\n <article className={s.article()}>{children}</article>\n </div>\n {toc && <div className={s.toc()}>{toc}</div>}\n </div>\n );\n}\n","// 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":";AAKA,SAAS,UAAU;;;ACIf,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;AA+CO,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;;;ADhCI,gBAAAA,MAGI,QAAAC,aAHJ;AAhCC,IAAM,aAAa,GAAG;AAAA,EAC3B,OAAO;AAAA,IACL,MACE;AAAA,IAEF,SAAS;AAAA,IACT,WAAW;AAAA,IACX,eACE;AAAA,IAEF,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AACF,CAAC;AACD,IAAM,IAAI,WAAW;AAcd,SAAS,WAAW,EAAE,SAAS,cAAc,KAAK,WAAW,UAAU,GAAG,MAAM,GAAoB;AACzG,SACE,gBAAAA,MAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACzC;AAAA,oBAAAD,KAAC,SAAI,WAAW,EAAE,QAAQ,GAAI,mBAAQ;AAAA,IACtC,gBAAAC,MAAC,SAAI,WAAU,+BACb;AAAA,sBAAAA,MAAC,aAAQ,WAAW,EAAE,UAAU,GAC9B;AAAA,wBAAAA,MAAC,aAAQ,WAAW,EAAE,cAAc,GACjC;AAAA;AAAA,UAAa;AAAA,UAAC,gBAAAD,KAAC,gBAAa,WAAU,8DAA6D;AAAA,WACtG;AAAA,QACA,gBAAAA,KAAC,SAAI,WAAW,EAAE,WAAW,GAAI,mBAAQ;AAAA,SAC3C;AAAA,MACA,gBAAAA,KAAC,aAAQ,WAAW,EAAE,QAAQ,GAAI,UAAS;AAAA,OAC7C;AAAA,IACC,OAAO,gBAAAA,KAAC,SAAI,WAAW,EAAE,IAAI,GAAI,eAAI;AAAA,KACxC;AAEJ;","names":["jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/docs-layout/docs-layout.tsx"],"sourcesContent":["// Server-safe. A documentation page in the site's frame (--kz-page-max-docs): the sidebar of pages, the article, the\n// table of contents — the three columns of the frame on a wide screen, the sidebar folded into a disclosure above the\n// article on a phone, the contents under the title as chips (a `Toc`). Its edges are the bar's: no column runs to the\n// window's edge.\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { ChevronGlyph } from \"../glyphs\";\n\nexport const docsLayout = tv({\n slots: {\n root:\n \"mx-auto grid w-full max-w-[calc(var(--kz-page-max-docs,88rem)+2*var(--kz-page-gutter,24px))] grid-cols-1 gap-8 px-(--kz-page-gutter,16px) \" +\n \"pt-(--kz-hero-top,6rem) pb-16 lg:grid-cols-[15rem_minmax(0,1fr)] xl:grid-cols-[15rem_minmax(0,1fr)_13rem]\",\n sidebar: \"hidden lg:block lg:sticky lg:top-24 lg:max-h-[calc(100dvh-7rem)] lg:self-start lg:overflow-y-auto\",\n mobileNav: \"rounded-xl border border-border-default bg-surface-1 lg:hidden\",\n mobileSummary:\n \"flex min-h-11 cursor-pointer list-none items-center justify-between gap-2 px-4 text-sm font-semibold text-fg [&::-webkit-details-marker]:hidden \" +\n \"rounded-xl focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring [[open]>&>svg]:rotate-180\",\n mobileBody: \"border-t border-border-subtle px-2 py-2\",\n article: \"min-w-0 max-w-3xl\",\n toc: \"hidden xl:block xl:sticky xl:top-24 xl:self-start\",\n },\n});\nconst s = docsLayout();\n\nexport type DocsLayoutProps = React.ComponentProps<\"div\"> & {\n /** The pages of the documentation (a nav of links, grouped). */\n sidebar: React.ReactNode;\n /** On a phone the sidebar is folded: the words that open it (`Pages of the documentation`). */\n sidebarLabel: string;\n /** The page's table of contents (a `Toc` of @krizaka/ui/toc): beside the article from `xl`. */\n toc?: React.ReactNode;\n /** The article: its title, its body. */\n children: React.ReactNode;\n};\n\n/** A documentation page: pages · article · contents, in the site's frame. */\nexport function DocsLayout({ sidebar, sidebarLabel, toc, className, children, ...props }: DocsLayoutProps) {\n return (\n <div className={s.root({ className })} {...props}>\n <div className={s.sidebar()}>{sidebar}</div>\n <div className=\"flex min-w-0 flex-col gap-6\">\n <details className={s.mobileNav()}>\n <summary className={s.mobileSummary()}>\n {sidebarLabel} <ChevronGlyph className=\"h-4 w-4 transition-transform motion-reduce:transition-none\" />\n </summary>\n <div className={s.mobileBody()}>{sidebar}</div>\n </details>\n <article className={s.article()}>{children}</article>\n </div>\n {toc && <div className={s.toc()}>{toc}</div>}\n </div>\n );\n}\n"],"mappings":";;;;;AAKA,SAAS,UAAU;AAoCb,cAGI,YAHJ;AAhCC,IAAM,aAAa,GAAG;AAAA,EAC3B,OAAO;AAAA,IACL,MACE;AAAA,IAEF,SAAS;AAAA,IACT,WAAW;AAAA,IACX,eACE;AAAA,IAEF,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,KAAK;AAAA,EACP;AACF,CAAC;AACD,IAAM,IAAI,WAAW;AAcd,SAAS,WAAW,EAAE,SAAS,cAAc,KAAK,WAAW,UAAU,GAAG,MAAM,GAAoB;AACzG,SACE,qBAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACzC;AAAA,wBAAC,SAAI,WAAW,EAAE,QAAQ,GAAI,mBAAQ;AAAA,IACtC,qBAAC,SAAI,WAAU,+BACb;AAAA,2BAAC,aAAQ,WAAW,EAAE,UAAU,GAC9B;AAAA,6BAAC,aAAQ,WAAW,EAAE,cAAc,GACjC;AAAA;AAAA,UAAa;AAAA,UAAC,oBAAC,gBAAa,WAAU,8DAA6D;AAAA,WACtG;AAAA,QACA,oBAAC,SAAI,WAAW,EAAE,WAAW,GAAI,mBAAQ;AAAA,SAC3C;AAAA,MACA,oBAAC,aAAQ,WAAW,EAAE,QAAQ,GAAI,UAAS;AAAA,OAC7C;AAAA,IACC,OAAO,oBAAC,SAAI,WAAW,EAAE,IAAI,GAAI,eAAI;AAAA,KACxC;AAEJ;","names":[]}
package/dist/docs-nav.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  cn
3
- } from "./chunk-KH3JOEPY.js";
3
+ } from "./chunk-S6NYGOJT.js";
4
4
 
5
5
  // src/docs-nav/docs-nav.tsx
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+
3
+ /** True while the drag carries files (not text or a link): the only drag that should raise the overlay. */
4
+ declare function dragHasFiles(transfer: {
5
+ types?: readonly string[] | DOMStringList;
6
+ } | null | undefined): boolean;
7
+ /** One accepted kind: a MIME type (`application/pdf`), a family (`image/*`) or an extension (`.pdf`). */
8
+ type AcceptRule = string;
9
+ interface DropSplit<F> {
10
+ accepted: F[];
11
+ rejected: F[];
12
+ }
13
+ /** Splits dropped files by `accept` (no rule: everything is accepted). */
14
+ declare function splitDropped<F extends Pick<File, "name" | "type">>(files: readonly F[], accept?: readonly AcceptRule[]): DropSplit<F>;
15
+
16
+ type DropOverlayProps = Omit<React.ComponentProps<"div">, "children" | "onDrop"> & {
17
+ /** What the overlay says (“Drop to check”) — passed translated. */
18
+ label: string;
19
+ /** One line under it (“PDF or text”). */
20
+ hint?: string;
21
+ /** The files dropped: the accepted ones, then the ones `accept` refused. */
22
+ onFiles: (accepted: File[], rejected: File[]) => void;
23
+ /** What is accepted: MIME types, families (`image/*`) or extensions (`.pdf`). */
24
+ accept?: readonly AcceptRule[];
25
+ /** Turns the window back into a plain page (while a modal is open, signed out). */
26
+ disabled?: boolean;
27
+ };
28
+ /** Drag a file anywhere on the page: a full-window overlay accepts it. */
29
+ declare function DropOverlay({ label, hint, onFiles, accept, disabled, className, ...props }: DropOverlayProps): React.JSX.Element | null;
30
+
31
+ export { type AcceptRule, DropOverlay, type DropOverlayProps, type DropSplit, dragHasFiles, splitDropped };