@krizaka/ui 3.27.0 → 3.29.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 (189) hide show
  1. package/README.md +3 -0
  2. package/dist/blocks.css +2 -0
  3. package/dist/chip-link.js +4 -27
  4. package/dist/chip-link.js.map +1 -1
  5. package/dist/chip-row.d.ts +78 -0
  6. package/dist/chip-row.js +61 -0
  7. package/dist/chip-row.js.map +1 -0
  8. package/dist/chunk-BTTDIVVJ.js +33 -0
  9. package/dist/chunk-BTTDIVVJ.js.map +1 -0
  10. package/dist/docs-hub-page.d.ts +7 -1
  11. package/dist/docs-hub-page.js +2 -2
  12. package/dist/docs-hub-page.js.map +1 -1
  13. package/dist/engine-flow.d.ts +97 -0
  14. package/dist/engine-flow.js +214 -0
  15. package/dist/engine-flow.js.map +1 -0
  16. package/dist/motion.css +121 -1
  17. package/dist/native.d.ts +52 -5
  18. package/dist/native.js +409 -318
  19. package/dist/native.js.map +1 -1
  20. package/package.json +34 -6
  21. package/registry/account-menu.json +1 -1
  22. package/registry/achievement.json +1 -1
  23. package/registry/action-bar.json +1 -1
  24. package/registry/activity-feed.json +1 -1
  25. package/registry/alert.json +1 -1
  26. package/registry/app-header.json +1 -1
  27. package/registry/app-shell.json +1 -1
  28. package/registry/argument-card.json +1 -1
  29. package/registry/audio-player.json +1 -1
  30. package/registry/auth-layout.json +1 -1
  31. package/registry/avatar.json +1 -1
  32. package/registry/badge.json +1 -1
  33. package/registry/button.json +1 -1
  34. package/registry/captcha.json +1 -1
  35. package/registry/card-grid.json +1 -1
  36. package/registry/card.json +1 -1
  37. package/registry/catalogue-page.json +1 -1
  38. package/registry/changelog-page.json +1 -1
  39. package/registry/chat.json +55 -8
  40. package/registry/checkbox.json +1 -1
  41. package/registry/chip-link.json +1 -1
  42. package/registry/chip-row.json +173 -0
  43. package/registry/chip.json +1 -1
  44. package/registry/choice-grid.json +1 -1
  45. package/registry/code-block.json +1 -1
  46. package/registry/combobox.json +1 -1
  47. package/registry/command.json +1 -1
  48. package/registry/comparison-table.json +1 -1
  49. package/registry/component-page.json +1 -1
  50. package/registry/confirm-button.json +1 -1
  51. package/registry/contact-page.json +1 -1
  52. package/registry/continue-prompt.json +1 -1
  53. package/registry/countdown.json +1 -1
  54. package/registry/cover-hero.json +1 -1
  55. package/registry/cta-panel.json +1 -1
  56. package/registry/dashboard-layout.json +1 -1
  57. package/registry/data-table.json +1 -1
  58. package/registry/date-picker.json +1 -1
  59. package/registry/decision-list.json +1 -1
  60. package/registry/description-list.json +1 -1
  61. package/registry/detail-layout.json +1 -1
  62. package/registry/dialog.json +1 -1
  63. package/registry/docs-article-page.json +1 -1
  64. package/registry/docs-hub-page.json +16 -2
  65. package/registry/docs-layout.json +1 -1
  66. package/registry/docs-nav.json +1 -1
  67. package/registry/document-viewer.json +1 -1
  68. package/registry/dropdown-menu.json +1 -1
  69. package/registry/empty-state.json +1 -1
  70. package/registry/engine-flow.json +280 -0
  71. package/registry/error-page.json +1 -1
  72. package/registry/examples/chat/native/assistant.d.ts +4 -0
  73. package/registry/examples/chat/native/assistant.dark.png +0 -0
  74. package/registry/examples/chat/native/assistant.js +32 -0
  75. package/registry/examples/chat/native/assistant.light.png +0 -0
  76. package/registry/examples/chat/native/assistant.tsx +28 -0
  77. package/registry/examples/chip-row/audience.d.ts +4 -0
  78. package/registry/examples/chip-row/audience.js +15 -0
  79. package/registry/examples/chip-row/audience.tsx +16 -0
  80. package/registry/examples/chip-row/many.d.ts +4 -0
  81. package/registry/examples/chip-row/many.js +12 -0
  82. package/registry/examples/chip-row/many.tsx +16 -0
  83. package/registry/examples/engine-flow/compact.d.ts +4 -0
  84. package/registry/examples/engine-flow/compact.js +33 -0
  85. package/registry/examples/engine-flow/compact.tsx +30 -0
  86. package/registry/examples/engine-flow/radial.d.ts +4 -0
  87. package/registry/examples/engine-flow/radial.js +37 -0
  88. package/registry/examples/engine-flow/radial.tsx +32 -0
  89. package/registry/examples/settings-layout/native/account.d.ts +4 -0
  90. package/registry/examples/settings-layout/native/account.dark.png +0 -0
  91. package/registry/examples/settings-layout/native/account.js +22 -0
  92. package/registry/examples/settings-layout/native/account.light.png +0 -0
  93. package/registry/examples/settings-layout/native/account.tsx +18 -0
  94. package/registry/field.json +1 -1
  95. package/registry/file-upload.json +1 -1
  96. package/registry/filter-bar.json +1 -1
  97. package/registry/force-update-screen.json +1 -1
  98. package/registry/form.json +1 -1
  99. package/registry/gallery-page.json +1 -1
  100. package/registry/genui.json +1 -1
  101. package/registry/glow-card.json +1 -1
  102. package/registry/goal-gauge.json +1 -1
  103. package/registry/how-it-works-page.json +1 -1
  104. package/registry/image-cropper.json +1 -1
  105. package/registry/index.json +74 -11
  106. package/registry/iso.json +3 -3
  107. package/registry/kanban.json +1 -1
  108. package/registry/kbd.json +1 -1
  109. package/registry/landing-page.json +1 -1
  110. package/registry/landscape.json +1 -1
  111. package/registry/language-switch.json +1 -1
  112. package/registry/legal-page.json +1 -1
  113. package/registry/link-card.json +1 -1
  114. package/registry/list.json +1 -1
  115. package/registry/loader.json +1 -1
  116. package/registry/longform-page.json +1 -1
  117. package/registry/maintenance-screen.json +1 -1
  118. package/registry/map.json +2 -2
  119. package/registry/markdown.json +1 -1
  120. package/registry/marketing-layout.json +1 -1
  121. package/registry/marquee.json +1 -1
  122. package/registry/mascot-quote.json +1 -1
  123. package/registry/mascot-state.json +1 -1
  124. package/registry/mascots.json +1 -1
  125. package/registry/match-dialog.json +1 -1
  126. package/registry/media-capture.json +1 -1
  127. package/registry/media-gallery.json +1 -1
  128. package/registry/media-grid.json +1 -1
  129. package/registry/meta-row.json +1 -1
  130. package/registry/meter.json +1 -1
  131. package/registry/nav-bar.json +2 -2
  132. package/registry/number-ticker.json +1 -1
  133. package/registry/opening-hours.json +1 -1
  134. package/registry/page-header.json +1 -1
  135. package/registry/page-hero.json +1 -1
  136. package/registry/page.json +1 -1
  137. package/registry/pagination.json +1 -1
  138. package/registry/photo-grid.json +1 -1
  139. package/registry/pointer-light.json +1 -1
  140. package/registry/popover.json +1 -1
  141. package/registry/pricing-page.json +1 -1
  142. package/registry/product-page.json +1 -1
  143. package/registry/profile-card.json +1 -1
  144. package/registry/progress.json +1 -1
  145. package/registry/promise-card.json +1 -1
  146. package/registry/radio-group.json +1 -1
  147. package/registry/rail-nav.json +2 -2
  148. package/registry/recipes.json +1 -1
  149. package/registry/scroll-stage.json +1 -1
  150. package/registry/search-field.json +1 -1
  151. package/registry/section-backdrop.json +1 -1
  152. package/registry/separator.json +1 -1
  153. package/registry/service-card.json +1 -1
  154. package/registry/settings-layout.json +110 -7
  155. package/registry/showcase.json +1 -1
  156. package/registry/site-footer.json +2 -2
  157. package/registry/sites.json +1 -1
  158. package/registry/skeleton.json +1 -1
  159. package/registry/skip-link.json +1 -1
  160. package/registry/slider.json +1 -1
  161. package/registry/slot-picker.json +1 -1
  162. package/registry/slot.json +1 -1
  163. package/registry/spinner.json +1 -1
  164. package/registry/split-view.json +1 -1
  165. package/registry/stage-banner.json +1 -1
  166. package/registry/stat.json +1 -1
  167. package/registry/status-page.json +1 -1
  168. package/registry/step-progress.json +1 -1
  169. package/registry/step-showcase.json +1 -1
  170. package/registry/stepper.json +1 -1
  171. package/registry/sticky-action.json +1 -1
  172. package/registry/swipe-deck.json +1 -1
  173. package/registry/switch.json +1 -1
  174. package/registry/tabs.json +1 -1
  175. package/registry/tag-input.json +1 -1
  176. package/registry/tag-selector.json +1 -1
  177. package/registry/terminal-replay.json +1 -1
  178. package/registry/theme.json +1 -1
  179. package/registry/toast.json +1 -1
  180. package/registry/toc.json +1 -1
  181. package/registry/tooltip.json +1 -1
  182. package/registry/tree-view.json +1 -1
  183. package/registry/update-prompt.json +1 -1
  184. package/registry/verified-badge.json +1 -1
  185. package/registry/vertical-video.json +1 -1
  186. package/registry/video-player.json +1 -1
  187. package/registry/video-trimmer.json +1 -1
  188. package/registry/virtual.json +1 -1
  189. package/registry/waveform.json +1 -1
package/README.md CHANGED
@@ -153,6 +153,7 @@ light or a product's — is a set of tokens.
153
153
  | `@krizaka/ui/site-footer` | `SiteFooter` (`current`, `labels`, `version`, `env`, `legal`; own columns as children) `.Column` (`title`) `.Link` (`active`, `asChild`): the footer of every Krizaka site — the family in columns, “A Krizaka company / product / open-source project”, the version, Montréal | client |
154
154
  | `@krizaka/ui/chip` | `Chip` (`selected`/`defaultSelected` + `onSelectedChange`, `size` sm·md; `removable` + `removeLabel` + `onRemove`), `Chip.Group` (`type` single·multiple, `label`, `required` for single), `chip` (the slots) | client |
155
155
  | `@krizaka/ui/chip-link` | `ChipLink` (a filter that is a link: `selected`, `current`, `size`, `asChild`), `chipVariants` (`size`, `selected`) | server |
156
+ | `@krizaka/ui/chip-row` | `ChipRow`, `ChipRow.Item` (a scroll-snap row of chip links, wraps from `md`: `selected`, `badge`, `asChild`) | client (arrow keys) |
156
157
  | `@krizaka/ui/meta-row` | `MetaRow` (`items`, `chips`, `size` sm·md): one quiet line of dot-separated facts with status chips at its end; a real list, dots hidden from assistive technology; `/native` has the same | server |
157
158
  | `@krizaka/ui/switch` | `Switch` (`checked`/`defaultChecked` + `onCheckedChange`, `label` unless a visible label names it, `size` sm·md, `invalid`), `switchVariants` | client |
158
159
  | `@krizaka/ui/slider` | `Slider` (`value`: a number or a `[min, max]` range, `onValueChange`, `onValueCommit`, `label`, `thumbLabels`, `formatValue` → aria-valuetext, `showLabel`, `origin`), `slider` (the slots) | client |
@@ -175,6 +176,7 @@ light or a product's — is a set of tokens.
175
176
  | `@krizaka/ui/achievement` | `Achievement` (`title`, `eyebrow`, `badge`, `replaced`, `locked`), `AchievementList`, `Emblem` (`sword` · `mirror` · `jewel`) | server |
176
177
  | `@krizaka/ui/landscape` | `Landscape` (`tone` own · brand, `flock`, `phoenix`, `animated`, `position`, `fade`): the Krizaka valley at dusk, decorative | client |
177
178
  | `@krizaka/ui/glow-card` | `GlowCard` (`glow` border·spotlight·both, `alive`, `asChild`) | client |
179
+ | `@krizaka/ui/engine-flow` | `EngineFlow` (`label`, `hub`, `nodes` with `flow` in·out·both, `planned`, `status`, `description`, `href`; `layout` radial·top-to-bottom·left-to-right, `compactLayout` under 560 px, `particles`, `conduit` bezier·straight, `hint`, `speed`): an engine and the apps it serves, photons along SVG conduits (motion.css), no animation frame | client |
178
180
  | `@krizaka/ui/marquee` | `Marquee` (`label`, `pauseLabel`, `playLabel`, `speed` px/s, `direction`, `fade`, `defaultPaused`) | client |
179
181
  | `@krizaka/ui/section-backdrop` | `SectionBackdrop` (`as`, `direction` down·up, `dome`, `grid`, `media` blurred for depth of field, `animated`): a page section on the brand's section gradient — see `@krizaka/tokens` BRAND.md, "Visual language" | server |
180
182
  | `@krizaka/ui/mascots` | `Mascot` (`bird` falcon·owl·duck·flamingo·pigeon·lovebird·crane, `mood` welcome·thinking·success·empty·error, `tone` brand·own, `size`, `animated`, `title`), `MASCOT_BIRDS`, `MASCOT_MOODS`: the Krizaka flock, in the host brand's accent — one bird at a moment that matters (onboarding, a long wait, a success, an empty list, an error); native `Mascot` in `/native` | client |
@@ -494,6 +496,7 @@ import { MotionObserver, RotatingWord } from "@krizaka/ui";
494
496
  | `kz-spotlight` | A soft bloom following the pointer across a card |
495
497
  | `kz-lift` | A card rising under the pointer |
496
498
  | `kz-gradient-text`, `kz-marquee` | Drifting gradient text, endless bands |
499
+ | `kz-flow` | EngineFlow's conduits and photons: paused off screen, held while settling, still under reduced motion |
497
500
  | `kz-overlay`, `kz-dialog`, `kz-pop`, `kz-fade` | Backdrops, dialogs (from the bottom on phones), menus, views swapped in place |
498
501
  | `kz-progress` | The indeterminate progress bar's travelling segment |
499
502
  | `kz-backdrop`, `kz-backdrop-drift`, `-dome`, `-grid`, `-media` | The layers of `SectionBackdrop`: the brand's section gradient, the slow light drift (40 s), the dome, the perspective grid, the blurred foreground |
package/dist/blocks.css CHANGED
@@ -708,6 +708,8 @@ a.kz-fact:focus-visible { outline: 2px solid var(--kz-ring, var(--kz-accent)); o
708
708
  border-top: 1px solid var(--kz-border-subtle); }
709
709
  .kz-tpl-collection ul a { display: inline-flex; min-height: 28px; align-items: center; padding: 0 10px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
710
710
  text-decoration: none; color: var(--kz-text-primary); background: var(--kz-surface-2); border: 1px solid var(--kz-border-subtle); }
711
+ .kz-tpl-collection[data-links="stack"] ul { display: grid; justify-items: start; }
712
+ .kz-tpl-collection[data-links="stack"] ul a { max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
711
713
  .kz-tpl-collection ul a:hover { border-color: var(--kz-accent); }
712
714
  .kz-tpl-collection ul a:focus-visible { outline: 2px solid var(--kz-ring, var(--kz-accent)); outline-offset: 2px; }
713
715
  @media (hover: hover) and (prefers-reduced-motion: no-preference) {
package/dist/chip-link.js CHANGED
@@ -1,30 +1,7 @@
1
- // src/chip-link/chip-link.tsx
2
- import { Slot } from "radix-ui";
3
- import { tv } from "tailwind-variants";
4
- import { jsx } from "react/jsx-runtime";
5
- var chipVariants = tv({
6
- base: "inline-flex shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-full border font-semibold no-underline transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
7
- variants: {
8
- size: { sm: "h-7 px-3 text-xs", md: "h-9 px-3.5 text-xs" },
9
- selected: {
10
- false: "border-border-default bg-surface-1 text-fg-secondary hover:border-border-strong hover:text-fg",
11
- true: "border-accent bg-accent-soft text-fg"
12
- }
13
- },
14
- defaultVariants: { size: "md", selected: false }
15
- });
16
- function ChipLink({ size, selected = false, current = "page", asChild, className, ...props }) {
17
- const Comp = asChild ? Slot.Root : "a";
18
- return /* @__PURE__ */ jsx(
19
- Comp,
20
- {
21
- "data-state": selected ? "on" : "off",
22
- "aria-current": selected ? current : void 0,
23
- className: chipVariants({ size, selected, className }),
24
- ...props
25
- }
26
- );
27
- }
1
+ import {
2
+ ChipLink,
3
+ chipVariants
4
+ } from "./chunk-BTTDIVVJ.js";
28
5
  export {
29
6
  ChipLink,
30
7
  chipVariants
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/chip-link/chip-link.tsx"],"sourcesContent":["// Server-safe: no hook, no context. A chip that is a link — a filter that is an address (`/explore?tag=night`): the look\n// of `Chip`, the current filter marked by `selected` (`aria-current`, the accent), usable in a Server Component.\n// `chipVariants` styles anything else (a router link you render yourself).\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const chipVariants = tv({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-full border font-semibold no-underline transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n variants: {\n size: { sm: \"h-7 px-3 text-xs\", md: \"h-9 px-3.5 text-xs\" },\n selected: {\n false: \"border-border-default bg-surface-1 text-fg-secondary hover:border-border-strong hover:text-fg\",\n true: \"border-accent bg-accent-soft text-fg\",\n },\n },\n defaultVariants: { size: \"md\", selected: false },\n});\n\nexport type ChipVariantsProps = VariantProps<typeof chipVariants>;\n\nexport type ChipLinkProps = React.ComponentProps<\"a\"> & {\n /**\n * sm · md.\n * @default \"md\"\n */\n size?: ChipVariantsProps[\"size\"];\n /** The current filter: the accent, `aria-current` (`page` by default) and `data-state=\"on\"`. */\n selected?: boolean;\n /**\n * What `aria-current` says when selected: `page` (a filter that is a page) or `true`.\n * @default \"page\"\n */\n current?: \"page\" | \"true\";\n /** Renders your router's `<Link>` with the chip's look. */\n asChild?: boolean;\n};\n\n/** A filter that is a link, with the look of `Chip`. */\nexport function ChipLink({ size, selected = false, current = \"page\", asChild, className, ...props }: ChipLinkProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return (\n <Comp\n data-state={selected ? \"on\" : \"off\"}\n aria-current={selected ? current : undefined}\n className={chipVariants({ size, selected, className })}\n {...props}\n />\n );\n}\n"],"mappings":";AAGA,SAAS,YAAY;AAErB,SAAS,UAA6B;AAuClC;AArCG,IAAM,eAAe,GAAG;AAAA,EAC7B,MACE;AAAA,EAEF,UAAU;AAAA,IACR,MAAM,EAAE,IAAI,oBAAoB,IAAI,qBAAqB;AAAA,IACzD,UAAU;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,MAAM,MAAM,UAAU,MAAM;AACjD,CAAC;AAsBM,SAAS,SAAS,EAAE,MAAM,WAAW,OAAO,UAAU,QAAQ,SAAS,WAAW,GAAG,MAAM,GAAkB;AAClH,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAY,WAAW,OAAO;AAAA,MAC9B,gBAAc,WAAW,UAAU;AAAA,MACnC,WAAW,aAAa,EAAE,MAAM,UAAU,UAAU,CAAC;AAAA,MACpD,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,78 @@
1
+ import * as tailwind_variants from 'tailwind-variants';
2
+ import * as React from 'react';
3
+
4
+ declare const chipRow: tailwind_variants.TVReturnType<{
5
+ [key: string]: {
6
+ [key: string]: tailwind_variants.ClassValue | {
7
+ list?: tailwind_variants.ClassValue;
8
+ hint?: tailwind_variants.ClassValue;
9
+ root?: tailwind_variants.ClassValue;
10
+ item?: tailwind_variants.ClassValue;
11
+ badge?: tailwind_variants.ClassValue;
12
+ };
13
+ };
14
+ } | {
15
+ [x: string]: {
16
+ [x: string]: tailwind_variants.ClassValue | {
17
+ list?: tailwind_variants.ClassValue;
18
+ hint?: tailwind_variants.ClassValue;
19
+ root?: tailwind_variants.ClassValue;
20
+ item?: tailwind_variants.ClassValue;
21
+ badge?: tailwind_variants.ClassValue;
22
+ };
23
+ };
24
+ } | {}, {
25
+ root: string;
26
+ hint: string;
27
+ list: string;
28
+ item: string;
29
+ badge: string;
30
+ }, undefined, {
31
+ [key: string]: {
32
+ [key: string]: tailwind_variants.ClassValue | {
33
+ list?: tailwind_variants.ClassValue;
34
+ hint?: tailwind_variants.ClassValue;
35
+ root?: tailwind_variants.ClassValue;
36
+ item?: tailwind_variants.ClassValue;
37
+ badge?: tailwind_variants.ClassValue;
38
+ };
39
+ };
40
+ } | {}, {
41
+ root: string;
42
+ hint: string;
43
+ list: string;
44
+ item: string;
45
+ badge: string;
46
+ }, tailwind_variants.TVReturnTypeLike<unknown, {
47
+ root: string;
48
+ hint: string;
49
+ list: string;
50
+ item: string;
51
+ badge: string;
52
+ }>>;
53
+ type ChipRowProps = Omit<React.ComponentProps<"nav">, "aria-label"> & {
54
+ /** What the links choose among ("For whom?"): the row's accessible name, passed translated. */
55
+ label: string;
56
+ /** A line under the label that says how to choose; read with the row. */
57
+ hint?: React.ReactNode;
58
+ };
59
+ /** A scroll-snap row of chip links; wraps from `md`. Items: `ChipRow.Item`. */
60
+ declare function ChipRowRoot({ label, hint, className, children, ...props }: ChipRowProps): React.JSX.Element;
61
+ type ChipRowItemProps = React.ComponentProps<"a"> & {
62
+ /** The current choice: the accent and `aria-current`. */
63
+ selected?: boolean;
64
+ /** What `aria-current` says when selected.
65
+ * @default "page" */
66
+ current?: "page" | "true";
67
+ /** A small tag after the label ("Soon"), passed translated. */
68
+ badge?: React.ReactNode;
69
+ /** Renders your router's `<Link>` as the chip; put the label and the badge in your link's children yourself. */
70
+ asChild?: boolean;
71
+ };
72
+ /** One link of the row. */
73
+ declare function ChipRowItem({ selected, current, badge, asChild, className, children, ...props }: ChipRowItemProps): React.JSX.Element;
74
+ declare const ChipRow: typeof ChipRowRoot & {
75
+ Item: typeof ChipRowItem;
76
+ };
77
+
78
+ export { ChipRow, type ChipRowItemProps, type ChipRowProps, chipRow };
@@ -0,0 +1,61 @@
1
+ import {
2
+ chipVariants
3
+ } from "./chunk-BTTDIVVJ.js";
4
+
5
+ // src/chip-row/chip-row.tsx
6
+ import { Slot } from "radix-ui";
7
+ import * as React from "react";
8
+ import { tv } from "tailwind-variants";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ var chipRow = tv({
11
+ slots: {
12
+ root: "flex w-full flex-col gap-2",
13
+ hint: "text-xs text-fg-muted",
14
+ list: "m-0 flex list-none snap-x snap-proximity gap-2 overflow-x-auto p-0 pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden [mask-image:linear-gradient(to_right,#000_calc(100%-2rem),transparent)] md:flex-wrap md:overflow-visible md:pb-0 md:[mask-image:none]",
15
+ item: "snap-start",
16
+ badge: "rounded-full bg-surface-3 px-1.5 py-0.5 text-[0.625rem] font-semibold uppercase leading-none tracking-wide text-fg-muted"
17
+ }
18
+ });
19
+ var s = chipRow();
20
+ function ChipRowRoot({ label, hint, className, children, ...props }) {
21
+ const id = React.useId();
22
+ const list = React.useRef(null);
23
+ const move = (event) => {
24
+ const keys = ["ArrowLeft", "ArrowRight", "Home", "End"];
25
+ if (!keys.includes(event.key)) return;
26
+ const links = [...list.current?.querySelectorAll("a[href],button:not([disabled])") ?? []];
27
+ const at = links.indexOf(event.target);
28
+ if (at < 0) return;
29
+ const last = links.length - 1;
30
+ const to = event.key === "Home" ? 0 : event.key === "End" ? last : Math.min(last, Math.max(0, at + (event.key === "ArrowRight" ? 1 : -1)));
31
+ event.preventDefault();
32
+ links[to]?.focus();
33
+ links[to]?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
34
+ };
35
+ return /* @__PURE__ */ jsxs("nav", { "aria-label": label, "aria-describedby": hint ? `${id}-hint` : void 0, className: s.root({ className }), ...props, children: [
36
+ hint ? /* @__PURE__ */ jsx("p", { id: `${id}-hint`, className: s.hint(), children: hint }) : null,
37
+ /* @__PURE__ */ jsx("ul", { ref: list, className: s.list(), onKeyDown: move, children })
38
+ ] });
39
+ }
40
+ function ChipRowItem({ selected = false, current = "page", badge, asChild, className, children, ...props }) {
41
+ const Comp = asChild ? Slot.Root : "a";
42
+ return /* @__PURE__ */ jsx("li", { className: s.item(), children: /* @__PURE__ */ jsx(
43
+ Comp,
44
+ {
45
+ "data-state": selected ? "on" : "off",
46
+ "aria-current": selected ? current : void 0,
47
+ className: chipVariants({ selected, className: ["min-h-11", className] }),
48
+ ...props,
49
+ children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
50
+ children,
51
+ badge ? /* @__PURE__ */ jsx("span", { className: s.badge(), children: badge }) : null
52
+ ] })
53
+ }
54
+ ) });
55
+ }
56
+ var ChipRow = Object.assign(ChipRowRoot, { Item: ChipRowItem });
57
+ export {
58
+ ChipRow,
59
+ chipRow
60
+ };
61
+ //# sourceMappingURL=chip-row.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/chip-row/chip-row.tsx"],"sourcesContent":["// Client (arrow-key focus only). A row of chip links that scrolls sideways with scroll-snap on a phone (the trailing edge\n// fades, no scrollbar) and wraps from `md`: an audience picker, the filters of a page. Each item is a `ChipLink`-style\n// link at least 44 px high; the current one carries `aria-current`. Tab goes through the links; ← → Home End move between them.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { chipVariants } from \"../chip-link\";\n\nexport const chipRow = tv({\n slots: {\n root: \"flex w-full flex-col gap-2\",\n hint: \"text-xs text-fg-muted\",\n list:\n \"m-0 flex list-none snap-x snap-proximity gap-2 overflow-x-auto p-0 pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden \" +\n \"[mask-image:linear-gradient(to_right,#000_calc(100%-2rem),transparent)] md:flex-wrap md:overflow-visible md:pb-0 md:[mask-image:none]\",\n item: \"snap-start\",\n badge: \"rounded-full bg-surface-3 px-1.5 py-0.5 text-[0.625rem] font-semibold uppercase leading-none tracking-wide text-fg-muted\",\n },\n});\n\nconst s = chipRow();\n\nexport type ChipRowProps = Omit<React.ComponentProps<\"nav\">, \"aria-label\"> & {\n /** What the links choose among (\"For whom?\"): the row's accessible name, passed translated. */\n label: string;\n /** A line under the label that says how to choose; read with the row. */\n hint?: React.ReactNode;\n};\n\n/** A scroll-snap row of chip links; wraps from `md`. Items: `ChipRow.Item`. */\nfunction ChipRowRoot({ label, hint, className, children, ...props }: ChipRowProps) {\n const id = React.useId();\n const list = React.useRef<HTMLUListElement>(null);\n const move = (event: React.KeyboardEvent<HTMLUListElement>) => {\n const keys = [\"ArrowLeft\", \"ArrowRight\", \"Home\", \"End\"];\n if (!keys.includes(event.key)) return;\n const links = [...(list.current?.querySelectorAll<HTMLElement>(\"a[href],button:not([disabled])\") ?? [])];\n const at = links.indexOf(event.target as HTMLElement);\n if (at < 0) return;\n const last = links.length - 1;\n const to = event.key === \"Home\" ? 0 : event.key === \"End\" ? last : Math.min(last, Math.max(0, at + (event.key === \"ArrowRight\" ? 1 : -1)));\n event.preventDefault();\n links[to]?.focus();\n links[to]?.scrollIntoView?.({ block: \"nearest\", inline: \"nearest\" });\n };\n return (\n <nav aria-label={label} aria-describedby={hint ? `${id}-hint` : undefined} className={s.root({ className })} {...props}>\n {hint ? (\n <p id={`${id}-hint`} className={s.hint()}>\n {hint}\n </p>\n ) : null}\n <ul ref={list} className={s.list()} onKeyDown={move}>\n {children}\n </ul>\n </nav>\n );\n}\n\nexport type ChipRowItemProps = React.ComponentProps<\"a\"> & {\n /** The current choice: the accent and `aria-current`. */\n selected?: boolean;\n /** What `aria-current` says when selected.\n * @default \"page\" */\n current?: \"page\" | \"true\";\n /** A small tag after the label (\"Soon\"), passed translated. */\n badge?: React.ReactNode;\n /** Renders your router's `<Link>` as the chip; put the label and the badge in your link's children yourself. */\n asChild?: boolean;\n};\n\n/** One link of the row. */\nfunction ChipRowItem({ selected = false, current = \"page\", badge, asChild, className, children, ...props }: ChipRowItemProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return (\n <li className={s.item()}>\n <Comp\n data-state={selected ? \"on\" : \"off\"}\n aria-current={selected ? current : undefined}\n className={chipVariants({ selected, className: [\"min-h-11\", className] })}\n {...props}\n >\n {asChild ? (\n children\n ) : (\n <>\n {children}\n {badge ? <span className={s.badge()}>{badge}</span> : null}\n </>\n )}\n </Comp>\n </li>\n );\n}\n\nexport const ChipRow = Object.assign(ChipRowRoot, { Item: ChipRowItem });\n"],"mappings":";;;;;AAGA,SAAS,YAAY;AACrB,YAAY,WAAW;AACvB,SAAS,UAAU;AA0Cf,SAuCM,UArCF,KAFJ;AAtCG,IAAM,UAAU,GAAG;AAAA,EACxB,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MACE;AAAA,IAEF,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AACF,CAAC;AAED,IAAM,IAAI,QAAQ;AAUlB,SAAS,YAAY,EAAE,OAAO,MAAM,WAAW,UAAU,GAAG,MAAM,GAAiB;AACjF,QAAM,KAAW,YAAM;AACvB,QAAM,OAAa,aAAyB,IAAI;AAChD,QAAM,OAAO,CAAC,UAAiD;AAC7D,UAAM,OAAO,CAAC,aAAa,cAAc,QAAQ,KAAK;AACtD,QAAI,CAAC,KAAK,SAAS,MAAM,GAAG,EAAG;AAC/B,UAAM,QAAQ,CAAC,GAAI,KAAK,SAAS,iBAA8B,gCAAgC,KAAK,CAAC,CAAE;AACvG,UAAM,KAAK,MAAM,QAAQ,MAAM,MAAqB;AACpD,QAAI,KAAK,EAAG;AACZ,UAAM,OAAO,MAAM,SAAS;AAC5B,UAAM,KAAK,MAAM,QAAQ,SAAS,IAAI,MAAM,QAAQ,QAAQ,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI,GAAG,MAAM,MAAM,QAAQ,eAAe,IAAI,GAAG,CAAC;AACzI,UAAM,eAAe;AACrB,UAAM,EAAE,GAAG,MAAM;AACjB,UAAM,EAAE,GAAG,iBAAiB,EAAE,OAAO,WAAW,QAAQ,UAAU,CAAC;AAAA,EACrE;AACA,SACE,qBAAC,SAAI,cAAY,OAAO,oBAAkB,OAAO,GAAG,EAAE,UAAU,QAAW,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC9G;AAAA,WACC,oBAAC,OAAE,IAAI,GAAG,EAAE,SAAS,WAAW,EAAE,KAAK,GACpC,gBACH,IACE;AAAA,IACJ,oBAAC,QAAG,KAAK,MAAM,WAAW,EAAE,KAAK,GAAG,WAAW,MAC5C,UACH;AAAA,KACF;AAEJ;AAeA,SAAS,YAAY,EAAE,WAAW,OAAO,UAAU,QAAQ,OAAO,SAAS,WAAW,UAAU,GAAG,MAAM,GAAqB;AAC5H,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE,oBAAC,QAAG,WAAW,EAAE,KAAK,GACpB;AAAA,IAAC;AAAA;AAAA,MACC,cAAY,WAAW,OAAO;AAAA,MAC9B,gBAAc,WAAW,UAAU;AAAA,MACnC,WAAW,aAAa,EAAE,UAAU,WAAW,CAAC,YAAY,SAAS,EAAE,CAAC;AAAA,MACvE,GAAG;AAAA,MAEH,oBACC,WAEA,iCACG;AAAA;AAAA,QACA,QAAQ,oBAAC,UAAK,WAAW,EAAE,MAAM,GAAI,iBAAM,IAAU;AAAA,SACxD;AAAA;AAAA,EAEJ,GACF;AAEJ;AAEO,IAAM,UAAU,OAAO,OAAO,aAAa,EAAE,MAAM,YAAY,CAAC;","names":[]}
@@ -0,0 +1,33 @@
1
+ // src/chip-link/chip-link.tsx
2
+ import { Slot } from "radix-ui";
3
+ import { tv } from "tailwind-variants";
4
+ import { jsx } from "react/jsx-runtime";
5
+ var chipVariants = tv({
6
+ base: "inline-flex shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-full border font-semibold no-underline transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
7
+ variants: {
8
+ size: { sm: "h-7 px-3 text-xs", md: "h-9 px-3.5 text-xs" },
9
+ selected: {
10
+ false: "border-border-default bg-surface-1 text-fg-secondary hover:border-border-strong hover:text-fg",
11
+ true: "border-accent bg-accent-soft text-fg"
12
+ }
13
+ },
14
+ defaultVariants: { size: "md", selected: false }
15
+ });
16
+ function ChipLink({ size, selected = false, current = "page", asChild, className, ...props }) {
17
+ const Comp = asChild ? Slot.Root : "a";
18
+ return /* @__PURE__ */ jsx(
19
+ Comp,
20
+ {
21
+ "data-state": selected ? "on" : "off",
22
+ "aria-current": selected ? current : void 0,
23
+ className: chipVariants({ size, selected, className }),
24
+ ...props
25
+ }
26
+ );
27
+ }
28
+
29
+ export {
30
+ chipVariants,
31
+ ChipLink
32
+ };
33
+ //# sourceMappingURL=chunk-BTTDIVVJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/chip-link/chip-link.tsx"],"sourcesContent":["// Server-safe: no hook, no context. A chip that is a link — a filter that is an address (`/explore?tag=night`): the look\n// of `Chip`, the current filter marked by `selected` (`aria-current`, the accent), usable in a Server Component.\n// `chipVariants` styles anything else (a router link you render yourself).\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const chipVariants = tv({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-full border font-semibold no-underline transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n variants: {\n size: { sm: \"h-7 px-3 text-xs\", md: \"h-9 px-3.5 text-xs\" },\n selected: {\n false: \"border-border-default bg-surface-1 text-fg-secondary hover:border-border-strong hover:text-fg\",\n true: \"border-accent bg-accent-soft text-fg\",\n },\n },\n defaultVariants: { size: \"md\", selected: false },\n});\n\nexport type ChipVariantsProps = VariantProps<typeof chipVariants>;\n\nexport type ChipLinkProps = React.ComponentProps<\"a\"> & {\n /**\n * sm · md.\n * @default \"md\"\n */\n size?: ChipVariantsProps[\"size\"];\n /** The current filter: the accent, `aria-current` (`page` by default) and `data-state=\"on\"`. */\n selected?: boolean;\n /**\n * What `aria-current` says when selected: `page` (a filter that is a page) or `true`.\n * @default \"page\"\n */\n current?: \"page\" | \"true\";\n /** Renders your router's `<Link>` with the chip's look. */\n asChild?: boolean;\n};\n\n/** A filter that is a link, with the look of `Chip`. */\nexport function ChipLink({ size, selected = false, current = \"page\", asChild, className, ...props }: ChipLinkProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return (\n <Comp\n data-state={selected ? \"on\" : \"off\"}\n aria-current={selected ? current : undefined}\n className={chipVariants({ size, selected, className })}\n {...props}\n />\n );\n}\n"],"mappings":";AAGA,SAAS,YAAY;AAErB,SAAS,UAA6B;AAuClC;AArCG,IAAM,eAAe,GAAG;AAAA,EAC7B,MACE;AAAA,EAEF,UAAU;AAAA,IACR,MAAM,EAAE,IAAI,oBAAoB,IAAI,qBAAqB;AAAA,IACzD,UAAU;AAAA,MACR,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,MAAM,MAAM,UAAU,MAAM;AACjD,CAAC;AAsBM,SAAS,SAAS,EAAE,MAAM,WAAW,OAAO,UAAU,QAAQ,SAAS,WAAW,GAAG,MAAM,GAAkB;AAClH,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAY,WAAW,OAAO;AAAA,MAC9B,gBAAc,WAAW,UAAU;AAAA,MACnC,WAAW,aAAa,EAAE,MAAM,UAAU,UAAU,CAAC;AAAA,MACpD,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -65,8 +65,14 @@ type DocsHubPageProps = Omit<React.HTMLAttributes<HTMLElement>, "title"> & {
65
65
  };
66
66
  /** The app's link component (Next's `Link`) for internal addresses. */
67
67
  linkAs?: LinkComponent;
68
+ /**
69
+ * How a collection's quick links sit: `wrap` (pills in a row that wraps) or `stack` (one pill per line, so the first
70
+ * link of every card starts at the same height).
71
+ * @default "wrap"
72
+ */
73
+ linksLayout?: "wrap" | "stack";
68
74
  };
69
75
  /** A documentation hub: search first, the collections in their brand, quick starts, popular and new pages. */
70
- declare function DocsHubPage({ eyebrow, title, lead, search, searchHints, collectionsTitle, collections, quickstarts, popular, whatsNew, promise, linkAs, ...props }: DocsHubPageProps): React.JSX.Element;
76
+ declare function DocsHubPage({ eyebrow, title, lead, search, searchHints, collectionsTitle, collections, quickstarts, popular, whatsNew, promise, linkAs, linksLayout, ...props }: DocsHubPageProps): React.JSX.Element;
71
77
 
72
78
  export { type DocsCollection, type DocsHubLink, DocsHubPage, type DocsHubPageProps };
@@ -10,14 +10,14 @@ function List({ items, linkAs: Link = "a" }) {
10
10
  item.meta && /* @__PURE__ */ jsx("small", { children: item.meta })
11
11
  ] }) }, `${i}:${item.href}`)) });
12
12
  }
13
- function DocsHubPage({ eyebrow, title, lead, search, searchHints, collectionsTitle, collections, quickstarts, popular, whatsNew, promise, linkAs, ...props }) {
13
+ function DocsHubPage({ eyebrow, title, lead, search, searchHints, collectionsTitle, collections, quickstarts, popular, whatsNew, promise, linkAs, linksLayout = "wrap", ...props }) {
14
14
  const L = linkAs ?? "a";
15
15
  return /* @__PURE__ */ jsxs("div", { ...props, children: [
16
16
  /* @__PURE__ */ jsx(PageHero, { eyebrow, title, lead, align: "center", backdrop: "grid", children: (search || searchHints) && /* @__PURE__ */ jsxs("div", { className: "kz-tpl-hub-search", children: [
17
17
  search,
18
18
  searchHints && /* @__PURE__ */ jsx("div", { className: "kz-tpl-hub-hints", children: searchHints })
19
19
  ] }) }),
20
- /* @__PURE__ */ jsx(Section, { id: "collections", title: collectionsTitle, headingSize: "sm", spacing: "sm", children: /* @__PURE__ */ jsx("ul", { className: "kz-tpl-collections", children: collections.map((c) => /* @__PURE__ */ jsx("li", { className: c.brand ? "brand-" + c.brand : void 0, children: /* @__PURE__ */ jsxs("div", { className: "kz-tpl-collection", children: [
20
+ /* @__PURE__ */ jsx(Section, { id: "collections", title: collectionsTitle, headingSize: "sm", spacing: "sm", children: /* @__PURE__ */ jsx("ul", { className: "kz-tpl-collections", children: collections.map((c) => /* @__PURE__ */ jsx("li", { className: c.brand ? "brand-" + c.brand : void 0, children: /* @__PURE__ */ jsxs("div", { className: "kz-tpl-collection", "data-links": linksLayout, children: [
21
21
  /* @__PURE__ */ jsxs("div", { className: "kz-tpl-collection-head", children: [
22
22
  c.mark && /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: c.mark }),
23
23
  /* @__PURE__ */ jsx(L, { href: c.href, children: c.title })
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/docs-hub-page/docs-hub-page.tsx"],"sourcesContent":["// Server-safe. The entry of a documentation (blocks.css `.kz-tpl-hub-*`, `.kz-tpl-collections`): the search in the\n// middle of the hero, the collections each in its product's brand with its quick links, the quick starts beside the\n// most read pages, what is new from the registries, and the owl's promise. One column on a phone, the search first.\nimport { MascotQuote } from \"@krizaka/ui/mascot-quote\";\nimport { Section } from \"@krizaka/ui/page\";\nimport type { LinkComponent } from \"@krizaka/ui/page-hero\";\nimport { PageHero } from \"@krizaka/ui/page-hero\";\nimport * as React from \"react\";\n\nexport interface DocsCollection {\n /** A stable key. */\n id: string;\n /** The product's brand (`orazaka`…): the panel wears `.brand-<id>`. */\n brand?: string;\n /** The product's mark. */\n mark?: React.ReactNode;\n /** The collection's name: a link to its home. */\n title: string;\n /** Where it starts. */\n href: string;\n /** What it covers, in one sentence. */\n description?: React.ReactNode;\n /** Its most useful pages (three or four). */\n links?: readonly { href: string; label: string }[];\n}\n\nexport interface DocsHubLink {\n /** Where it leads. */\n href: string;\n /** The page's title. */\n title: React.ReactNode;\n /** On the right, in mono: a collection, a version, a date. */\n meta?: React.ReactNode;\n}\n\nexport type DocsHubPageProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\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 /** The search, front and centre (a SearchField, a button that opens the command palette). */\n search?: React.ReactNode;\n /** Under the search: what people look for (a few links or keys). */\n searchHints?: React.ReactNode;\n /** The collections' heading. */\n collectionsTitle: React.ReactNode;\n /** The collections, each in its brand. */\n collections: readonly DocsCollection[];\n /** The quick starts: a title and their samples (CodeBlocks, CodeTabs). */\n quickstarts?: { title: React.ReactNode; children: React.ReactNode };\n /** The most read pages. */\n popular?: { title: React.ReactNode; items: readonly DocsHubLink[] };\n /** What is new (releases from the registries, published pages). */\n whatsNew?: { title: React.ReactNode; items: readonly DocsHubLink[] };\n /** The owl's promise at the foot: what this documentation guarantees. */\n promise?: { label: React.ReactNode; text: React.ReactNode };\n /** The app's link component (Next's `Link`) for internal addresses. */\n linkAs?: LinkComponent;\n};\n\nfunction List({ items, linkAs: Link = \"a\" }: { items: readonly DocsHubLink[]; linkAs?: LinkComponent }) {\n const L = Link as React.ElementType;\n return (\n <ul className=\"kz-tpl-links\">\n {items.map((item, i) => (\n <li key={`${i}:${item.href}`}>\n <L href={item.href}>\n <strong>{item.title}</strong>\n {item.meta && <small>{item.meta}</small>}\n </L>\n </li>\n ))}\n </ul>\n );\n}\n\n/** A documentation hub: search first, the collections in their brand, quick starts, popular and new pages. */\nexport function DocsHubPage({ eyebrow, title, lead, search, searchHints, collectionsTitle, collections, quickstarts, popular, whatsNew, promise, linkAs, ...props }: DocsHubPageProps) {\n const L = (linkAs ?? \"a\") as React.ElementType;\n return (\n <div {...props}>\n <PageHero eyebrow={eyebrow} title={title} lead={lead} align=\"center\" backdrop=\"grid\">\n {(search || searchHints) && (\n <div className=\"kz-tpl-hub-search\">\n {search}\n {searchHints && <div className=\"kz-tpl-hub-hints\">{searchHints}</div>}\n </div>\n )}\n </PageHero>\n <Section id=\"collections\" title={collectionsTitle} headingSize=\"sm\" spacing=\"sm\">\n <ul className=\"kz-tpl-collections\">\n {collections.map((c) => (\n <li key={c.id} className={c.brand ? \"brand-\" + c.brand : undefined}>\n <div className=\"kz-tpl-collection\">\n <div className=\"kz-tpl-collection-head\">\n {c.mark && <span aria-hidden>{c.mark}</span>}\n <L href={c.href}>{c.title}</L>\n </div>\n {c.description && <p>{c.description}</p>}\n {c.links && c.links.length > 0 && (\n <ul aria-label={c.title}>\n {c.links.map((l) => (\n <li key={l.href}>\n <L href={l.href}>{l.label}</L>\n </li>\n ))}\n </ul>\n )}\n </div>\n </li>\n ))}\n </ul>\n </Section>\n {(quickstarts || popular) && (\n <Section spacing=\"sm\" divider aria-label={typeof quickstarts?.title === \"string\" ? quickstarts.title : undefined}>\n <div className=\"kz-tpl-two\">\n {quickstarts && (\n <div className=\"kz-tpl-stack\">\n <h2 className=\"kz-heading-title kz-tpl-h2\">{quickstarts.title}</h2>\n {quickstarts.children}\n </div>\n )}\n {popular && (\n <div className=\"kz-tpl-stack\">\n <h2 className=\"kz-heading-title kz-tpl-h2\">{popular.title}</h2>\n <List items={popular.items} linkAs={linkAs} />\n </div>\n )}\n </div>\n </Section>\n )}\n {whatsNew && (\n <Section id=\"whats-new\" title={whatsNew.title} headingSize=\"sm\" spacing=\"sm\" divider>\n <List items={whatsNew.items} linkAs={linkAs} />\n </Section>\n )}\n {promise && (\n <Section spacing=\"sm\" aria-label={typeof promise.label === \"string\" ? promise.label : undefined}>\n <MascotQuote variant=\"callout\" bird=\"owl\" mood=\"welcome\" label={promise.label}>\n {promise.text}\n </MascotQuote>\n </Section>\n )}\n </div>\n );\n}\n"],"mappings":";AAGA,SAAS,mBAAmB;AAC5B,SAAS,eAAe;AAExB,SAAS,gBAAgB;AA8Df,SACE,KADF;AANV,SAAS,KAAK,EAAE,OAAO,QAAQ,OAAO,IAAI,GAA8D;AACtG,QAAM,IAAI;AACV,SACE,oBAAC,QAAG,WAAU,gBACX,gBAAM,IAAI,CAAC,MAAM,MAChB,oBAAC,QACC,+BAAC,KAAE,MAAM,KAAK,MACZ;AAAA,wBAAC,YAAQ,eAAK,OAAM;AAAA,IACnB,KAAK,QAAQ,oBAAC,WAAO,eAAK,MAAK;AAAA,KAClC,KAJO,GAAG,CAAC,IAAI,KAAK,IAAI,EAK1B,CACD,GACH;AAEJ;AAGO,SAAS,YAAY,EAAE,SAAS,OAAO,MAAM,QAAQ,aAAa,kBAAkB,aAAa,aAAa,SAAS,UAAU,SAAS,QAAQ,GAAG,MAAM,GAAqB;AACrL,QAAM,IAAK,UAAU;AACrB,SACE,qBAAC,SAAK,GAAG,OACP;AAAA,wBAAC,YAAS,SAAkB,OAAc,MAAY,OAAM,UAAS,UAAS,QAC1E,qBAAU,gBACV,qBAAC,SAAI,WAAU,qBACZ;AAAA;AAAA,MACA,eAAe,oBAAC,SAAI,WAAU,oBAAoB,uBAAY;AAAA,OACjE,GAEJ;AAAA,IACA,oBAAC,WAAQ,IAAG,eAAc,OAAO,kBAAkB,aAAY,MAAK,SAAQ,MAC1E,8BAAC,QAAG,WAAU,sBACX,sBAAY,IAAI,CAAC,MAChB,oBAAC,QAAc,WAAW,EAAE,QAAQ,WAAW,EAAE,QAAQ,QACvD,+BAAC,SAAI,WAAU,qBACb;AAAA,2BAAC,SAAI,WAAU,0BACZ;AAAA,UAAE,QAAQ,oBAAC,UAAK,eAAW,MAAE,YAAE,MAAK;AAAA,QACrC,oBAAC,KAAE,MAAM,EAAE,MAAO,YAAE,OAAM;AAAA,SAC5B;AAAA,MACC,EAAE,eAAe,oBAAC,OAAG,YAAE,aAAY;AAAA,MACnC,EAAE,SAAS,EAAE,MAAM,SAAS,KAC3B,oBAAC,QAAG,cAAY,EAAE,OACf,YAAE,MAAM,IAAI,CAAC,MACZ,oBAAC,QACC,8BAAC,KAAE,MAAM,EAAE,MAAO,YAAE,OAAM,KADnB,EAAE,IAEX,CACD,GACH;AAAA,OAEJ,KAhBO,EAAE,EAiBX,CACD,GACH,GACF;AAAA,KACE,eAAe,YACf,oBAAC,WAAQ,SAAQ,MAAK,SAAO,MAAC,cAAY,OAAO,aAAa,UAAU,WAAW,YAAY,QAAQ,QACrG,+BAAC,SAAI,WAAU,cACZ;AAAA,qBACC,qBAAC,SAAI,WAAU,gBACb;AAAA,4BAAC,QAAG,WAAU,8BAA8B,sBAAY,OAAM;AAAA,QAC7D,YAAY;AAAA,SACf;AAAA,MAED,WACC,qBAAC,SAAI,WAAU,gBACb;AAAA,4BAAC,QAAG,WAAU,8BAA8B,kBAAQ,OAAM;AAAA,QAC1D,oBAAC,QAAK,OAAO,QAAQ,OAAO,QAAgB;AAAA,SAC9C;AAAA,OAEJ,GACF;AAAA,IAED,YACC,oBAAC,WAAQ,IAAG,aAAY,OAAO,SAAS,OAAO,aAAY,MAAK,SAAQ,MAAK,SAAO,MAClF,8BAAC,QAAK,OAAO,SAAS,OAAO,QAAgB,GAC/C;AAAA,IAED,WACC,oBAAC,WAAQ,SAAQ,MAAK,cAAY,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,QACpF,8BAAC,eAAY,SAAQ,WAAU,MAAK,OAAM,MAAK,WAAU,OAAO,QAAQ,OACrE,kBAAQ,MACX,GACF;AAAA,KAEJ;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/docs-hub-page/docs-hub-page.tsx"],"sourcesContent":["// Server-safe. The entry of a documentation (blocks.css `.kz-tpl-hub-*`, `.kz-tpl-collections`): the search in the\n// middle of the hero, the collections each in its product's brand with its quick links, the quick starts beside the\n// most read pages, what is new from the registries, and the owl's promise. One column on a phone, the search first.\nimport { MascotQuote } from \"@krizaka/ui/mascot-quote\";\nimport { Section } from \"@krizaka/ui/page\";\nimport type { LinkComponent } from \"@krizaka/ui/page-hero\";\nimport { PageHero } from \"@krizaka/ui/page-hero\";\nimport * as React from \"react\";\n\nexport interface DocsCollection {\n /** A stable key. */\n id: string;\n /** The product's brand (`orazaka`…): the panel wears `.brand-<id>`. */\n brand?: string;\n /** The product's mark. */\n mark?: React.ReactNode;\n /** The collection's name: a link to its home. */\n title: string;\n /** Where it starts. */\n href: string;\n /** What it covers, in one sentence. */\n description?: React.ReactNode;\n /** Its most useful pages (three or four). */\n links?: readonly { href: string; label: string }[];\n}\n\nexport interface DocsHubLink {\n /** Where it leads. */\n href: string;\n /** The page's title. */\n title: React.ReactNode;\n /** On the right, in mono: a collection, a version, a date. */\n meta?: React.ReactNode;\n}\n\nexport type DocsHubPageProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\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 /** The search, front and centre (a SearchField, a button that opens the command palette). */\n search?: React.ReactNode;\n /** Under the search: what people look for (a few links or keys). */\n searchHints?: React.ReactNode;\n /** The collections' heading. */\n collectionsTitle: React.ReactNode;\n /** The collections, each in its brand. */\n collections: readonly DocsCollection[];\n /** The quick starts: a title and their samples (CodeBlocks, CodeTabs). */\n quickstarts?: { title: React.ReactNode; children: React.ReactNode };\n /** The most read pages. */\n popular?: { title: React.ReactNode; items: readonly DocsHubLink[] };\n /** What is new (releases from the registries, published pages). */\n whatsNew?: { title: React.ReactNode; items: readonly DocsHubLink[] };\n /** The owl's promise at the foot: what this documentation guarantees. */\n promise?: { label: React.ReactNode; text: React.ReactNode };\n /** The app's link component (Next's `Link`) for internal addresses. */\n linkAs?: LinkComponent;\n /**\n * How a collection's quick links sit: `wrap` (pills in a row that wraps) or `stack` (one pill per line, so the first\n * link of every card starts at the same height).\n * @default \"wrap\"\n */\n linksLayout?: \"wrap\" | \"stack\";\n};\n\nfunction List({ items, linkAs: Link = \"a\" }: { items: readonly DocsHubLink[]; linkAs?: LinkComponent }) {\n const L = Link as React.ElementType;\n return (\n <ul className=\"kz-tpl-links\">\n {items.map((item, i) => (\n <li key={`${i}:${item.href}`}>\n <L href={item.href}>\n <strong>{item.title}</strong>\n {item.meta && <small>{item.meta}</small>}\n </L>\n </li>\n ))}\n </ul>\n );\n}\n\n/** A documentation hub: search first, the collections in their brand, quick starts, popular and new pages. */\nexport function DocsHubPage({ eyebrow, title, lead, search, searchHints, collectionsTitle, collections, quickstarts, popular, whatsNew, promise, linkAs, linksLayout = \"wrap\", ...props }: DocsHubPageProps) {\n const L = (linkAs ?? \"a\") as React.ElementType;\n return (\n <div {...props}>\n <PageHero eyebrow={eyebrow} title={title} lead={lead} align=\"center\" backdrop=\"grid\">\n {(search || searchHints) && (\n <div className=\"kz-tpl-hub-search\">\n {search}\n {searchHints && <div className=\"kz-tpl-hub-hints\">{searchHints}</div>}\n </div>\n )}\n </PageHero>\n <Section id=\"collections\" title={collectionsTitle} headingSize=\"sm\" spacing=\"sm\">\n <ul className=\"kz-tpl-collections\">\n {collections.map((c) => (\n <li key={c.id} className={c.brand ? \"brand-\" + c.brand : undefined}>\n <div className=\"kz-tpl-collection\" data-links={linksLayout}>\n <div className=\"kz-tpl-collection-head\">\n {c.mark && <span aria-hidden>{c.mark}</span>}\n <L href={c.href}>{c.title}</L>\n </div>\n {c.description && <p>{c.description}</p>}\n {c.links && c.links.length > 0 && (\n <ul aria-label={c.title}>\n {c.links.map((l) => (\n <li key={l.href}>\n <L href={l.href}>{l.label}</L>\n </li>\n ))}\n </ul>\n )}\n </div>\n </li>\n ))}\n </ul>\n </Section>\n {(quickstarts || popular) && (\n <Section spacing=\"sm\" divider aria-label={typeof quickstarts?.title === \"string\" ? quickstarts.title : undefined}>\n <div className=\"kz-tpl-two\">\n {quickstarts && (\n <div className=\"kz-tpl-stack\">\n <h2 className=\"kz-heading-title kz-tpl-h2\">{quickstarts.title}</h2>\n {quickstarts.children}\n </div>\n )}\n {popular && (\n <div className=\"kz-tpl-stack\">\n <h2 className=\"kz-heading-title kz-tpl-h2\">{popular.title}</h2>\n <List items={popular.items} linkAs={linkAs} />\n </div>\n )}\n </div>\n </Section>\n )}\n {whatsNew && (\n <Section id=\"whats-new\" title={whatsNew.title} headingSize=\"sm\" spacing=\"sm\" divider>\n <List items={whatsNew.items} linkAs={linkAs} />\n </Section>\n )}\n {promise && (\n <Section spacing=\"sm\" aria-label={typeof promise.label === \"string\" ? promise.label : undefined}>\n <MascotQuote variant=\"callout\" bird=\"owl\" mood=\"welcome\" label={promise.label}>\n {promise.text}\n </MascotQuote>\n </Section>\n )}\n </div>\n );\n}\n"],"mappings":";AAGA,SAAS,mBAAmB;AAC5B,SAAS,eAAe;AAExB,SAAS,gBAAgB;AAoEf,SACE,KADF;AANV,SAAS,KAAK,EAAE,OAAO,QAAQ,OAAO,IAAI,GAA8D;AACtG,QAAM,IAAI;AACV,SACE,oBAAC,QAAG,WAAU,gBACX,gBAAM,IAAI,CAAC,MAAM,MAChB,oBAAC,QACC,+BAAC,KAAE,MAAM,KAAK,MACZ;AAAA,wBAAC,YAAQ,eAAK,OAAM;AAAA,IACnB,KAAK,QAAQ,oBAAC,WAAO,eAAK,MAAK;AAAA,KAClC,KAJO,GAAG,CAAC,IAAI,KAAK,IAAI,EAK1B,CACD,GACH;AAEJ;AAGO,SAAS,YAAY,EAAE,SAAS,OAAO,MAAM,QAAQ,aAAa,kBAAkB,aAAa,aAAa,SAAS,UAAU,SAAS,QAAQ,cAAc,QAAQ,GAAG,MAAM,GAAqB;AAC3M,QAAM,IAAK,UAAU;AACrB,SACE,qBAAC,SAAK,GAAG,OACP;AAAA,wBAAC,YAAS,SAAkB,OAAc,MAAY,OAAM,UAAS,UAAS,QAC1E,qBAAU,gBACV,qBAAC,SAAI,WAAU,qBACZ;AAAA;AAAA,MACA,eAAe,oBAAC,SAAI,WAAU,oBAAoB,uBAAY;AAAA,OACjE,GAEJ;AAAA,IACA,oBAAC,WAAQ,IAAG,eAAc,OAAO,kBAAkB,aAAY,MAAK,SAAQ,MAC1E,8BAAC,QAAG,WAAU,sBACX,sBAAY,IAAI,CAAC,MAChB,oBAAC,QAAc,WAAW,EAAE,QAAQ,WAAW,EAAE,QAAQ,QACvD,+BAAC,SAAI,WAAU,qBAAoB,cAAY,aAC7C;AAAA,2BAAC,SAAI,WAAU,0BACZ;AAAA,UAAE,QAAQ,oBAAC,UAAK,eAAW,MAAE,YAAE,MAAK;AAAA,QACrC,oBAAC,KAAE,MAAM,EAAE,MAAO,YAAE,OAAM;AAAA,SAC5B;AAAA,MACC,EAAE,eAAe,oBAAC,OAAG,YAAE,aAAY;AAAA,MACnC,EAAE,SAAS,EAAE,MAAM,SAAS,KAC3B,oBAAC,QAAG,cAAY,EAAE,OACf,YAAE,MAAM,IAAI,CAAC,MACZ,oBAAC,QACC,8BAAC,KAAE,MAAM,EAAE,MAAO,YAAE,OAAM,KADnB,EAAE,IAEX,CACD,GACH;AAAA,OAEJ,KAhBO,EAAE,EAiBX,CACD,GACH,GACF;AAAA,KACE,eAAe,YACf,oBAAC,WAAQ,SAAQ,MAAK,SAAO,MAAC,cAAY,OAAO,aAAa,UAAU,WAAW,YAAY,QAAQ,QACrG,+BAAC,SAAI,WAAU,cACZ;AAAA,qBACC,qBAAC,SAAI,WAAU,gBACb;AAAA,4BAAC,QAAG,WAAU,8BAA8B,sBAAY,OAAM;AAAA,QAC7D,YAAY;AAAA,SACf;AAAA,MAED,WACC,qBAAC,SAAI,WAAU,gBACb;AAAA,4BAAC,QAAG,WAAU,8BAA8B,kBAAQ,OAAM;AAAA,QAC1D,oBAAC,QAAK,OAAO,QAAQ,OAAO,QAAgB;AAAA,SAC9C;AAAA,OAEJ,GACF;AAAA,IAED,YACC,oBAAC,WAAQ,IAAG,aAAY,OAAO,SAAS,OAAO,aAAY,MAAK,SAAQ,MAAK,SAAO,MAClF,8BAAC,QAAK,OAAO,SAAS,OAAO,QAAgB,GAC/C;AAAA,IAED,WACC,oBAAC,WAAQ,SAAQ,MAAK,cAAY,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,QACpF,8BAAC,eAAY,SAAQ,WAAU,MAAK,OAAM,MAAK,WAAU,OAAO,QAAQ,OACrE,kBAAQ,MACX,GACF;AAAA,KAEJ;AAEJ;","names":[]}
@@ -0,0 +1,97 @@
1
+ import * as React from 'react';
2
+
3
+ /** How the nodes are placed around the hub. */
4
+ type FlowLayout = "radial" | "top-to-bottom" | "left-to-right";
5
+ /** The shape of a conduit: an S-shaped cubic Bézier, or a straight line. */
6
+ type FlowConduit = "bezier" | "straight";
7
+ interface FlowPoint {
8
+ x: number;
9
+ y: number;
10
+ }
11
+ interface FlowGeometry {
12
+ /** The box: 100 units wide, `height` units high (the stage keeps this aspect ratio, so nothing is distorted). */
13
+ width: number;
14
+ height: number;
15
+ hub: FlowPoint;
16
+ nodes: FlowPoint[];
17
+ /** One path per node, from the node to the hub. */
18
+ paths: string[];
19
+ /** The length of each path, in units. */
20
+ lengths: number[];
21
+ }
22
+ /** The box height per layout (the width is always 100). */
23
+ declare const FLOW_HEIGHT: Record<FlowLayout, number>;
24
+ /** The positions of `count` nodes around the hub. */
25
+ declare function flowPositions(layout: FlowLayout, count: number): {
26
+ hub: FlowPoint;
27
+ nodes: FlowPoint[];
28
+ };
29
+ /** The whole geometry of a flow: positions, conduits (node → hub) and their lengths. */
30
+ declare function flowGeometry(layout: FlowLayout, count: number, conduit?: FlowConduit): FlowGeometry;
31
+
32
+ interface EngineFlowNode {
33
+ /** A stable id (`orochia`). */
34
+ id: string;
35
+ /** Its name, the button's accessible name ("Orochia"). */
36
+ label: string;
37
+ /** Its mark (a `ProductLogo`), decorative. */
38
+ mark?: React.ReactNode;
39
+ /** One line: what it uses the engine for — shown when the node is pointed at or focused. */
40
+ description?: React.ReactNode;
41
+ /** Where it lives (its site). */
42
+ href?: string;
43
+ /** The link's words ("Visit dev.orochia.com"); defaults to the label. */
44
+ linkLabel?: React.ReactNode;
45
+ /** Opens the link in a new tab. */
46
+ external?: boolean;
47
+ /** What travels: `in` towards the hub, `out` back from it, `both`.
48
+ * @default "in" */
49
+ flow?: "in" | "out" | "both";
50
+ /** Not wired yet: drawn dim, its conduit dashed and still, no photon. */
51
+ planned?: boolean;
52
+ /** A word beside the name in the detail line ("planned"), passed translated. */
53
+ status?: React.ReactNode;
54
+ /** Its brand scope (`brand-orochia`): its conduit, photons and ring take its `--kz-accent`. */
55
+ className?: string;
56
+ }
57
+ interface EngineFlowHub {
58
+ /** The engine's name ("Orazaka"). */
59
+ label: string;
60
+ /** Its mark, decorative. */
61
+ mark?: React.ReactNode;
62
+ /** A line under the name ("the engine"). */
63
+ caption?: React.ReactNode;
64
+ /** Its brand scope; the photons coming back take its accent. */
65
+ className?: string;
66
+ }
67
+ type EngineFlowProps = Omit<React.ComponentProps<"figure">, "children"> & {
68
+ /** What the figure shows ("Orazaka and the products it powers"), passed translated. */
69
+ label: string;
70
+ /** The engine, at the hub. */
71
+ hub: EngineFlowHub;
72
+ /** The apps around it. */
73
+ nodes: readonly EngineFlowNode[];
74
+ /** How the nodes sit around the hub.
75
+ * @default "radial" */
76
+ layout?: FlowLayout;
77
+ /** The layout under a 560 px wide container (a phone); `false` keeps `layout` everywhere.
78
+ * @default "top-to-bottom" */
79
+ compactLayout?: FlowLayout | false;
80
+ /** `photons` travel the conduits; `none` draws them still.
81
+ * @default "photons" */
82
+ particles?: "photons" | "none";
83
+ /** The conduits' shape.
84
+ * @default "bezier" */
85
+ conduit?: FlowConduit;
86
+ /** The detail line before a node is chosen ("Point at a product"). */
87
+ hint?: React.ReactNode;
88
+ /** The node shown in the detail line at first. */
89
+ defaultActive?: string;
90
+ /** Photon speed, in units per second (the stage is 100 units wide).
91
+ * @default 16 */
92
+ speed?: number;
93
+ };
94
+ /** An engine at the hub and the apps it serves, with what travels between them. */
95
+ declare function EngineFlow({ label, hub, nodes, layout, compactLayout, particles, conduit, hint, defaultActive, speed, className, ...props }: EngineFlowProps): React.JSX.Element;
96
+
97
+ export { EngineFlow, type EngineFlowHub, type EngineFlowNode, type EngineFlowProps, FLOW_HEIGHT, type FlowConduit, type FlowGeometry, type FlowLayout, type FlowPoint, flowGeometry, flowPositions };