@krizaka/ui 3.36.0 → 3.38.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.
- package/dist/activity-feed.js +1 -1
- package/dist/activity-feed.js.map +1 -1
- package/dist/app-shell.js +3 -3
- package/dist/app-shell.js.map +1 -1
- package/dist/badge.d.ts +1 -1
- package/dist/badge.js +1 -1
- package/dist/badge.js.map +1 -1
- package/dist/blocks.css +30 -30
- package/dist/card.d.ts +6 -6
- package/dist/card.js +2 -2
- package/dist/card.js.map +1 -1
- package/dist/chip-row.js +1 -1
- package/dist/chip-row.js.map +1 -1
- package/dist/chip.js +1 -1
- package/dist/chip.js.map +1 -1
- package/dist/{chunk-QDXV544C.js → chunk-4QH6CP2Y.js} +2 -2
- package/dist/chunk-4QH6CP2Y.js.map +1 -0
- package/dist/{chunk-CKSHLSDH.js → chunk-AAP3U66V.js} +2 -2
- package/dist/{chunk-7UCPGXKN.js → chunk-C3NF7V5Y.js} +2 -2
- package/dist/{chunk-7UCPGXKN.js.map → chunk-C3NF7V5Y.js.map} +1 -1
- package/dist/{chunk-K2ZYB4HP.js → chunk-S5LP7KKW.js} +2 -2
- package/dist/{chunk-63KCDMX2.js → chunk-VPO27AFS.js} +4 -4
- package/dist/chunk-VPO27AFS.js.map +1 -0
- package/dist/{chunk-YOTQD7JD.js → chunk-WYQ277F2.js} +2 -2
- package/dist/{chunk-2DGLWTPS.js → chunk-YKOLME7R.js} +3 -3
- package/dist/{chunk-2DGLWTPS.js.map → chunk-YKOLME7R.js.map} +1 -1
- package/dist/code-block.js +4 -4
- package/dist/code-block.js.map +1 -1
- package/dist/combobox.js +2 -2
- package/dist/data-table.js +3 -3
- package/dist/file-upload.js +3 -3
- package/dist/file-upload.js.map +1 -1
- package/dist/filter-bar.js +2 -2
- package/dist/genui.js +4 -4
- package/dist/landing-page.js +1 -6
- package/dist/landing-page.js.map +1 -1
- package/dist/language-switch.js +1 -1
- package/dist/marketing-layout.js +1 -1
- package/dist/marketing-layout.js.map +1 -1
- package/dist/media-grid.js +1 -1
- package/dist/meter.js +2 -2
- package/dist/meter.js.map +1 -1
- package/dist/motion.css +2 -2
- package/dist/native.js +4 -4
- package/dist/native.js.map +1 -1
- package/dist/nav-bar.js +7 -7
- package/dist/nav-bar.js.map +1 -1
- package/dist/product-page.js +1 -6
- package/dist/product-page.js.map +1 -1
- package/dist/progress.js +3 -3
- package/dist/progress.js.map +1 -1
- package/dist/rail-nav.js +1 -1
- package/dist/rail-nav.js.map +1 -1
- package/dist/service-card.js +2 -2
- package/dist/service-card.js.map +1 -1
- package/dist/settings-layout.js +1 -1
- package/dist/settings-layout.js.map +1 -1
- package/dist/site-footer.js +2 -2
- package/dist/site-footer.js.map +1 -1
- package/dist/skip-link.js +1 -1
- package/dist/slot-picker.js +1 -1
- package/dist/slot-picker.js.map +1 -1
- package/dist/step-progress.js +1 -1
- package/dist/step-progress.js.map +1 -1
- package/dist/tabs.js +4 -4
- package/dist/tabs.js.map +1 -1
- package/dist/tag-input.js +2 -2
- package/dist/tag-selector.js +1 -1
- package/dist/toast.js +1 -1
- package/dist/toast.js.map +1 -1
- package/package.json +5 -5
- package/registry/activity-feed.json +1 -1
- package/registry/app-shell.json +1 -1
- package/registry/badge.json +1 -1
- package/registry/card.json +1 -1
- package/registry/chip-row.json +1 -1
- package/registry/chip.json +1 -1
- package/registry/examples/badge/native/dot.dark.png +0 -0
- package/registry/examples/badge/native/dot.light.png +0 -0
- package/registry/examples/badge/native/scrim.dark.png +0 -0
- package/registry/examples/badge/native/scrim.light.png +0 -0
- package/registry/examples/badge/native/tones.dark.png +0 -0
- package/registry/examples/badge/native/tones.light.png +0 -0
- package/registry/examples/card/native/default.dark.png +0 -0
- package/registry/examples/card/native/default.light.png +0 -0
- package/registry/examples/card/native/elevated.dark.png +0 -0
- package/registry/examples/card/native/elevated.light.png +0 -0
- package/registry/examples/description-list/native/job-details.dark.png +0 -0
- package/registry/examples/description-list/native/job-details.light.png +0 -0
- package/registry/examples/meta-row/native/video.dark.png +0 -0
- package/registry/examples/meta-row/native/video.light.png +0 -0
- package/registry/examples/swipe-deck/native/discover.dark.png +0 -0
- package/registry/examples/swipe-deck/native/discover.light.png +0 -0
- package/registry/index.json +5 -5
- package/registry/landing-page.json +1 -1
- package/registry/language-switch.json +1 -1
- package/registry/map.json +1 -1
- package/registry/meter.json +1 -1
- package/registry/nav-bar.json +2 -2
- package/registry/product-page.json +1 -1
- package/registry/progress.json +1 -1
- package/registry/rail-nav.json +2 -2
- package/registry/service-card.json +1 -1
- package/registry/settings-layout.json +1 -1
- package/registry/site-footer.json +2 -2
- package/registry/skip-link.json +1 -1
- package/registry/slot-picker.json +1 -1
- package/registry/step-progress.json +1 -1
- package/registry/tabs.json +1 -1
- package/registry/toast.json +1 -1
- package/dist/chunk-63KCDMX2.js.map +0 -1
- package/dist/chunk-QDXV544C.js.map +0 -1
- /package/dist/{chunk-CKSHLSDH.js.map → chunk-AAP3U66V.js.map} +0 -0
- /package/dist/{chunk-K2ZYB4HP.js.map → chunk-S5LP7KKW.js.map} +0 -0
- /package/dist/{chunk-YOTQD7JD.js.map → chunk-WYQ277F2.js.map} +0 -0
package/dist/nav-bar.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-IANSFIVC.js";
|
|
8
8
|
import {
|
|
9
9
|
LanguageSwitch
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-VPO27AFS.js";
|
|
11
11
|
import {
|
|
12
12
|
useSlidingIndicator
|
|
13
13
|
} from "./chunk-4QN5YJ3D.js";
|
|
@@ -53,14 +53,14 @@ var navBar = tv({
|
|
|
53
53
|
// Two lines at most, wrapped at word boundaries — a longer one ends in an ellipsis, never cut mid-sentence.
|
|
54
54
|
menuText: "mt-0.5 block line-clamp-2 wrap-break-word text-xs leading-4 text-fg-secondary",
|
|
55
55
|
actions: "ml-auto flex items-center gap-2",
|
|
56
|
-
toggle: "inline-flex h-9 w-9 items-center justify-center rounded-
|
|
56
|
+
toggle: "inline-flex h-9 w-9 items-center justify-center rounded-sm border border-border-subtle bg-surface-2 text-fg md:hidden focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
|
|
57
57
|
mobile: "kz-pop absolute inset-x-0 top-full mt-2 grid gap-1 rounded-2xl border border-border-default bg-surface-1 p-2 shadow-lg md:hidden",
|
|
58
58
|
mobileGroup: "grid gap-0.5 [&+&]:mt-1 [&+&]:border-t [&+&]:border-border-subtle [&+&]:pt-2",
|
|
59
59
|
mobileGroupTitle: "px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary",
|
|
60
60
|
mobileLink: "flex items-center justify-between rounded-xl px-3 py-3 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg-accent",
|
|
61
61
|
// The family switcher: a chevron attached to the brand, its panel aligned on the bar's left edge.
|
|
62
62
|
family: "hidden md:block",
|
|
63
|
-
familyTrigger: "group/trigger -ml-2 mr-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-
|
|
63
|
+
familyTrigger: "group/trigger -ml-2 mr-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-sm text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg data-[state=open]:bg-surface-3 data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
|
|
64
64
|
familyViewport: "kz-pop absolute left-0 top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[width,height] duration-300 motion-reduce:transition-none",
|
|
65
65
|
familyPanel: "grid w-[min(92vw,42rem)] gap-x-2 gap-y-3 p-3 sm:grid-cols-2",
|
|
66
66
|
familyGroupTitle: "px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary",
|
|
@@ -68,15 +68,15 @@ var navBar = tv({
|
|
|
68
68
|
familyMark: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-fg",
|
|
69
69
|
familyName: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm font-semibold text-fg",
|
|
70
70
|
familyText: "mt-0.5 block text-xs leading-relaxed text-fg-secondary",
|
|
71
|
-
familyTag: "rounded-
|
|
71
|
+
familyTag: "rounded-sm px-1.5 py-px text-[10px] font-semibold",
|
|
72
72
|
mobileFamily: "mt-1 grid gap-2 border-t border-border-subtle px-1 pb-1 pt-3",
|
|
73
73
|
mobileFamilyLink: "flex min-h-11 items-center gap-3 rounded-xl px-2 py-2 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft",
|
|
74
|
-
badge: "hidden h-6 shrink-0 items-center gap-1 rounded-
|
|
75
|
-
repo: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-
|
|
74
|
+
badge: "hidden h-6 shrink-0 items-center gap-1 rounded-sm border border-border-subtle bg-surface-2 px-2 font-mono text-[11px] font-medium text-fg-secondary sm:inline-flex",
|
|
75
|
+
repo: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-sm text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
|
|
76
76
|
},
|
|
77
77
|
variants: {
|
|
78
78
|
floating: {
|
|
79
|
-
true: { root: "max-w-5xl rounded-
|
|
79
|
+
true: { root: "max-w-5xl rounded-sm border pl-5 pr-2 data-compact:max-w-4xl" },
|
|
80
80
|
false: { root: "border-b px-4 md:px-6" }
|
|
81
81
|
}
|
|
82
82
|
},
|
package/dist/nav-bar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/nav-bar/nav-bar.tsx","../src/nav-bar/placement.ts"],"sourcesContent":["// Client (scroll, a sliding indicator, menus). Radix NavigationMenu does the menus' semantics and keyboard (Enter, Space\n// and ↓ open; ↑ ↓ Home End walk; Escape closes and returns the focus; Tab out closes); this file draws the Krizaka bar:\n// a floating pill that tightens once the page scrolls, one light that glides to the item under the pointer or the\n// focus and rests on the current page, and a mobile panel that is a plain disclosure (no focus trap, Escape closes).\nimport { NavigationMenu as Nav, Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { FamilyMark, GitHubGlyph } from \"../family-mark\";\nimport { LanguageSwitch, type LanguageSwitchProps } from \"../language-switch/language-switch\";\nimport { type FamilyLabels, familyLabels, type Site, type SiteId, sitesByGroup } from \"../sites/sites\";\nimport { useSlidingIndicator } from \"../sliding-indicator\";\nimport { placePanel } from \"./placement\";\n\nexport const navBar = tv({\n slots: {\n root:\n \"group/nav relative z-40 mx-auto flex h-14 w-full items-center gap-2 border-border-subtle bg-surface-1 \" +\n \"transition-[height,background-color,border-color,box-shadow] duration-300 motion-reduce:transition-none \" +\n \"data-compact:h-12 data-compact:border-border-default data-compact:bg-surface-1 data-compact:shadow-lg\",\n brand:\n \"mr-2 inline-flex shrink-0 items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg no-underline \" +\n \"rounded-md focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n items: \"relative hidden md:block\",\n list:\n \"group/list relative isolate flex items-center gap-0.5 \" +\n // The ink rule (Cahier, ADR-004): a pen line under the item that is pointed at or focused, resting on the current page.\n \"before:absolute before:left-0 before:top-0 before:-z-10 before:h-0.5 before:w-(--kz-ind-w) before:translate-x-(--kz-ind-x) before:translate-y-[calc(var(--kz-ind-y)+var(--kz-ind-h)-6px)] \" +\n \"before:scale-x-[0.72] before:bg-fg before:opacity-0 before:transition-[translate,width,opacity] before:duration-300 motion-reduce:before:transition-none \" +\n \"data-[indicator=on]:before:opacity-100\",\n item:\n \"inline-flex h-9 select-none items-center gap-1 rounded-sm px-3.5 text-sm font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:text-fg data-active:text-fg data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n // Before the light is ready (server render), the current page carries its own tint.\n \"group-not-data-[indicator=on]/list:data-active:underline group-not-data-[indicator=on]/list:data-active:decoration-2 group-not-data-[indicator=on]/list:data-active:underline-offset-8\",\n chevron: \"h-3.5 w-3.5 transition-transform duration-300 group-data-[state=open]/trigger:rotate-180 motion-reduce:transition-none\",\n viewport:\n // `left` is set by NavBarItems (--kz-menu-left): the panel's edge under its trigger, kept inside the page.\n \"kz-pop absolute left-[var(--kz-menu-left,0px)] top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden \" +\n \"rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[left,width,height] duration-300 motion-reduce:transition-none\",\n // Icon · title · a description of two lines at most. 28 rem (40 rem in two columns), never wider than the page\n // between its gutters, and never taller than the screen.\n panel: \"grid w-[min(28rem,calc(100vw-2rem))] max-h-[calc(100dvh-6rem)] gap-0.5 overflow-y-auto p-1.5\",\n panelWide: \"w-[min(40rem,calc(100vw-2rem))] md:grid-cols-2\",\n menuLink:\n \"group/link flex items-start gap-3 rounded-lg px-2.5 py-2 text-left no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring data-active:bg-accent-soft\",\n menuIcon:\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-border-default bg-surface-2 text-fg-accent \" +\n \"transition-[transform,border-color] duration-300 group-hover/link:-translate-y-0.5 group-hover/link:border-accent [&>svg]:h-4 [&>svg]:w-4 motion-reduce:transform-none\",\n menuTitle: \"block line-clamp-2 wrap-break-word text-sm font-semibold leading-5 text-fg\",\n // Two lines at most, wrapped at word boundaries — a longer one ends in an ellipsis, never cut mid-sentence.\n menuText: \"mt-0.5 block line-clamp-2 wrap-break-word text-xs leading-4 text-fg-secondary\",\n actions: \"ml-auto flex items-center gap-2\",\n toggle:\n \"inline-flex h-9 w-9 items-center justify-center rounded-full border border-border-subtle bg-surface-2 text-fg md:hidden \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n mobile: \"kz-pop absolute inset-x-0 top-full mt-2 grid gap-1 rounded-2xl border border-border-default bg-surface-1 p-2 shadow-lg md:hidden\",\n mobileGroup: \"grid gap-0.5 [&+&]:mt-1 [&+&]:border-t [&+&]:border-border-subtle [&+&]:pt-2\",\n mobileGroupTitle: \"px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary\",\n mobileLink:\n \"flex items-center justify-between rounded-xl px-3 py-3 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg-accent\",\n // The family switcher: a chevron attached to the brand, its panel aligned on the bar's left edge.\n family: \"hidden md:block\",\n familyTrigger:\n \"group/trigger -ml-2 mr-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-fg-secondary transition-colors \" +\n \"hover:bg-surface-3 hover:text-fg data-[state=open]:bg-surface-3 data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n familyViewport:\n \"kz-pop absolute left-0 top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden \" +\n \"rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[width,height] duration-300 motion-reduce:transition-none\",\n familyPanel: \"grid w-[min(92vw,42rem)] gap-x-2 gap-y-3 p-3 sm:grid-cols-2\",\n familyGroupTitle: \"px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary\",\n familyLink:\n \"group/link flex items-start gap-3 rounded-xl px-3 py-2.5 text-left no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft\",\n familyMark: \"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-fg\",\n familyName: \"flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm font-semibold text-fg\",\n familyText: \"mt-0.5 block text-xs leading-relaxed text-fg-secondary\",\n familyTag: \"rounded-full px-1.5 py-px text-[10px] font-semibold\",\n mobileFamily: \"mt-1 grid gap-2 border-t border-border-subtle px-1 pb-1 pt-3\",\n mobileFamilyLink:\n \"flex min-h-11 items-center gap-3 rounded-xl px-2 py-2 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft\",\n badge:\n \"hidden h-6 shrink-0 items-center gap-1 rounded-full border border-border-subtle bg-surface-2 px-2 font-mono text-[11px] font-medium text-fg-secondary sm:inline-flex\",\n repo:\n \"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n variants: {\n floating: {\n true: { root: \"max-w-5xl rounded-full border pl-5 pr-2 data-compact:max-w-4xl\" },\n false: { root: \"border-b px-4 md:px-6\" },\n },\n },\n defaultVariants: { floating: true },\n});\nconst s = navBar();\n\ninterface NavBarContext {\n label: string;\n open: boolean;\n setOpen: (open: boolean) => void;\n panelId: string;\n}\nconst Context = React.createContext<NavBarContext | null>(null);\n/** The open menu of `NavBar.Items` (`\"\"`: none), so a plain link can close it when the pointer moves on to it. */\nconst ItemsContext = React.createContext<{ close: () => void }>({ close: () => {} });\n/** True inside `NavBar.Mobile`: the family renders as the panel's last group instead of a switcher. */\nconst MobileContext = React.createContext(false);\nconst useNavBar = () => {\n const ctx = React.useContext(Context);\n if (!ctx) throw new Error(\"NavBar parts must be inside <NavBar.Root>.\");\n return ctx;\n};\n\nexport type NavBarRootProps = React.ComponentProps<\"header\"> & {\n /** The accessible name of the navigation (“Main”) — passed translated. */\n label: string;\n /**\n * Pixels of scroll after which the bar tightens (denser, lower, lifted). `false`: never.\n * @default 24\n */\n compactAfter?: number | false;\n /**\n * A floating pill (the Krizaka bar) or a full-width bar with a hairline under it.\n * @default true\n */\n floating?: boolean;\n};\n\n/** The bar. Place it in a `sticky top-3` (floating) or `sticky top-0` wrapper — or let it scroll. */\nexport function NavBarRoot({ label, compactAfter = 24, floating = true, className, children, ...props }: NavBarRootProps) {\n const [compact, setCompact] = React.useState(false);\n const [open, setOpen] = React.useState(false);\n const panelId = React.useId();\n React.useEffect(() => {\n if (compactAfter === false) return;\n const onScroll = () => setCompact(window.scrollY > compactAfter);\n onScroll();\n window.addEventListener(\"scroll\", onScroll, { passive: true });\n return () => window.removeEventListener(\"scroll\", onScroll);\n }, [compactAfter]);\n const ctx = React.useMemo(() => ({ label, open, setOpen, panelId }), [label, open, panelId]);\n return (\n <Context.Provider value={ctx}>\n <header data-compact={compact ? \"\" : undefined} data-floating={floating} className={navBar({ floating }).root({ className })} {...props}>\n {children}\n </header>\n </Context.Provider>\n );\n}\n\nexport type NavBarBrandProps = React.ComponentProps<\"a\"> & {\n /** Renders your link (a router `<Link>`) with the brand's look. */\n asChild?: boolean;\n};\n\n/** The brand: a mark and a name, linking home. */\nexport function NavBarBrand({ asChild, className, ...props }: NavBarBrandProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp className={s.brand({ className })} {...props} />;\n}\n\nexport type NavBarItemsProps = Omit<React.ComponentProps<typeof Nav.Root>, \"orientation\">;\n\n/**\n * The desktop navigation: links and menus, with the light that glides between them. Hidden below `md` (see\n * `NavBar.Mobile`). A menu opens on click, Enter, Space or ↓ — or when the pointer rests on its trigger (hover intent,\n * `delayDuration`, 200 ms): passing over the bar opens nothing. While a menu is open the light stays on its trigger;\n * moving on to a plain link closes the menu, so the bar never shows two current items. A click outside or Escape closes.\n */\nexport function NavBarItems({ className, children, value: valueProp, defaultValue, onValueChange, delayDuration = 200, ...props }: NavBarItemsProps) {\n const { label } = useNavBar();\n const [inner, setInner] = React.useState(defaultValue ?? \"\");\n const value = valueProp ?? inner;\n const setValue = React.useCallback(\n (next: string) => {\n setInner(next);\n onValueChange?.(next);\n },\n [onValueChange],\n );\n const items = React.useMemo(() => ({ close: () => setValue(\"\") }), [setValue]);\n const { ref, handlers } = useSlidingIndicator<HTMLUListElement>({\n item: \"[data-nav-item]\",\n active: \"[data-nav-item][data-active]\",\n prefer: \"[data-nav-item][data-state=open]\",\n follow: true,\n });\n const root = React.useRef<HTMLElement>(null);\n const viewport = React.useRef<HTMLDivElement>(null);\n // The open panel sits under its trigger and stays inside the page (collision): measured when a menu opens, when\n // the panel changes size (another menu) and when the window does.\n React.useLayoutEffect(() => {\n const panel = viewport.current;\n const nav = root.current;\n if (!panel || !nav || !value) return;\n const place = () => {\n const trigger = nav.querySelector<HTMLElement>(\"[data-nav-item][data-state=open]\");\n const width = Number.parseFloat(panel.style.getPropertyValue(\"--radix-navigation-menu-viewport-width\"));\n if (!trigger || !Number.isFinite(width)) return;\n const left = `${placePanel({ trigger: trigger.getBoundingClientRect().left, root: nav.getBoundingClientRect().left, panel: width, window: document.documentElement.clientWidth })}px`;\n if (panel.style.getPropertyValue(\"--kz-menu-left\") !== left) panel.style.setProperty(\"--kz-menu-left\", left);\n };\n place();\n const watch = new MutationObserver(place);\n watch.observe(panel, { attributes: true, attributeFilter: [\"style\"] });\n window.addEventListener(\"resize\", place);\n return () => {\n watch.disconnect();\n window.removeEventListener(\"resize\", place);\n };\n }, [value]);\n return (\n <ItemsContext.Provider value={items}>\n <Nav.Root ref={root} aria-label={label} className={s.items({ className })} value={value} onValueChange={setValue} delayDuration={delayDuration} {...props}>\n <Nav.List ref={ref} className={s.list()} {...handlers}>\n {children}\n </Nav.List>\n <Nav.Viewport ref={viewport} className={s.viewport()} />\n </Nav.Root>\n </ItemsContext.Provider>\n );\n}\n\nexport type NavBarLinkProps = Omit<React.ComponentProps<typeof Nav.Link>, \"active\"> & {\n /** The current page: `aria-current=\"page\"`, and the light rests on it. */\n active?: boolean;\n /** Classes on the list item around the link (to show it from a breakpoint only). */\n itemClassName?: string;\n};\n\n/** A link of the bar. `asChild` renders your router's `<Link>`. */\nexport function NavBarLink({ active, className, itemClassName, onPointerEnter, ...props }: NavBarLinkProps) {\n const { close } = React.useContext(ItemsContext);\n return (\n <Nav.Item className={itemClassName}>\n <Nav.Link\n data-nav-item=\"\"\n data-active={active ? \"\" : undefined}\n active={active}\n aria-current={active ? \"page\" : undefined}\n className={s.item({ className })}\n onPointerEnter={(e) => {\n onPointerEnter?.(e);\n close();\n }}\n {...props}\n />\n </Nav.Item>\n );\n}\n\nexport type NavBarMenuProps = Omit<React.ComponentProps<typeof Nav.Item>, \"children\"> & {\n /** The trigger's words (“Products”) — passed translated. */\n label: string;\n /** The current page is inside this menu: the light rests on its trigger. */\n active?: boolean;\n /** The menu's links (`NavBar.MenuLink`), laid out in a panel; `columns` sets the grid. */\n children: React.ReactNode;\n /**\n * Columns of the panel.\n * @default 1\n */\n columns?: 1 | 2;\n /**\n * A section with this many links or fewer needs no hidden list: they sit in the bar as plain links (the active one\n * marked, no dropdown, `label` unused on the desktop). Above it, a dropdown. `0` always makes a dropdown.\n * @default 3\n */\n inlineUpTo?: number;\n /**\n * From which breakpoint the inline links stand in the bar. Below it (between the phone panel at `md` and this\n * breakpoint) the section is the dropdown, so long labels never overflow a tablet-width bar. `md` inlines as soon as\n * the bar is shown.\n * @default \"lg\"\n */\n inlineFrom?: \"md\" | \"lg\" | \"xl\";\n};\n\n// Static class names (Tailwind reads them at build time).\nconst INLINE_HIDE = { md: \"\", lg: \"max-lg:hidden\", xl: \"max-xl:hidden\" } as const;\nconst DROPDOWN_HIDE = { md: \"\", lg: \"lg:hidden\", xl: \"xl:hidden\" } as const;\n\n/**\n * A menu of the bar: its trigger, and its links in a panel that opens under the bar. A menu of `inlineUpTo` links or\n * fewer (3 by default) is not a menu at all: its links stand in the bar, each with its active state — a hidden list of\n * three is one click more for nothing. The phone's panel groups them as usual (`NavBar.MobileGroup`).\n */\nexport function NavBarMenu({ label, active, columns = 1, inlineUpTo = 3, inlineFrom = \"lg\", children, className, ...props }: NavBarMenuProps) {\n const links = React.Children.toArray(children);\n const dropdown = (hide: string) => (\n <Nav.Item className={cn(hide, className)} {...props}>\n <Nav.Trigger data-nav-item=\"\" data-active={active ? \"\" : undefined} className={cn(s.item(), \"group/trigger\")}>\n {label}\n <svg viewBox=\"0 0 24 24\" className={s.chevron()} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </Nav.Trigger>\n <Nav.Content className={cn(s.panel(), columns === 2 && s.panelWide())}>{children}</Nav.Content>\n </Nav.Item>\n );\n const inline = links.length > 0 && links.length <= inlineUpTo && links.every((c) => React.isValidElement(c) && c.type === NavBarMenuLink);\n if (inline) {\n return (\n <>\n {inlineFrom !== \"md\" && dropdown(DROPDOWN_HIDE[inlineFrom])}\n {links.map((link) => {\n const { title, href, active: here, asChild, children: child, icon: _icon, description: _description, className: linkClass, ...rest } = (link as React.ReactElement<NavBarMenuLinkProps>).props;\n return (\n <NavBarLink key={(link as React.ReactElement).key} asChild={asChild} href={asChild ? undefined : href} active={here} className={linkClass} itemClassName={INLINE_HIDE[inlineFrom]} {...rest}>\n {asChild && React.isValidElement<{ children?: React.ReactNode }>(child) ? React.cloneElement(child, undefined, title) : title}\n </NavBarLink>\n );\n })}\n </>\n );\n }\n return dropdown(\"\");\n}\n\nexport type NavBarMenuLinkProps = Omit<React.ComponentProps<typeof Nav.Link>, \"title\" | \"active\"> & {\n /** The link's name — passed translated. */\n title: string;\n /** One line under it — passed translated. */\n description?: string;\n /** An icon (a signature icon of `@krizaka/icons`: its node lights up on hover). */\n icon?: React.ReactNode;\n /** The current page. */\n active?: boolean;\n};\n\n/** A link inside a menu: an icon, a name and a line of text. */\nexport function NavBarMenuLink({ title, description, icon, active, href, className, asChild, children, ...props }: NavBarMenuLinkProps) {\n const body = (\n <>\n {icon && <span className={s.menuIcon()}>{icon}</span>}\n <span className=\"min-w-0 flex-1\">\n <span className={s.menuTitle()}>{title}</span>\n {description && <span className={s.menuText()}>{description}</span>}\n </span>\n </>\n );\n return (\n <Nav.Link asChild={asChild} href={asChild ? undefined : href} active={active} aria-current={active ? \"page\" : undefined} data-active={active ? \"\" : undefined} className={s.menuLink({ className })} {...props}>\n {asChild && React.isValidElement<{ children?: React.ReactNode }>(children) ? React.cloneElement(children, undefined, body) : body}\n </Nav.Link>\n );\n}\n\n/** The right side: search, theme, language, the call to action. */\nexport function NavBarActions({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.actions({ className })} {...props} />;\n}\n\nexport type NavBarMobileProps = React.ComponentProps<\"nav\"> & {\n /** The toggle's name when closed (“Open the menu”) — passed translated. */\n openLabel: string;\n /** The toggle's name when open (“Close the menu”) — passed translated. */\n closeLabel: string;\n};\n\n/**\n * Below `md`: a toggle, and a panel under the bar with its links (`NavBar.MobileLink`), grouped like the bar's menus\n * (`NavBar.MobileGroup`). A disclosure: Escape, a click on a link or a press outside close it; Escape returns the focus\n * to the toggle.\n */\nexport function NavBarMobile({ openLabel, closeLabel, className, children, ...props }: NavBarMobileProps) {\n const { label, open, setOpen, panelId } = useNavBar();\n const toggle = React.useRef<HTMLButtonElement>(null);\n React.useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n setOpen(false);\n toggle.current?.focus();\n };\n // A press outside the panel and its toggle closes it (the page under it stays usable).\n const onPress = (e: PointerEvent) => {\n const target = e.target as Node | null;\n if (!target || toggle.current?.contains(target) || document.getElementById(panelId)?.contains(target)) return;\n setOpen(false);\n };\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(\"pointerdown\", onPress);\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.removeEventListener(\"pointerdown\", onPress);\n };\n }, [open, setOpen, panelId]);\n return (\n <>\n <button ref={toggle} type=\"button\" aria-expanded={open} aria-controls={panelId} aria-label={open ? closeLabel : openLabel} onClick={() => setOpen(!open)} className={s.toggle()}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4.5 w-4.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n {open ? <path d=\"M18 6 6 18M6 6l12 12\" /> : <path d=\"M4 7h16M4 12h16M4 17h10\" />}\n </svg>\n </button>\n {open && (\n <nav\n id={panelId}\n aria-label={label}\n className={s.mobile({ className })}\n onClick={(e) => {\n if ((e.target as Element).closest(\"a\")) setOpen(false);\n }}\n {...props}\n >\n <MobileContext.Provider value>{children}</MobileContext.Provider>\n </nav>\n )}\n </>\n );\n}\n\nexport type NavBarMobileGroupProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The group's heading — the same words as the bar's menu (“Product”) — passed translated. */\n label: string;\n};\n\n/** A group of the mobile panel: the links of one of the bar's menus under its name, in the same order. */\nexport function NavBarMobileGroup({ label, className, children, ...props }: NavBarMobileGroupProps) {\n const id = React.useId();\n return (\n <div role=\"group\" aria-labelledby={id} className={s.mobileGroup({ className })} {...props}>\n <p id={id} className={s.mobileGroupTitle()}>\n {label}\n </p>\n {children}\n </div>\n );\n}\n\nexport type NavBarMobileLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the mobile panel. */\nexport function NavBarMobileLink({ active, asChild, className, ...props }: NavBarMobileLinkProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.mobileLink({ className })} {...props} />;\n}\n\n\nconst tagTone = {\n upcoming: \"bg-accent-soft text-fg ring-1 ring-inset ring-accent/40\",\n construction: \"bg-warning/15 text-fg ring-1 ring-inset ring-warning/40\",\n development: \"bg-surface-3 text-fg ring-1 ring-inset ring-border-strong\",\n current: \"bg-surface-3 text-fg-secondary\",\n};\n\n/** A site's name and its tags: status when not released, “You are here” on the current one. */\nfunction FamilyName({ site, current, labels }: { site: Site; current: boolean; labels: FamilyLabels }) {\n return (\n <span className={s.familyName()}>\n {site.name}\n {site.status !== \"released\" && <span className={cn(s.familyTag(), tagTone[site.status])}>{labels.status[site.status]}</span>}\n {current && <span className={cn(s.familyTag(), tagTone.current)}>{labels.current}</span>}\n </span>\n );\n}\n\nexport type NavBarFamilyProps = {\n /** The site this bar belongs to (`@krizaka/ui/sites`): marked in the family, `aria-current=\"true\"`. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** Opens the panel at first render (a story, a screenshot). */\n defaultOpen?: boolean;\n /** Classes of the switcher (or, inside `NavBar.Mobile`, of the family's group). */\n className?: string;\n};\n\n/**\n * The family switcher, attached to the brand (place it right after `NavBar.Brand`): a chevron that opens every site of\n * Krizaka grouped — Krizaka · Products · Open source · GitHub — the current one marked. It opens on click, Enter, Space\n * or ↓ (never on hover); ↑ ↓ walk the sites, Escape closes and returns the focus. Hidden below `md`: place a second\n * `NavBar.Family` as the last child of `NavBar.Mobile`, where it renders as the panel's last group.\n */\nexport function NavBarFamily({ current, labels = familyLabels.en, defaultOpen, className }: NavBarFamilyProps) {\n const inMobile = React.useContext(MobileContext);\n const id = React.useId();\n const groups = sitesByGroup();\n if (inMobile) {\n return (\n <div role=\"group\" aria-labelledby={`${id}-family`} className={s.mobileFamily({ className })}>\n <p id={`${id}-family`} className={s.familyGroupTitle()}>\n {labels.family}\n </p>\n {groups.map(({ group, sites }) => (\n <div key={group}>\n {/* The company's own group is named like the family itself: its heading would repeat the panel's. */}\n {group !== \"krizaka\" && (\n <p id={`${id}-${group}`} className={s.familyGroupTitle()}>\n {labels.groups[group]}\n </p>\n )}\n <ul aria-labelledby={group !== \"krizaka\" ? `${id}-${group}` : `${id}-family`} className=\"grid gap-0.5\">\n {sites.map((site) => (\n <li key={site.id}>\n <a href={site.url} data-current={site.id === current ? \"\" : undefined} aria-current={site.id === current ? \"true\" : undefined} className={s.mobileFamilyLink()}>\n <span className={s.familyMark()}>\n <FamilyMark mark={site.mark} size={24} />\n </span>\n <FamilyName site={site} current={site.id === current} labels={labels} />\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n );\n }\n // Click only: a pointer passing over the brand never opens the family (Radix opens its menus on hover by default).\n const noHover = (e: React.PointerEvent) => e.preventDefault();\n const columns = [groups.filter((g) => g.group === \"krizaka\" || g.group === \"products\"), groups.filter((g) => g.group === \"open-source\" || g.group === \"github\")];\n return (\n <Nav.Root aria-label={labels.family} defaultValue={defaultOpen ? \"family\" : undefined} className={s.family({ className })}>\n <Nav.List className=\"flex\">\n <Nav.Item value=\"family\">\n <Nav.Trigger aria-label={labels.family} onPointerMove={noHover} onPointerLeave={noHover} className={s.familyTrigger()}>\n <svg viewBox=\"0 0 24 24\" className={s.chevron()} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </Nav.Trigger>\n <Nav.Content onPointerLeave={noHover} className={s.familyPanel()}>\n {columns.map((column, i) => (\n <div key={i} className=\"grid content-start gap-3\">\n {column.map(({ group, sites }) => (\n <div key={group}>\n <p id={`${id}-${group}`} className={s.familyGroupTitle()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className=\"grid gap-0.5\">\n {sites.map((site) => (\n <li key={site.id}>\n <Nav.Link href={site.url} data-current={site.id === current ? \"\" : undefined} aria-current={site.id === current ? \"true\" : undefined} className={s.familyLink()}>\n <span className={s.familyMark()}>\n <FamilyMark mark={site.mark} size={28} />\n </span>\n <span className=\"min-w-0\">\n <FamilyName site={site} current={site.id === current} labels={labels} />\n <span className={s.familyText()}>{labels.descriptions[site.id]}</span>\n </span>\n </Nav.Link>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n ))}\n </Nav.Content>\n </Nav.Item>\n </Nav.List>\n <Nav.Viewport onPointerLeave={noHover} className={s.familyViewport()} />\n </Nav.Root>\n );\n}\n\nexport type NavBarBadgeProps = React.ComponentProps<\"span\"> & {\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n};\n\n/** A small mono badge beside the brand: the environment and the version (`DEV · v1.2.3`). Hidden below `sm`. */\nexport function NavBarBadge({ env, version, className, children, ...props }: NavBarBadgeProps) {\n const parts = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean);\n return (\n <span className={s.badge({ className })} {...props}>\n {parts.join(\" · \")}\n {children}\n </span>\n );\n}\n\nexport type NavBarLanguageProps = Omit<LanguageSwitchProps, \"variant\">;\n\n/**\n * The language switch, the same on every site: in the bar a globe and the current code (FR) opening a short menu of\n * the languages by their own names; inside `NavBar.Mobile` the same languages as a row in the preferences.\n */\nexport function NavBarLanguage(props: NavBarLanguageProps) {\n const inMobile = React.useContext(MobileContext);\n return <LanguageSwitch variant={inMobile ? \"inline\" : \"menu\"} {...props} />;\n}\n\nexport type NavBarMobilePreferencesProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The group's heading (“Preferences”) — passed translated. */\n label: string;\n};\n\n/** The last group of the mobile panel: the preferences (theme, `NavBar.Language`), in a row under their heading. */\nexport function NavBarMobilePreferences({ label, className, children, ...props }: NavBarMobilePreferencesProps) {\n const id = React.useId();\n return (\n <div role=\"group\" aria-labelledby={id} className={s.mobileGroup({ className })} {...props}>\n <p id={id} className={s.mobileGroupTitle()}>\n {label}\n </p>\n <div className=\"flex flex-wrap items-center gap-2 px-3 py-1\">{children}</div>\n </div>\n );\n}\n\nexport type NavBarRepoProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The repository the site is built from. */\n href: string;\n /** The link's accessible name (“Source on GitHub”) — passed translated. */\n label: string;\n};\n\n/** The site's repository on GitHub, an icon link of `NavBar.Actions`. */\nexport function NavBarRepo({ label, className, ...props }: NavBarRepoProps) {\n return (\n <a aria-label={label} className={s.repo({ className })} {...props}>\n <GitHubGlyph size={18} />\n </a>\n );\n}\n\n/**\n * `NavBar.Root/Brand/Family/Badge/Items/Link/Menu/MenuLink/Actions/Repo/Language/Mobile/MobileGroup/MobilePreferences/MobileLink` — the Krizaka navigation bar,\n * the same on every site of the family: floating, tightening on scroll, the family switcher on the brand, one light\n * gliding between its items, accessible menus, a mobile panel.\n */\nexport const NavBar = {\n Root: NavBarRoot,\n Brand: NavBarBrand,\n Family: NavBarFamily,\n Badge: NavBarBadge,\n Items: NavBarItems,\n Link: NavBarLink,\n Menu: NavBarMenu,\n MenuLink: NavBarMenuLink,\n Actions: NavBarActions,\n Repo: NavBarRepo,\n Language: NavBarLanguage,\n Mobile: NavBarMobile,\n MobilePreferences: NavBarMobilePreferences,\n MobileGroup: NavBarMobileGroup,\n MobileLink: NavBarMobileLink,\n};\n","/**\n * Where a menu panel of the bar sits: its left edge under its trigger's, pushed back inside the page when it would run\n * past the right edge, never closer to the left edge than the gutter. All values are pixels of the page (a bounding\n * rect's `left`, a width), the result is the panel's `left` relative to the bar's navigation (`root`). Pure, so a\n * viewport of 360 px and one of 1280 px are tested without a browser.\n */\nexport interface PlacePanel {\n /** The trigger's left edge. */\n trigger: number;\n /** The navigation's left edge (the panel is positioned inside it). */\n root: number;\n /** The panel's width. */\n panel: number;\n /** The window's width. */\n window: number;\n /**\n * The space kept between the panel and the window's edges.\n * @default 16\n */\n gutter?: number;\n}\n\nexport function placePanel({ trigger, root, panel, window, gutter = 16 }: PlacePanel): number {\n const wanted = trigger - root;\n const farthest = window - gutter - panel - root;\n const nearest = gutter - root;\n return Math.round(Math.max(nearest, Math.min(wanted, farthest)));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAIA,SAAS,kBAAkB,KAAK,YAAY;AAC5C,YAAY,WAAW;AACvB,SAAS,UAAU;;;ACgBZ,SAAS,WAAW,EAAE,SAAS,MAAM,OAAO,QAAAA,SAAQ,SAAS,GAAG,GAAuB;AAC5F,QAAM,SAAS,UAAU;AACzB,QAAM,WAAWA,UAAS,SAAS,QAAQ;AAC3C,QAAM,UAAU,SAAS;AACzB,SAAO,KAAK,MAAM,KAAK,IAAI,SAAS,KAAK,IAAI,QAAQ,QAAQ,CAAC,CAAC;AACjE;;;ADyHM,SAgKA,UAhKA,KAsEA,YAtEA;AArIC,IAAM,SAAS,GAAG;AAAA,EACvB,OAAO;AAAA,IACL,MACE;AAAA,IAGF,OACE;AAAA,IAEF,OAAO;AAAA,IACP,MACE;AAAA,IAKF,MACE;AAAA,IAIF,SAAS;AAAA,IACT;AAAA;AAAA,MAEE;AAAA;AAAA;AAAA;AAAA,IAIF,OAAO;AAAA,IACP,WAAW;AAAA,IACX,UACE;AAAA,IAEF,UACE;AAAA,IAEF,WAAW;AAAA;AAAA,IAEX,UAAU;AAAA,IACV,SAAS;AAAA,IACT,QACE;AAAA,IAEF,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,YACE;AAAA;AAAA,IAGF,QAAQ;AAAA,IACR,eACE;AAAA,IAEF,gBACE;AAAA,IAEF,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,YACE;AAAA,IAEF,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,cAAc;AAAA,IACd,kBACE;AAAA,IAEF,OACE;AAAA,IACF,MACE;AAAA,EAEJ;AAAA,EACA,UAAU;AAAA,IACR,UAAU;AAAA,MACR,MAAM,EAAE,MAAM,iEAAiE;AAAA,MAC/E,OAAO,EAAE,MAAM,wBAAwB;AAAA,IACzC;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,UAAU,KAAK;AACpC,CAAC;AACD,IAAM,IAAI,OAAO;AAQjB,IAAM,UAAgB,oBAAoC,IAAI;AAE9D,IAAM,eAAqB,oBAAqC,EAAE,OAAO,MAAM;AAAC,EAAE,CAAC;AAEnF,IAAM,gBAAsB,oBAAc,KAAK;AAC/C,IAAM,YAAY,MAAM;AACtB,QAAM,MAAY,iBAAW,OAAO;AACpC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,4CAA4C;AACtE,SAAO;AACT;AAkBO,SAAS,WAAW,EAAE,OAAO,eAAe,IAAI,WAAW,MAAM,WAAW,UAAU,GAAG,MAAM,GAAoB;AACxH,QAAM,CAAC,SAAS,UAAU,IAAU,eAAS,KAAK;AAClD,QAAM,CAAC,MAAM,OAAO,IAAU,eAAS,KAAK;AAC5C,QAAM,UAAgB,YAAM;AAC5B,EAAM,gBAAU,MAAM;AACpB,QAAI,iBAAiB,MAAO;AAC5B,UAAM,WAAW,MAAM,WAAW,OAAO,UAAU,YAAY;AAC/D,aAAS;AACT,WAAO,iBAAiB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC;AAC7D,WAAO,MAAM,OAAO,oBAAoB,UAAU,QAAQ;AAAA,EAC5D,GAAG,CAAC,YAAY,CAAC;AACjB,QAAM,MAAY,cAAQ,OAAO,EAAE,OAAO,MAAM,SAAS,QAAQ,IAAI,CAAC,OAAO,MAAM,OAAO,CAAC;AAC3F,SACE,oBAAC,QAAQ,UAAR,EAAiB,OAAO,KACvB,8BAAC,YAAO,gBAAc,UAAU,KAAK,QAAW,iBAAe,UAAU,WAAW,OAAO,EAAE,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC/H,UACH,GACF;AAEJ;AAQO,SAAS,YAAY,EAAE,SAAS,WAAW,GAAG,MAAM,GAAqB;AAC9E,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SAAO,oBAAC,QAAK,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AAC7D;AAUO,SAAS,YAAY,EAAE,WAAW,UAAU,OAAO,WAAW,cAAc,eAAe,gBAAgB,KAAK,GAAG,MAAM,GAAqB;AACnJ,QAAM,EAAE,MAAM,IAAI,UAAU;AAC5B,QAAM,CAAC,OAAO,QAAQ,IAAU,eAAS,gBAAgB,EAAE;AAC3D,QAAM,QAAQ,aAAa;AAC3B,QAAM,WAAiB;AAAA,IACrB,CAAC,SAAiB;AAChB,eAAS,IAAI;AACb,sBAAgB,IAAI;AAAA,IACtB;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AACA,QAAM,QAAc,cAAQ,OAAO,EAAE,OAAO,MAAM,SAAS,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC;AAC7E,QAAM,EAAE,KAAK,SAAS,IAAI,oBAAsC;AAAA,IAC9D,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AACD,QAAM,OAAa,aAAoB,IAAI;AAC3C,QAAM,WAAiB,aAAuB,IAAI;AAGlD,EAAM,sBAAgB,MAAM;AAC1B,UAAM,QAAQ,SAAS;AACvB,UAAM,MAAM,KAAK;AACjB,QAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAO;AAC9B,UAAM,QAAQ,MAAM;AAClB,YAAM,UAAU,IAAI,cAA2B,kCAAkC;AACjF,YAAM,QAAQ,OAAO,WAAW,MAAM,MAAM,iBAAiB,wCAAwC,CAAC;AACtG,UAAI,CAAC,WAAW,CAAC,OAAO,SAAS,KAAK,EAAG;AACzC,YAAM,OAAO,GAAG,WAAW,EAAE,SAAS,QAAQ,sBAAsB,EAAE,MAAM,MAAM,IAAI,sBAAsB,EAAE,MAAM,OAAO,OAAO,QAAQ,SAAS,gBAAgB,YAAY,CAAC,CAAC;AACjL,UAAI,MAAM,MAAM,iBAAiB,gBAAgB,MAAM,KAAM,OAAM,MAAM,YAAY,kBAAkB,IAAI;AAAA,IAC7G;AACA,UAAM;AACN,UAAM,QAAQ,IAAI,iBAAiB,KAAK;AACxC,UAAM,QAAQ,OAAO,EAAE,YAAY,MAAM,iBAAiB,CAAC,OAAO,EAAE,CAAC;AACrE,WAAO,iBAAiB,UAAU,KAAK;AACvC,WAAO,MAAM;AACX,YAAM,WAAW;AACjB,aAAO,oBAAoB,UAAU,KAAK;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AACV,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAC5B,+BAAC,IAAI,MAAJ,EAAS,KAAK,MAAM,cAAY,OAAO,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,OAAc,eAAe,UAAU,eAA+B,GAAG,OAClJ;AAAA,wBAAC,IAAI,MAAJ,EAAS,KAAU,WAAW,EAAE,KAAK,GAAI,GAAG,UAC1C,UACH;AAAA,IACA,oBAAC,IAAI,UAAJ,EAAa,KAAK,UAAU,WAAW,EAAE,SAAS,GAAG;AAAA,KACxD,GACF;AAEJ;AAUO,SAAS,WAAW,EAAE,QAAQ,WAAW,eAAe,gBAAgB,GAAG,MAAM,GAAoB;AAC1G,QAAM,EAAE,MAAM,IAAU,iBAAW,YAAY;AAC/C,SACE,oBAAC,IAAI,MAAJ,EAAS,WAAW,eACnB;AAAA,IAAC,IAAI;AAAA,IAAJ;AAAA,MACC,iBAAc;AAAA,MACd,eAAa,SAAS,KAAK;AAAA,MAC3B;AAAA,MACA,gBAAc,SAAS,SAAS;AAAA,MAChC,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC;AAAA,MAC/B,gBAAgB,CAAC,MAAM;AACrB,yBAAiB,CAAC;AAClB,cAAM;AAAA,MACR;AAAA,MACC,GAAG;AAAA;AAAA,EACN,GACF;AAEJ;AA8BA,IAAM,cAAc,EAAE,IAAI,IAAI,IAAI,iBAAiB,IAAI,gBAAgB;AACvE,IAAM,gBAAgB,EAAE,IAAI,IAAI,IAAI,aAAa,IAAI,YAAY;AAO1D,SAAS,WAAW,EAAE,OAAO,QAAQ,UAAU,GAAG,aAAa,GAAG,aAAa,MAAM,UAAU,WAAW,GAAG,MAAM,GAAoB;AAC5I,QAAM,QAAc,eAAS,QAAQ,QAAQ;AAC7C,QAAM,WAAW,CAAC,SAChB,qBAAC,IAAI,MAAJ,EAAS,WAAW,GAAG,MAAM,SAAS,GAAI,GAAG,OAC5C;AAAA,yBAAC,IAAI,SAAJ,EAAY,iBAAc,IAAG,eAAa,SAAS,KAAK,QAAW,WAAW,GAAG,EAAE,KAAK,GAAG,eAAe,GACxG;AAAA;AAAA,MACD,oBAAC,SAAI,SAAQ,aAAY,WAAW,EAAE,QAAQ,GAAG,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,eAAW,MAClI,8BAAC,UAAK,GAAE,gBAAe,GACzB;AAAA,OACF;AAAA,IACA,oBAAC,IAAI,SAAJ,EAAY,WAAW,GAAG,EAAE,MAAM,GAAG,YAAY,KAAK,EAAE,UAAU,CAAC,GAAI,UAAS;AAAA,KACnF;AAEF,QAAM,SAAS,MAAM,SAAS,KAAK,MAAM,UAAU,cAAc,MAAM,MAAM,CAAC,MAAY,qBAAe,CAAC,KAAK,EAAE,SAAS,cAAc;AACxI,MAAI,QAAQ;AACV,WACE,iCACG;AAAA,qBAAe,QAAQ,SAAS,cAAc,UAAU,CAAC;AAAA,MACzD,MAAM,IAAI,CAAC,SAAS;AACnB,cAAM,EAAE,OAAO,MAAM,QAAQ,MAAM,SAAS,UAAU,OAAO,MAAM,OAAO,aAAa,cAAc,WAAW,WAAW,GAAG,KAAK,IAAK,KAAiD;AACzL,eACE,oBAAC,cAAkD,SAAkB,MAAM,UAAU,SAAY,MAAM,QAAQ,MAAM,WAAW,WAAW,eAAe,YAAY,UAAU,GAAI,GAAG,MACpL,qBAAiB,qBAA+C,KAAK,IAAU,mBAAa,OAAO,QAAW,KAAK,IAAI,SADxG,KAA4B,GAE9C;AAAA,MAEJ,CAAC;AAAA,OACH;AAAA,EAEJ;AACA,SAAO,SAAS,EAAE;AACpB;AAcO,SAAS,eAAe,EAAE,OAAO,aAAa,MAAM,QAAQ,MAAM,WAAW,SAAS,UAAU,GAAG,MAAM,GAAwB;AACtI,QAAM,OACJ,iCACG;AAAA,YAAQ,oBAAC,UAAK,WAAW,EAAE,SAAS,GAAI,gBAAK;AAAA,IAC9C,qBAAC,UAAK,WAAU,kBACd;AAAA,0BAAC,UAAK,WAAW,EAAE,UAAU,GAAI,iBAAM;AAAA,MACtC,eAAe,oBAAC,UAAK,WAAW,EAAE,SAAS,GAAI,uBAAY;AAAA,OAC9D;AAAA,KACF;AAEF,SACE,oBAAC,IAAI,MAAJ,EAAS,SAAkB,MAAM,UAAU,SAAY,MAAM,QAAgB,gBAAc,SAAS,SAAS,QAAW,eAAa,SAAS,KAAK,QAAW,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,GAAI,GAAG,OACtM,qBAAiB,qBAA+C,QAAQ,IAAU,mBAAa,UAAU,QAAW,IAAI,IAAI,MAC/H;AAEJ;AAGO,SAAS,cAAc,EAAE,WAAW,GAAG,MAAM,GAAgC;AAClF,SAAO,oBAAC,SAAI,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AAC9D;AAcO,SAAS,aAAa,EAAE,WAAW,YAAY,WAAW,UAAU,GAAG,MAAM,GAAsB;AACxG,QAAM,EAAE,OAAO,MAAM,SAAS,QAAQ,IAAI,UAAU;AACpD,QAAM,SAAe,aAA0B,IAAI;AACnD,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,CAAC,MAAqB;AAClC,UAAI,EAAE,QAAQ,SAAU;AACxB,cAAQ,KAAK;AACb,aAAO,SAAS,MAAM;AAAA,IACxB;AAEA,UAAM,UAAU,CAAC,MAAoB;AACnC,YAAM,SAAS,EAAE;AACjB,UAAI,CAAC,UAAU,OAAO,SAAS,SAAS,MAAM,KAAK,SAAS,eAAe,OAAO,GAAG,SAAS,MAAM,EAAG;AACvG,cAAQ,KAAK;AAAA,IACf;AACA,aAAS,iBAAiB,WAAW,KAAK;AAC1C,aAAS,iBAAiB,eAAe,OAAO;AAChD,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,KAAK;AAC7C,eAAS,oBAAoB,eAAe,OAAO;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,MAAM,SAAS,OAAO,CAAC;AAC3B,SACE,iCACE;AAAA,wBAAC,YAAO,KAAK,QAAQ,MAAK,UAAS,iBAAe,MAAM,iBAAe,SAAS,cAAY,OAAO,aAAa,WAAW,SAAS,MAAM,QAAQ,CAAC,IAAI,GAAG,WAAW,EAAE,OAAO,GAC5K,8BAAC,SAAI,SAAQ,aAAY,WAAU,eAAc,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,eAAW,MACjI,iBAAO,oBAAC,UAAK,GAAE,wBAAuB,IAAK,oBAAC,UAAK,GAAE,2BAA0B,GAChF,GACF;AAAA,IACC,QACC;AAAA,MAAC;AAAA;AAAA,QACC,IAAI;AAAA,QACJ,cAAY;AAAA,QACZ,WAAW,EAAE,OAAO,EAAE,UAAU,CAAC;AAAA,QACjC,SAAS,CAAC,MAAM;AACd,cAAK,EAAE,OAAmB,QAAQ,GAAG,EAAG,SAAQ,KAAK;AAAA,QACvD;AAAA,QACC,GAAG;AAAA,QAEJ,8BAAC,cAAc,UAAd,EAAuB,OAAK,MAAE,UAAS;AAAA;AAAA,IAC1C;AAAA,KAEJ;AAEJ;AAQO,SAAS,kBAAkB,EAAE,OAAO,WAAW,UAAU,GAAG,MAAM,GAA2B;AAClG,QAAM,KAAW,YAAM;AACvB,SACE,qBAAC,SAAI,MAAK,SAAQ,mBAAiB,IAAI,WAAW,EAAE,YAAY,EAAE,UAAU,CAAC,GAAI,GAAG,OAClF;AAAA,wBAAC,OAAE,IAAQ,WAAW,EAAE,iBAAiB,GACtC,iBACH;AAAA,IACC;AAAA,KACH;AAEJ;AAUO,SAAS,iBAAiB,EAAE,QAAQ,SAAS,WAAW,GAAG,MAAM,GAA0B;AAChG,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SAAO,oBAAC,QAAK,gBAAc,SAAS,SAAS,QAAW,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC,GAAI,GAAG,OAAO;AAC7G;AAGA,IAAM,UAAU;AAAA,EACd,UAAU;AAAA,EACV,cAAc;AAAA,EACd,aAAa;AAAA,EACb,SAAS;AACX;AAGA,SAAS,WAAW,EAAE,MAAM,SAAS,OAAO,GAA2D;AACrG,SACE,qBAAC,UAAK,WAAW,EAAE,WAAW,GAC3B;AAAA,SAAK;AAAA,IACL,KAAK,WAAW,cAAc,oBAAC,UAAK,WAAW,GAAG,EAAE,UAAU,GAAG,QAAQ,KAAK,MAAM,CAAC,GAAI,iBAAO,OAAO,KAAK,MAAM,GAAE;AAAA,IACpH,WAAW,oBAAC,UAAK,WAAW,GAAG,EAAE,UAAU,GAAG,QAAQ,OAAO,GAAI,iBAAO,SAAQ;AAAA,KACnF;AAEJ;AAsBO,SAAS,aAAa,EAAE,SAAS,SAAS,aAAa,IAAI,aAAa,UAAU,GAAsB;AAC7G,QAAM,WAAiB,iBAAW,aAAa;AAC/C,QAAM,KAAW,YAAM;AACvB,QAAM,SAAS,aAAa;AAC5B,MAAI,UAAU;AACZ,WACE,qBAAC,SAAI,MAAK,SAAQ,mBAAiB,GAAG,EAAE,WAAW,WAAW,EAAE,aAAa,EAAE,UAAU,CAAC,GACxF;AAAA,0BAAC,OAAE,IAAI,GAAG,EAAE,WAAW,WAAW,EAAE,iBAAiB,GAClD,iBAAO,QACV;AAAA,MACC,OAAO,IAAI,CAAC,EAAE,OAAO,MAAM,MAC1B,qBAAC,SAEE;AAAA,kBAAU,aACT,oBAAC,OAAE,IAAI,GAAG,EAAE,IAAI,KAAK,IAAI,WAAW,EAAE,iBAAiB,GACpD,iBAAO,OAAO,KAAK,GACtB;AAAA,QAEF,oBAAC,QAAG,mBAAiB,UAAU,YAAY,GAAG,EAAE,IAAI,KAAK,KAAK,GAAG,EAAE,WAAW,WAAU,gBACrF,gBAAM,IAAI,CAAC,SACV,oBAAC,QACC,+BAAC,OAAE,MAAM,KAAK,KAAK,gBAAc,KAAK,OAAO,UAAU,KAAK,QAAW,gBAAc,KAAK,OAAO,UAAU,SAAS,QAAW,WAAW,EAAE,iBAAiB,GAC3J;AAAA,8BAAC,UAAK,WAAW,EAAE,WAAW,GAC5B,8BAAC,cAAW,MAAM,KAAK,MAAM,MAAM,IAAI,GACzC;AAAA,UACA,oBAAC,cAAW,MAAY,SAAS,KAAK,OAAO,SAAS,QAAgB;AAAA,WACxE,KANO,KAAK,EAOd,CACD,GACH;AAAA,WAlBQ,KAmBV,CACD;AAAA,OACH;AAAA,EAEJ;AAEA,QAAM,UAAU,CAAC,MAA0B,EAAE,eAAe;AAC5D,QAAM,UAAU,CAAC,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,aAAa,EAAE,UAAU,UAAU,GAAG,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,iBAAiB,EAAE,UAAU,QAAQ,CAAC;AAC/J,SACE,qBAAC,IAAI,MAAJ,EAAS,cAAY,OAAO,QAAQ,cAAc,cAAc,WAAW,QAAW,WAAW,EAAE,OAAO,EAAE,UAAU,CAAC,GACtH;AAAA,wBAAC,IAAI,MAAJ,EAAS,WAAU,QAClB,+BAAC,IAAI,MAAJ,EAAS,OAAM,UACd;AAAA,0BAAC,IAAI,SAAJ,EAAY,cAAY,OAAO,QAAQ,eAAe,SAAS,gBAAgB,SAAS,WAAW,EAAE,cAAc,GAClH,8BAAC,SAAI,SAAQ,aAAY,WAAW,EAAE,QAAQ,GAAG,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,eAAW,MAClI,8BAAC,UAAK,GAAE,gBAAe,GACzB,GACF;AAAA,MACA,oBAAC,IAAI,SAAJ,EAAY,gBAAgB,SAAS,WAAW,EAAE,YAAY,GAC5D,kBAAQ,IAAI,CAAC,QAAQ,MACpB,oBAAC,SAAY,WAAU,4BACpB,iBAAO,IAAI,CAAC,EAAE,OAAO,MAAM,MAC1B,qBAAC,SACC;AAAA,4BAAC,OAAE,IAAI,GAAG,EAAE,IAAI,KAAK,IAAI,WAAW,EAAE,iBAAiB,GACpD,iBAAO,OAAO,KAAK,GACtB;AAAA,QACA,oBAAC,QAAG,mBAAiB,GAAG,EAAE,IAAI,KAAK,IAAI,WAAU,gBAC9C,gBAAM,IAAI,CAAC,SACV,oBAAC,QACC,+BAAC,IAAI,MAAJ,EAAS,MAAM,KAAK,KAAK,gBAAc,KAAK,OAAO,UAAU,KAAK,QAAW,gBAAc,KAAK,OAAO,UAAU,SAAS,QAAW,WAAW,EAAE,WAAW,GAC5J;AAAA,8BAAC,UAAK,WAAW,EAAE,WAAW,GAC5B,8BAAC,cAAW,MAAM,KAAK,MAAM,MAAM,IAAI,GACzC;AAAA,UACA,qBAAC,UAAK,WAAU,WACd;AAAA,gCAAC,cAAW,MAAY,SAAS,KAAK,OAAO,SAAS,QAAgB;AAAA,YACtE,oBAAC,UAAK,WAAW,EAAE,WAAW,GAAI,iBAAO,aAAa,KAAK,EAAE,GAAE;AAAA,aACjE;AAAA,WACF,KATO,KAAK,EAUd,CACD,GACH;AAAA,WAlBQ,KAmBV,CACD,KAtBO,CAuBV,CACD,GACH;AAAA,OACF,GACF;AAAA,IACA,oBAAC,IAAI,UAAJ,EAAa,gBAAgB,SAAS,WAAW,EAAE,eAAe,GAAG;AAAA,KACxE;AAEJ;AAUO,SAAS,YAAY,EAAE,KAAK,SAAS,WAAW,UAAU,GAAG,MAAM,GAAqB;AAC7F,QAAM,QAAQ,CAAC,KAAK,WAAW,IAAI,QAAQ,QAAQ,MAAM,EAAE,CAAC,EAAE,EAAE,OAAO,OAAO;AAC9E,SACE,qBAAC,UAAK,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,GAAI,GAAG,OAC1C;AAAA,UAAM,KAAK,QAAK;AAAA,IAChB;AAAA,KACH;AAEJ;AAQO,SAAS,eAAe,OAA4B;AACzD,QAAM,WAAiB,iBAAW,aAAa;AAC/C,SAAO,oBAAC,kBAAe,SAAS,WAAW,WAAW,QAAS,GAAG,OAAO;AAC3E;AAQO,SAAS,wBAAwB,EAAE,OAAO,WAAW,UAAU,GAAG,MAAM,GAAiC;AAC9G,QAAM,KAAW,YAAM;AACvB,SACE,qBAAC,SAAI,MAAK,SAAQ,mBAAiB,IAAI,WAAW,EAAE,YAAY,EAAE,UAAU,CAAC,GAAI,GAAG,OAClF;AAAA,wBAAC,OAAE,IAAQ,WAAW,EAAE,iBAAiB,GACtC,iBACH;AAAA,IACA,oBAAC,SAAI,WAAU,+CAA+C,UAAS;AAAA,KACzE;AAEJ;AAUO,SAAS,WAAW,EAAE,OAAO,WAAW,GAAG,MAAM,GAAoB;AAC1E,SACE,oBAAC,OAAE,cAAY,OAAO,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAC1D,8BAAC,eAAY,MAAM,IAAI,GACzB;AAEJ;AAOO,IAAM,SAAS;AAAA,EACpB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,SAAS;AAAA,EACT,MAAM;AAAA,EACN,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,YAAY;AACd;","names":["window"]}
|
|
1
|
+
{"version":3,"sources":["../src/nav-bar/nav-bar.tsx","../src/nav-bar/placement.ts"],"sourcesContent":["// Client (scroll, a sliding indicator, menus). Radix NavigationMenu does the menus' semantics and keyboard (Enter, Space\n// and ↓ open; ↑ ↓ Home End walk; Escape closes and returns the focus; Tab out closes); this file draws the Krizaka bar:\n// a floating pill that tightens once the page scrolls, one light that glides to the item under the pointer or the\n// focus and rests on the current page, and a mobile panel that is a plain disclosure (no focus trap, Escape closes).\nimport { NavigationMenu as Nav, Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { FamilyMark, GitHubGlyph } from \"../family-mark\";\nimport { LanguageSwitch, type LanguageSwitchProps } from \"../language-switch/language-switch\";\nimport { type FamilyLabels, familyLabels, type Site, type SiteId, sitesByGroup } from \"../sites/sites\";\nimport { useSlidingIndicator } from \"../sliding-indicator\";\nimport { placePanel } from \"./placement\";\n\nexport const navBar = tv({\n slots: {\n root:\n \"group/nav relative z-40 mx-auto flex h-14 w-full items-center gap-2 border-border-subtle bg-surface-1 \" +\n \"transition-[height,background-color,border-color,box-shadow] duration-300 motion-reduce:transition-none \" +\n \"data-compact:h-12 data-compact:border-border-default data-compact:bg-surface-1 data-compact:shadow-lg\",\n brand:\n \"mr-2 inline-flex shrink-0 items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg no-underline \" +\n \"rounded-md focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n items: \"relative hidden md:block\",\n list:\n \"group/list relative isolate flex items-center gap-0.5 \" +\n // The ink rule (Cahier, ADR-004): a pen line under the item that is pointed at or focused, resting on the current page.\n \"before:absolute before:left-0 before:top-0 before:-z-10 before:h-0.5 before:w-(--kz-ind-w) before:translate-x-(--kz-ind-x) before:translate-y-[calc(var(--kz-ind-y)+var(--kz-ind-h)-6px)] \" +\n \"before:scale-x-[0.72] before:bg-fg before:opacity-0 before:transition-[translate,width,opacity] before:duration-300 motion-reduce:before:transition-none \" +\n \"data-[indicator=on]:before:opacity-100\",\n item:\n \"inline-flex h-9 select-none items-center gap-1 rounded-sm px-3.5 text-sm font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:text-fg data-active:text-fg data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n // Before the light is ready (server render), the current page carries its own tint.\n \"group-not-data-[indicator=on]/list:data-active:underline group-not-data-[indicator=on]/list:data-active:decoration-2 group-not-data-[indicator=on]/list:data-active:underline-offset-8\",\n chevron: \"h-3.5 w-3.5 transition-transform duration-300 group-data-[state=open]/trigger:rotate-180 motion-reduce:transition-none\",\n viewport:\n // `left` is set by NavBarItems (--kz-menu-left): the panel's edge under its trigger, kept inside the page.\n \"kz-pop absolute left-[var(--kz-menu-left,0px)] top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden \" +\n \"rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[left,width,height] duration-300 motion-reduce:transition-none\",\n // Icon · title · a description of two lines at most. 28 rem (40 rem in two columns), never wider than the page\n // between its gutters, and never taller than the screen.\n panel: \"grid w-[min(28rem,calc(100vw-2rem))] max-h-[calc(100dvh-6rem)] gap-0.5 overflow-y-auto p-1.5\",\n panelWide: \"w-[min(40rem,calc(100vw-2rem))] md:grid-cols-2\",\n menuLink:\n \"group/link flex items-start gap-3 rounded-lg px-2.5 py-2 text-left no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring data-active:bg-accent-soft\",\n menuIcon:\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-border-default bg-surface-2 text-fg-accent \" +\n \"transition-[transform,border-color] duration-300 group-hover/link:-translate-y-0.5 group-hover/link:border-accent [&>svg]:h-4 [&>svg]:w-4 motion-reduce:transform-none\",\n menuTitle: \"block line-clamp-2 wrap-break-word text-sm font-semibold leading-5 text-fg\",\n // Two lines at most, wrapped at word boundaries — a longer one ends in an ellipsis, never cut mid-sentence.\n menuText: \"mt-0.5 block line-clamp-2 wrap-break-word text-xs leading-4 text-fg-secondary\",\n actions: \"ml-auto flex items-center gap-2\",\n toggle:\n \"inline-flex h-9 w-9 items-center justify-center rounded-sm border border-border-subtle bg-surface-2 text-fg md:hidden \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n mobile: \"kz-pop absolute inset-x-0 top-full mt-2 grid gap-1 rounded-2xl border border-border-default bg-surface-1 p-2 shadow-lg md:hidden\",\n mobileGroup: \"grid gap-0.5 [&+&]:mt-1 [&+&]:border-t [&+&]:border-border-subtle [&+&]:pt-2\",\n mobileGroupTitle: \"px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary\",\n mobileLink:\n \"flex items-center justify-between rounded-xl px-3 py-3 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg-accent\",\n // The family switcher: a chevron attached to the brand, its panel aligned on the bar's left edge.\n family: \"hidden md:block\",\n familyTrigger:\n \"group/trigger -ml-2 mr-1 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-sm text-fg-secondary transition-colors \" +\n \"hover:bg-surface-3 hover:text-fg data-[state=open]:bg-surface-3 data-[state=open]:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n familyViewport:\n \"kz-pop absolute left-0 top-full mt-2 h-(--radix-navigation-menu-viewport-height) w-(--radix-navigation-menu-viewport-width) origin-top-left overflow-hidden \" +\n \"rounded-2xl border border-border-default bg-surface-1 shadow-lg transition-[width,height] duration-300 motion-reduce:transition-none\",\n familyPanel: \"grid w-[min(92vw,42rem)] gap-x-2 gap-y-3 p-3 sm:grid-cols-2\",\n familyGroupTitle: \"px-3 pb-1 pt-1 text-[11px] font-semibold text-fg-secondary\",\n familyLink:\n \"group/link flex items-start gap-3 rounded-xl px-3 py-2.5 text-left no-underline outline-hidden transition-colors \" +\n \"hover:bg-surface-2 focus-visible:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft\",\n familyMark: \"mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-fg\",\n familyName: \"flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm font-semibold text-fg\",\n familyText: \"mt-0.5 block text-xs leading-relaxed text-fg-secondary\",\n familyTag: \"rounded-sm px-1.5 py-px text-[10px] font-semibold\",\n mobileFamily: \"mt-1 grid gap-2 border-t border-border-subtle px-1 pb-1 pt-3\",\n mobileFamilyLink:\n \"flex min-h-11 items-center gap-3 rounded-xl px-2 py-2 text-[15px] font-medium text-fg no-underline hover:bg-surface-2 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-current:bg-accent-soft\",\n badge:\n \"hidden h-6 shrink-0 items-center gap-1 rounded-sm border border-border-subtle bg-surface-2 px-2 font-mono text-[11px] font-medium text-fg-secondary sm:inline-flex\",\n repo:\n \"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-sm text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n },\n variants: {\n floating: {\n true: { root: \"max-w-5xl rounded-sm border pl-5 pr-2 data-compact:max-w-4xl\" },\n false: { root: \"border-b px-4 md:px-6\" },\n },\n },\n defaultVariants: { floating: true },\n});\nconst s = navBar();\n\ninterface NavBarContext {\n label: string;\n open: boolean;\n setOpen: (open: boolean) => void;\n panelId: string;\n}\nconst Context = React.createContext<NavBarContext | null>(null);\n/** The open menu of `NavBar.Items` (`\"\"`: none), so a plain link can close it when the pointer moves on to it. */\nconst ItemsContext = React.createContext<{ close: () => void }>({ close: () => {} });\n/** True inside `NavBar.Mobile`: the family renders as the panel's last group instead of a switcher. */\nconst MobileContext = React.createContext(false);\nconst useNavBar = () => {\n const ctx = React.useContext(Context);\n if (!ctx) throw new Error(\"NavBar parts must be inside <NavBar.Root>.\");\n return ctx;\n};\n\nexport type NavBarRootProps = React.ComponentProps<\"header\"> & {\n /** The accessible name of the navigation (“Main”) — passed translated. */\n label: string;\n /**\n * Pixels of scroll after which the bar tightens (denser, lower, lifted). `false`: never.\n * @default 24\n */\n compactAfter?: number | false;\n /**\n * A floating pill (the Krizaka bar) or a full-width bar with a hairline under it.\n * @default true\n */\n floating?: boolean;\n};\n\n/** The bar. Place it in a `sticky top-3` (floating) or `sticky top-0` wrapper — or let it scroll. */\nexport function NavBarRoot({ label, compactAfter = 24, floating = true, className, children, ...props }: NavBarRootProps) {\n const [compact, setCompact] = React.useState(false);\n const [open, setOpen] = React.useState(false);\n const panelId = React.useId();\n React.useEffect(() => {\n if (compactAfter === false) return;\n const onScroll = () => setCompact(window.scrollY > compactAfter);\n onScroll();\n window.addEventListener(\"scroll\", onScroll, { passive: true });\n return () => window.removeEventListener(\"scroll\", onScroll);\n }, [compactAfter]);\n const ctx = React.useMemo(() => ({ label, open, setOpen, panelId }), [label, open, panelId]);\n return (\n <Context.Provider value={ctx}>\n <header data-compact={compact ? \"\" : undefined} data-floating={floating} className={navBar({ floating }).root({ className })} {...props}>\n {children}\n </header>\n </Context.Provider>\n );\n}\n\nexport type NavBarBrandProps = React.ComponentProps<\"a\"> & {\n /** Renders your link (a router `<Link>`) with the brand's look. */\n asChild?: boolean;\n};\n\n/** The brand: a mark and a name, linking home. */\nexport function NavBarBrand({ asChild, className, ...props }: NavBarBrandProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp className={s.brand({ className })} {...props} />;\n}\n\nexport type NavBarItemsProps = Omit<React.ComponentProps<typeof Nav.Root>, \"orientation\">;\n\n/**\n * The desktop navigation: links and menus, with the light that glides between them. Hidden below `md` (see\n * `NavBar.Mobile`). A menu opens on click, Enter, Space or ↓ — or when the pointer rests on its trigger (hover intent,\n * `delayDuration`, 200 ms): passing over the bar opens nothing. While a menu is open the light stays on its trigger;\n * moving on to a plain link closes the menu, so the bar never shows two current items. A click outside or Escape closes.\n */\nexport function NavBarItems({ className, children, value: valueProp, defaultValue, onValueChange, delayDuration = 200, ...props }: NavBarItemsProps) {\n const { label } = useNavBar();\n const [inner, setInner] = React.useState(defaultValue ?? \"\");\n const value = valueProp ?? inner;\n const setValue = React.useCallback(\n (next: string) => {\n setInner(next);\n onValueChange?.(next);\n },\n [onValueChange],\n );\n const items = React.useMemo(() => ({ close: () => setValue(\"\") }), [setValue]);\n const { ref, handlers } = useSlidingIndicator<HTMLUListElement>({\n item: \"[data-nav-item]\",\n active: \"[data-nav-item][data-active]\",\n prefer: \"[data-nav-item][data-state=open]\",\n follow: true,\n });\n const root = React.useRef<HTMLElement>(null);\n const viewport = React.useRef<HTMLDivElement>(null);\n // The open panel sits under its trigger and stays inside the page (collision): measured when a menu opens, when\n // the panel changes size (another menu) and when the window does.\n React.useLayoutEffect(() => {\n const panel = viewport.current;\n const nav = root.current;\n if (!panel || !nav || !value) return;\n const place = () => {\n const trigger = nav.querySelector<HTMLElement>(\"[data-nav-item][data-state=open]\");\n const width = Number.parseFloat(panel.style.getPropertyValue(\"--radix-navigation-menu-viewport-width\"));\n if (!trigger || !Number.isFinite(width)) return;\n const left = `${placePanel({ trigger: trigger.getBoundingClientRect().left, root: nav.getBoundingClientRect().left, panel: width, window: document.documentElement.clientWidth })}px`;\n if (panel.style.getPropertyValue(\"--kz-menu-left\") !== left) panel.style.setProperty(\"--kz-menu-left\", left);\n };\n place();\n const watch = new MutationObserver(place);\n watch.observe(panel, { attributes: true, attributeFilter: [\"style\"] });\n window.addEventListener(\"resize\", place);\n return () => {\n watch.disconnect();\n window.removeEventListener(\"resize\", place);\n };\n }, [value]);\n return (\n <ItemsContext.Provider value={items}>\n <Nav.Root ref={root} aria-label={label} className={s.items({ className })} value={value} onValueChange={setValue} delayDuration={delayDuration} {...props}>\n <Nav.List ref={ref} className={s.list()} {...handlers}>\n {children}\n </Nav.List>\n <Nav.Viewport ref={viewport} className={s.viewport()} />\n </Nav.Root>\n </ItemsContext.Provider>\n );\n}\n\nexport type NavBarLinkProps = Omit<React.ComponentProps<typeof Nav.Link>, \"active\"> & {\n /** The current page: `aria-current=\"page\"`, and the light rests on it. */\n active?: boolean;\n /** Classes on the list item around the link (to show it from a breakpoint only). */\n itemClassName?: string;\n};\n\n/** A link of the bar. `asChild` renders your router's `<Link>`. */\nexport function NavBarLink({ active, className, itemClassName, onPointerEnter, ...props }: NavBarLinkProps) {\n const { close } = React.useContext(ItemsContext);\n return (\n <Nav.Item className={itemClassName}>\n <Nav.Link\n data-nav-item=\"\"\n data-active={active ? \"\" : undefined}\n active={active}\n aria-current={active ? \"page\" : undefined}\n className={s.item({ className })}\n onPointerEnter={(e) => {\n onPointerEnter?.(e);\n close();\n }}\n {...props}\n />\n </Nav.Item>\n );\n}\n\nexport type NavBarMenuProps = Omit<React.ComponentProps<typeof Nav.Item>, \"children\"> & {\n /** The trigger's words (“Products”) — passed translated. */\n label: string;\n /** The current page is inside this menu: the light rests on its trigger. */\n active?: boolean;\n /** The menu's links (`NavBar.MenuLink`), laid out in a panel; `columns` sets the grid. */\n children: React.ReactNode;\n /**\n * Columns of the panel.\n * @default 1\n */\n columns?: 1 | 2;\n /**\n * A section with this many links or fewer needs no hidden list: they sit in the bar as plain links (the active one\n * marked, no dropdown, `label` unused on the desktop). Above it, a dropdown. `0` always makes a dropdown.\n * @default 3\n */\n inlineUpTo?: number;\n /**\n * From which breakpoint the inline links stand in the bar. Below it (between the phone panel at `md` and this\n * breakpoint) the section is the dropdown, so long labels never overflow a tablet-width bar. `md` inlines as soon as\n * the bar is shown.\n * @default \"lg\"\n */\n inlineFrom?: \"md\" | \"lg\" | \"xl\";\n};\n\n// Static class names (Tailwind reads them at build time).\nconst INLINE_HIDE = { md: \"\", lg: \"max-lg:hidden\", xl: \"max-xl:hidden\" } as const;\nconst DROPDOWN_HIDE = { md: \"\", lg: \"lg:hidden\", xl: \"xl:hidden\" } as const;\n\n/**\n * A menu of the bar: its trigger, and its links in a panel that opens under the bar. A menu of `inlineUpTo` links or\n * fewer (3 by default) is not a menu at all: its links stand in the bar, each with its active state — a hidden list of\n * three is one click more for nothing. The phone's panel groups them as usual (`NavBar.MobileGroup`).\n */\nexport function NavBarMenu({ label, active, columns = 1, inlineUpTo = 3, inlineFrom = \"lg\", children, className, ...props }: NavBarMenuProps) {\n const links = React.Children.toArray(children);\n const dropdown = (hide: string) => (\n <Nav.Item className={cn(hide, className)} {...props}>\n <Nav.Trigger data-nav-item=\"\" data-active={active ? \"\" : undefined} className={cn(s.item(), \"group/trigger\")}>\n {label}\n <svg viewBox=\"0 0 24 24\" className={s.chevron()} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </Nav.Trigger>\n <Nav.Content className={cn(s.panel(), columns === 2 && s.panelWide())}>{children}</Nav.Content>\n </Nav.Item>\n );\n const inline = links.length > 0 && links.length <= inlineUpTo && links.every((c) => React.isValidElement(c) && c.type === NavBarMenuLink);\n if (inline) {\n return (\n <>\n {inlineFrom !== \"md\" && dropdown(DROPDOWN_HIDE[inlineFrom])}\n {links.map((link) => {\n const { title, href, active: here, asChild, children: child, icon: _icon, description: _description, className: linkClass, ...rest } = (link as React.ReactElement<NavBarMenuLinkProps>).props;\n return (\n <NavBarLink key={(link as React.ReactElement).key} asChild={asChild} href={asChild ? undefined : href} active={here} className={linkClass} itemClassName={INLINE_HIDE[inlineFrom]} {...rest}>\n {asChild && React.isValidElement<{ children?: React.ReactNode }>(child) ? React.cloneElement(child, undefined, title) : title}\n </NavBarLink>\n );\n })}\n </>\n );\n }\n return dropdown(\"\");\n}\n\nexport type NavBarMenuLinkProps = Omit<React.ComponentProps<typeof Nav.Link>, \"title\" | \"active\"> & {\n /** The link's name — passed translated. */\n title: string;\n /** One line under it — passed translated. */\n description?: string;\n /** An icon (a signature icon of `@krizaka/icons`: its node lights up on hover). */\n icon?: React.ReactNode;\n /** The current page. */\n active?: boolean;\n};\n\n/** A link inside a menu: an icon, a name and a line of text. */\nexport function NavBarMenuLink({ title, description, icon, active, href, className, asChild, children, ...props }: NavBarMenuLinkProps) {\n const body = (\n <>\n {icon && <span className={s.menuIcon()}>{icon}</span>}\n <span className=\"min-w-0 flex-1\">\n <span className={s.menuTitle()}>{title}</span>\n {description && <span className={s.menuText()}>{description}</span>}\n </span>\n </>\n );\n return (\n <Nav.Link asChild={asChild} href={asChild ? undefined : href} active={active} aria-current={active ? \"page\" : undefined} data-active={active ? \"\" : undefined} className={s.menuLink({ className })} {...props}>\n {asChild && React.isValidElement<{ children?: React.ReactNode }>(children) ? React.cloneElement(children, undefined, body) : body}\n </Nav.Link>\n );\n}\n\n/** The right side: search, theme, language, the call to action. */\nexport function NavBarActions({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.actions({ className })} {...props} />;\n}\n\nexport type NavBarMobileProps = React.ComponentProps<\"nav\"> & {\n /** The toggle's name when closed (“Open the menu”) — passed translated. */\n openLabel: string;\n /** The toggle's name when open (“Close the menu”) — passed translated. */\n closeLabel: string;\n};\n\n/**\n * Below `md`: a toggle, and a panel under the bar with its links (`NavBar.MobileLink`), grouped like the bar's menus\n * (`NavBar.MobileGroup`). A disclosure: Escape, a click on a link or a press outside close it; Escape returns the focus\n * to the toggle.\n */\nexport function NavBarMobile({ openLabel, closeLabel, className, children, ...props }: NavBarMobileProps) {\n const { label, open, setOpen, panelId } = useNavBar();\n const toggle = React.useRef<HTMLButtonElement>(null);\n React.useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n setOpen(false);\n toggle.current?.focus();\n };\n // A press outside the panel and its toggle closes it (the page under it stays usable).\n const onPress = (e: PointerEvent) => {\n const target = e.target as Node | null;\n if (!target || toggle.current?.contains(target) || document.getElementById(panelId)?.contains(target)) return;\n setOpen(false);\n };\n document.addEventListener(\"keydown\", onKey);\n document.addEventListener(\"pointerdown\", onPress);\n return () => {\n document.removeEventListener(\"keydown\", onKey);\n document.removeEventListener(\"pointerdown\", onPress);\n };\n }, [open, setOpen, panelId]);\n return (\n <>\n <button ref={toggle} type=\"button\" aria-expanded={open} aria-controls={panelId} aria-label={open ? closeLabel : openLabel} onClick={() => setOpen(!open)} className={s.toggle()}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4.5 w-4.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n {open ? <path d=\"M18 6 6 18M6 6l12 12\" /> : <path d=\"M4 7h16M4 12h16M4 17h10\" />}\n </svg>\n </button>\n {open && (\n <nav\n id={panelId}\n aria-label={label}\n className={s.mobile({ className })}\n onClick={(e) => {\n if ((e.target as Element).closest(\"a\")) setOpen(false);\n }}\n {...props}\n >\n <MobileContext.Provider value>{children}</MobileContext.Provider>\n </nav>\n )}\n </>\n );\n}\n\nexport type NavBarMobileGroupProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The group's heading — the same words as the bar's menu (“Product”) — passed translated. */\n label: string;\n};\n\n/** A group of the mobile panel: the links of one of the bar's menus under its name, in the same order. */\nexport function NavBarMobileGroup({ label, className, children, ...props }: NavBarMobileGroupProps) {\n const id = React.useId();\n return (\n <div role=\"group\" aria-labelledby={id} className={s.mobileGroup({ className })} {...props}>\n <p id={id} className={s.mobileGroupTitle()}>\n {label}\n </p>\n {children}\n </div>\n );\n}\n\nexport type NavBarMobileLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the mobile panel. */\nexport function NavBarMobileLink({ active, asChild, className, ...props }: NavBarMobileLinkProps) {\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.mobileLink({ className })} {...props} />;\n}\n\n\nconst tagTone = {\n upcoming: \"bg-accent-soft text-fg ring-1 ring-inset ring-accent/40\",\n construction: \"bg-warning/15 text-fg ring-1 ring-inset ring-warning/40\",\n development: \"bg-surface-3 text-fg ring-1 ring-inset ring-border-strong\",\n current: \"bg-surface-3 text-fg-secondary\",\n};\n\n/** A site's name and its tags: status when not released, “You are here” on the current one. */\nfunction FamilyName({ site, current, labels }: { site: Site; current: boolean; labels: FamilyLabels }) {\n return (\n <span className={s.familyName()}>\n {site.name}\n {site.status !== \"released\" && <span className={cn(s.familyTag(), tagTone[site.status])}>{labels.status[site.status]}</span>}\n {current && <span className={cn(s.familyTag(), tagTone.current)}>{labels.current}</span>}\n </span>\n );\n}\n\nexport type NavBarFamilyProps = {\n /** The site this bar belongs to (`@krizaka/ui/sites`): marked in the family, `aria-current=\"true\"`. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** Opens the panel at first render (a story, a screenshot). */\n defaultOpen?: boolean;\n /** Classes of the switcher (or, inside `NavBar.Mobile`, of the family's group). */\n className?: string;\n};\n\n/**\n * The family switcher, attached to the brand (place it right after `NavBar.Brand`): a chevron that opens every site of\n * Krizaka grouped — Krizaka · Products · Open source · GitHub — the current one marked. It opens on click, Enter, Space\n * or ↓ (never on hover); ↑ ↓ walk the sites, Escape closes and returns the focus. Hidden below `md`: place a second\n * `NavBar.Family` as the last child of `NavBar.Mobile`, where it renders as the panel's last group.\n */\nexport function NavBarFamily({ current, labels = familyLabels.en, defaultOpen, className }: NavBarFamilyProps) {\n const inMobile = React.useContext(MobileContext);\n const id = React.useId();\n const groups = sitesByGroup();\n if (inMobile) {\n return (\n <div role=\"group\" aria-labelledby={`${id}-family`} className={s.mobileFamily({ className })}>\n <p id={`${id}-family`} className={s.familyGroupTitle()}>\n {labels.family}\n </p>\n {groups.map(({ group, sites }) => (\n <div key={group}>\n {/* The company's own group is named like the family itself: its heading would repeat the panel's. */}\n {group !== \"krizaka\" && (\n <p id={`${id}-${group}`} className={s.familyGroupTitle()}>\n {labels.groups[group]}\n </p>\n )}\n <ul aria-labelledby={group !== \"krizaka\" ? `${id}-${group}` : `${id}-family`} className=\"grid gap-0.5\">\n {sites.map((site) => (\n <li key={site.id}>\n <a href={site.url} data-current={site.id === current ? \"\" : undefined} aria-current={site.id === current ? \"true\" : undefined} className={s.mobileFamilyLink()}>\n <span className={s.familyMark()}>\n <FamilyMark mark={site.mark} size={24} />\n </span>\n <FamilyName site={site} current={site.id === current} labels={labels} />\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n );\n }\n // Click only: a pointer passing over the brand never opens the family (Radix opens its menus on hover by default).\n const noHover = (e: React.PointerEvent) => e.preventDefault();\n const columns = [groups.filter((g) => g.group === \"krizaka\" || g.group === \"products\"), groups.filter((g) => g.group === \"open-source\" || g.group === \"github\")];\n return (\n <Nav.Root aria-label={labels.family} defaultValue={defaultOpen ? \"family\" : undefined} className={s.family({ className })}>\n <Nav.List className=\"flex\">\n <Nav.Item value=\"family\">\n <Nav.Trigger aria-label={labels.family} onPointerMove={noHover} onPointerLeave={noHover} className={s.familyTrigger()}>\n <svg viewBox=\"0 0 24 24\" className={s.chevron()} fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </Nav.Trigger>\n <Nav.Content onPointerLeave={noHover} className={s.familyPanel()}>\n {columns.map((column, i) => (\n <div key={i} className=\"grid content-start gap-3\">\n {column.map(({ group, sites }) => (\n <div key={group}>\n <p id={`${id}-${group}`} className={s.familyGroupTitle()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className=\"grid gap-0.5\">\n {sites.map((site) => (\n <li key={site.id}>\n <Nav.Link href={site.url} data-current={site.id === current ? \"\" : undefined} aria-current={site.id === current ? \"true\" : undefined} className={s.familyLink()}>\n <span className={s.familyMark()}>\n <FamilyMark mark={site.mark} size={28} />\n </span>\n <span className=\"min-w-0\">\n <FamilyName site={site} current={site.id === current} labels={labels} />\n <span className={s.familyText()}>{labels.descriptions[site.id]}</span>\n </span>\n </Nav.Link>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n ))}\n </Nav.Content>\n </Nav.Item>\n </Nav.List>\n <Nav.Viewport onPointerLeave={noHover} className={s.familyViewport()} />\n </Nav.Root>\n );\n}\n\nexport type NavBarBadgeProps = React.ComponentProps<\"span\"> & {\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n};\n\n/** A small mono badge beside the brand: the environment and the version (`DEV · v1.2.3`). Hidden below `sm`. */\nexport function NavBarBadge({ env, version, className, children, ...props }: NavBarBadgeProps) {\n const parts = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean);\n return (\n <span className={s.badge({ className })} {...props}>\n {parts.join(\" · \")}\n {children}\n </span>\n );\n}\n\nexport type NavBarLanguageProps = Omit<LanguageSwitchProps, \"variant\">;\n\n/**\n * The language switch, the same on every site: in the bar a globe and the current code (FR) opening a short menu of\n * the languages by their own names; inside `NavBar.Mobile` the same languages as a row in the preferences.\n */\nexport function NavBarLanguage(props: NavBarLanguageProps) {\n const inMobile = React.useContext(MobileContext);\n return <LanguageSwitch variant={inMobile ? \"inline\" : \"menu\"} {...props} />;\n}\n\nexport type NavBarMobilePreferencesProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The group's heading (“Preferences”) — passed translated. */\n label: string;\n};\n\n/** The last group of the mobile panel: the preferences (theme, `NavBar.Language`), in a row under their heading. */\nexport function NavBarMobilePreferences({ label, className, children, ...props }: NavBarMobilePreferencesProps) {\n const id = React.useId();\n return (\n <div role=\"group\" aria-labelledby={id} className={s.mobileGroup({ className })} {...props}>\n <p id={id} className={s.mobileGroupTitle()}>\n {label}\n </p>\n <div className=\"flex flex-wrap items-center gap-2 px-3 py-1\">{children}</div>\n </div>\n );\n}\n\nexport type NavBarRepoProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The repository the site is built from. */\n href: string;\n /** The link's accessible name (“Source on GitHub”) — passed translated. */\n label: string;\n};\n\n/** The site's repository on GitHub, an icon link of `NavBar.Actions`. */\nexport function NavBarRepo({ label, className, ...props }: NavBarRepoProps) {\n return (\n <a aria-label={label} className={s.repo({ className })} {...props}>\n <GitHubGlyph size={18} />\n </a>\n );\n}\n\n/**\n * `NavBar.Root/Brand/Family/Badge/Items/Link/Menu/MenuLink/Actions/Repo/Language/Mobile/MobileGroup/MobilePreferences/MobileLink` — the Krizaka navigation bar,\n * the same on every site of the family: floating, tightening on scroll, the family switcher on the brand, one light\n * gliding between its items, accessible menus, a mobile panel.\n */\nexport const NavBar = {\n Root: NavBarRoot,\n Brand: NavBarBrand,\n Family: NavBarFamily,\n Badge: NavBarBadge,\n Items: NavBarItems,\n Link: NavBarLink,\n Menu: NavBarMenu,\n MenuLink: NavBarMenuLink,\n Actions: NavBarActions,\n Repo: NavBarRepo,\n Language: NavBarLanguage,\n Mobile: NavBarMobile,\n MobilePreferences: NavBarMobilePreferences,\n MobileGroup: NavBarMobileGroup,\n MobileLink: NavBarMobileLink,\n};\n","/**\n * Where a menu panel of the bar sits: its left edge under its trigger's, pushed back inside the page when it would run\n * past the right edge, never closer to the left edge than the gutter. All values are pixels of the page (a bounding\n * rect's `left`, a width), the result is the panel's `left` relative to the bar's navigation (`root`). Pure, so a\n * viewport of 360 px and one of 1280 px are tested without a browser.\n */\nexport interface PlacePanel {\n /** The trigger's left edge. */\n trigger: number;\n /** The navigation's left edge (the panel is positioned inside it). */\n root: number;\n /** The panel's width. */\n panel: number;\n /** The window's width. */\n window: number;\n /**\n * The space kept between the panel and the window's edges.\n * @default 16\n */\n gutter?: number;\n}\n\nexport function placePanel({ trigger, root, panel, window, gutter = 16 }: PlacePanel): number {\n const wanted = trigger - root;\n const farthest = window - gutter - panel - root;\n const nearest = gutter - root;\n return Math.round(Math.max(nearest, Math.min(wanted, farthest)));\n}\n"],"mappings":"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","names":["window"]}
|
package/dist/product-page.js
CHANGED
|
@@ -24,12 +24,7 @@ function ProductPage({ brand, mark, title, lead, facts, actions, visual, visualL
|
|
|
24
24
|
] })
|
|
25
25
|
] }),
|
|
26
26
|
visual && /* @__PURE__ */ jsxs("figure", { className: "kz-tpl-stage", children: [
|
|
27
|
-
/* @__PURE__ */
|
|
28
|
-
/* @__PURE__ */ jsx("i", {}),
|
|
29
|
-
/* @__PURE__ */ jsx("i", {}),
|
|
30
|
-
/* @__PURE__ */ jsx("i", {}),
|
|
31
|
-
visualLabel && /* @__PURE__ */ jsx("span", { children: visualLabel })
|
|
32
|
-
] }),
|
|
27
|
+
/* @__PURE__ */ jsx("div", { className: "kz-tpl-stage-bar", "aria-hidden": true, children: visualLabel && /* @__PURE__ */ jsx("span", { children: visualLabel }) }),
|
|
33
28
|
visual
|
|
34
29
|
] })
|
|
35
30
|
] }) }) }),
|
package/dist/product-page.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/product-page/product-page.tsx"],"sourcesContent":["// Server-safe. A product's overview: the hero with the product's mark, its promise, facts and main action beside a live\n// window of the product; the traps it removes as compact argument cards; its decisions with their cost; the promise a\n// bird keeps; the closing call. Under the product's brand (`brand` → `.brand-<id>`).\nimport { ArgumentCard } from \"@krizaka/ui/argument-card\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\nimport { CtaPanel } from \"@krizaka/ui/cta-panel\";\nimport { type Decision, DecisionList } from \"@krizaka/ui/decision-list\";\nimport { MascotQuote } from \"@krizaka/ui/mascot-quote\";\nimport type { MascotBird } from \"@krizaka/ui/mascots\";\nimport { type Fact, Facts, Page, Section } from \"@krizaka/ui/page\";\nimport type { LinkComponent } from \"@krizaka/ui/page-hero\";\nimport { SectionBackdrop } from \"@krizaka/ui/section-backdrop\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport interface ProductReason {\n /** A stable key (the card's anchor). */\n id: string;\n /** Its name. */\n title: React.ReactNode;\n /** The trap elsewhere, in one line. */\n trap: React.ReactNode;\n /** The signature icon. */\n icon?: React.ReactNode;\n /** The bird in the corner (whose rule it is). */\n mark?: React.ReactNode;\n /** Where the long version lives (a page) — or nothing, and the card stays its face. */\n href?: string;\n}\n\nexport type ProductPageProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The product's brand (`orazaka`, `orochia`…): the page wears `.brand-<id>`. */\n brand?: string;\n /** The product's mark and name, above the title. */\n mark?: React.ReactNode;\n /** The promise: the page's `h1`. */\n title: React.ReactNode;\n /** One or two sentences under it. */\n lead?: React.ReactNode;\n /** Facts under the lead (open source, a law it keeps). */\n facts?: readonly Fact[];\n /** The hero's actions. */\n actions?: React.ReactNode;\n /** The product alive, in a window beside the words. */\n visual?: React.ReactNode;\n /** The window's caption. */\n visualLabel?: React.ReactNode;\n /** The reasons' section heading. */\n reasonsHeading: { eyebrow?: React.ReactNode; title: React.ReactNode; lead?: React.ReactNode };\n /** The words of the cards: the trap's label (read, not shown) and the way in. */\n reasonLabels: { trap: string; more: React.ReactNode };\n /** The traps it removes. */\n reasons: readonly ProductReason[];\n /** The decisions' section: heading, decisions and their four labels. */\n decisions?: { eyebrow?: React.ReactNode; title: React.ReactNode; items: readonly Decision[]; labels: { chose: React.ReactNode; refused: React.ReactNode; because: React.ReactNode; cost: React.ReactNode } };\n /** The promise a bird keeps, under the decisions. */\n promise?: { bird: MascotBird; label: React.ReactNode; text: React.ReactNode };\n /** More sections between the decisions and the closing call (the tour, the platform, a comparison). */\n children?: React.ReactNode;\n /** The closing call. */\n closing?: { title: React.ReactNode; body?: React.ReactNode; actions: React.ReactNode };\n /** The app's link component (Next's `Link`). */\n linkAs?: LinkComponent;\n};\n\n/** A product's overview: split hero, traps as compact cards, decisions with their cost, the bird's promise, closing call. */\nexport function ProductPage({ brand, mark, title, lead, facts, actions, visual, visualLabel, reasonsHeading, reasonLabels, reasons, decisions, promise, closing, linkAs, className, children, ...props }: ProductPageProps) {\n return (\n <div className={cn(brand && \"brand-\" + brand, className)} {...props}>\n <SectionBackdrop as=\"header\" grid className=\"kz-hero\">\n <Page>\n <div className={visual ? \"kz-tpl-split\" : undefined}>\n <div className=\"kz-hero-text\">\n {mark && <p className=\"kz-eyebrow\">{mark}</p>}\n <h1 className=\"kz-hero-title\">{title}</h1>\n {lead && <p className=\"kz-hero-lead\">{lead}</p>}\n {(facts || actions) && (\n <div className=\"kz-hero-extra\">\n {facts && <Facts items={facts} />}\n {actions && <div className=\"kz-tpl-actions\">{actions}</div>}\n </div>\n )}\n </div>\n {visual && (\n <figure className=\"kz-tpl-stage\">\n <div className=\"kz-tpl-stage-bar\" aria-hidden>\n
|
|
1
|
+
{"version":3,"sources":["../src/product-page/product-page.tsx"],"sourcesContent":["// Server-safe. A product's overview: the hero with the product's mark, its promise, facts and main action beside a live\n// window of the product; the traps it removes as compact argument cards; its decisions with their cost; the promise a\n// bird keeps; the closing call. Under the product's brand (`brand` → `.brand-<id>`).\nimport { ArgumentCard } from \"@krizaka/ui/argument-card\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\nimport { CtaPanel } from \"@krizaka/ui/cta-panel\";\nimport { type Decision, DecisionList } from \"@krizaka/ui/decision-list\";\nimport { MascotQuote } from \"@krizaka/ui/mascot-quote\";\nimport type { MascotBird } from \"@krizaka/ui/mascots\";\nimport { type Fact, Facts, Page, Section } from \"@krizaka/ui/page\";\nimport type { LinkComponent } from \"@krizaka/ui/page-hero\";\nimport { SectionBackdrop } from \"@krizaka/ui/section-backdrop\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport interface ProductReason {\n /** A stable key (the card's anchor). */\n id: string;\n /** Its name. */\n title: React.ReactNode;\n /** The trap elsewhere, in one line. */\n trap: React.ReactNode;\n /** The signature icon. */\n icon?: React.ReactNode;\n /** The bird in the corner (whose rule it is). */\n mark?: React.ReactNode;\n /** Where the long version lives (a page) — or nothing, and the card stays its face. */\n href?: string;\n}\n\nexport type ProductPageProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The product's brand (`orazaka`, `orochia`…): the page wears `.brand-<id>`. */\n brand?: string;\n /** The product's mark and name, above the title. */\n mark?: React.ReactNode;\n /** The promise: the page's `h1`. */\n title: React.ReactNode;\n /** One or two sentences under it. */\n lead?: React.ReactNode;\n /** Facts under the lead (open source, a law it keeps). */\n facts?: readonly Fact[];\n /** The hero's actions. */\n actions?: React.ReactNode;\n /** The product alive, in a window beside the words. */\n visual?: React.ReactNode;\n /** The window's caption. */\n visualLabel?: React.ReactNode;\n /** The reasons' section heading. */\n reasonsHeading: { eyebrow?: React.ReactNode; title: React.ReactNode; lead?: React.ReactNode };\n /** The words of the cards: the trap's label (read, not shown) and the way in. */\n reasonLabels: { trap: string; more: React.ReactNode };\n /** The traps it removes. */\n reasons: readonly ProductReason[];\n /** The decisions' section: heading, decisions and their four labels. */\n decisions?: { eyebrow?: React.ReactNode; title: React.ReactNode; items: readonly Decision[]; labels: { chose: React.ReactNode; refused: React.ReactNode; because: React.ReactNode; cost: React.ReactNode } };\n /** The promise a bird keeps, under the decisions. */\n promise?: { bird: MascotBird; label: React.ReactNode; text: React.ReactNode };\n /** More sections between the decisions and the closing call (the tour, the platform, a comparison). */\n children?: React.ReactNode;\n /** The closing call. */\n closing?: { title: React.ReactNode; body?: React.ReactNode; actions: React.ReactNode };\n /** The app's link component (Next's `Link`). */\n linkAs?: LinkComponent;\n};\n\n/** A product's overview: split hero, traps as compact cards, decisions with their cost, the bird's promise, closing call. */\nexport function ProductPage({ brand, mark, title, lead, facts, actions, visual, visualLabel, reasonsHeading, reasonLabels, reasons, decisions, promise, closing, linkAs, className, children, ...props }: ProductPageProps) {\n return (\n <div className={cn(brand && \"brand-\" + brand, className)} {...props}>\n <SectionBackdrop as=\"header\" grid className=\"kz-hero\">\n <Page>\n <div className={visual ? \"kz-tpl-split\" : undefined}>\n <div className=\"kz-hero-text\">\n {mark && <p className=\"kz-eyebrow\">{mark}</p>}\n <h1 className=\"kz-hero-title\">{title}</h1>\n {lead && <p className=\"kz-hero-lead\">{lead}</p>}\n {(facts || actions) && (\n <div className=\"kz-hero-extra\">\n {facts && <Facts items={facts} />}\n {actions && <div className=\"kz-tpl-actions\">{actions}</div>}\n </div>\n )}\n </div>\n {visual && (\n <figure className=\"kz-tpl-stage\">\n <div className=\"kz-tpl-stage-bar\" aria-hidden>\n {visualLabel && <span>{visualLabel}</span>}\n </div>\n {visual}\n </figure>\n )}\n </div>\n </Page>\n </SectionBackdrop>\n <Section id=\"why\" eyebrow={reasonsHeading.eyebrow} title={reasonsHeading.title} lead={reasonsHeading.lead} reveal>\n <CardGrid min={260} fit=\"fit\">\n {reasons.map((r) => (\n <ArgumentCard\n key={r.id}\n id={`why-${r.id}`}\n icon={r.icon}\n title={r.title}\n mark={r.mark}\n hook={{ label: reasonLabels.trap, text: r.trap }}\n more={r.href ? { href: r.href, label: reasonLabels.more } : undefined}\n linkAs={linkAs}\n />\n ))}\n </CardGrid>\n </Section>\n {decisions && (\n <Section id=\"decisions\" eyebrow={decisions.eyebrow} title={decisions.title} divider reveal>\n <DecisionList decisions={decisions.items} labels={decisions.labels} />\n {promise && (\n <div className=\"kz-tpl-promise\">\n <MascotQuote variant=\"callout\" bird={promise.bird} mood=\"welcome\" label={promise.label}>\n {promise.text}\n </MascotQuote>\n </div>\n )}\n </Section>\n )}\n {children}\n {closing && (\n <Section spacing=\"sm\" aria-labelledby=\"product-closing\">\n <CtaPanel id=\"product-closing\" title={closing.title} body={closing.body} reveal>\n {closing.actions}\n </CtaPanel>\n </Section>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAGA,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAwB,oBAAoB;AAC5C,SAAS,mBAAmB;AAE5B,SAAoB,OAAO,MAAM,eAAe;AAEhD,SAAS,uBAAuB;AA+DT,cAIP,YAJO;AAPhB,SAAS,YAAY,EAAE,OAAO,MAAM,OAAO,MAAM,OAAO,SAAS,QAAQ,aAAa,gBAAgB,cAAc,SAAS,WAAW,SAAS,SAAS,QAAQ,WAAW,UAAU,GAAG,MAAM,GAAqB;AAC1N,SACE,qBAAC,SAAI,WAAW,GAAG,SAAS,WAAW,OAAO,SAAS,GAAI,GAAG,OAC5D;AAAA,wBAAC,mBAAgB,IAAG,UAAS,MAAI,MAAC,WAAU,WAC1C,8BAAC,QACC,+BAAC,SAAI,WAAW,SAAS,iBAAiB,QACxC;AAAA,2BAAC,SAAI,WAAU,gBACZ;AAAA,gBAAQ,oBAAC,OAAE,WAAU,cAAc,gBAAK;AAAA,QACzC,oBAAC,QAAG,WAAU,iBAAiB,iBAAM;AAAA,QACpC,QAAQ,oBAAC,OAAE,WAAU,gBAAgB,gBAAK;AAAA,SACzC,SAAS,YACT,qBAAC,SAAI,WAAU,iBACZ;AAAA,mBAAS,oBAAC,SAAM,OAAO,OAAO;AAAA,UAC9B,WAAW,oBAAC,SAAI,WAAU,kBAAkB,mBAAQ;AAAA,WACvD;AAAA,SAEJ;AAAA,MACC,UACC,qBAAC,YAAO,WAAU,gBAChB;AAAA,4BAAC,SAAI,WAAU,oBAAmB,eAAW,MAC1C,yBAAe,oBAAC,UAAM,uBAAY,GACrC;AAAA,QACC;AAAA,SACH;AAAA,OAEJ,GACF,GACF;AAAA,IACA,oBAAC,WAAQ,IAAG,OAAM,SAAS,eAAe,SAAS,OAAO,eAAe,OAAO,MAAM,eAAe,MAAM,QAAM,MAC/G,8BAAC,YAAS,KAAK,KAAK,KAAI,OACrB,kBAAQ,IAAI,CAAC,MACZ;AAAA,MAAC;AAAA;AAAA,QAEC,IAAI,OAAO,EAAE,EAAE;AAAA,QACf,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,MAAM,EAAE;AAAA,QACR,MAAM,EAAE,OAAO,aAAa,MAAM,MAAM,EAAE,KAAK;AAAA,QAC/C,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,aAAa,KAAK,IAAI;AAAA,QAC5D;AAAA;AAAA,MAPK,EAAE;AAAA,IAQT,CACD,GACH,GACF;AAAA,IACC,aACC,qBAAC,WAAQ,IAAG,aAAY,SAAS,UAAU,SAAS,OAAO,UAAU,OAAO,SAAO,MAAC,QAAM,MACxF;AAAA,0BAAC,gBAAa,WAAW,UAAU,OAAO,QAAQ,UAAU,QAAQ;AAAA,MACnE,WACC,oBAAC,SAAI,WAAU,kBACb,8BAAC,eAAY,SAAQ,WAAU,MAAM,QAAQ,MAAM,MAAK,WAAU,OAAO,QAAQ,OAC9E,kBAAQ,MACX,GACF;AAAA,OAEJ;AAAA,IAED;AAAA,IACA,WACC,oBAAC,WAAQ,SAAQ,MAAK,mBAAgB,mBACpC,8BAAC,YAAS,IAAG,mBAAkB,OAAO,QAAQ,OAAO,MAAM,QAAQ,MAAM,QAAM,MAC5E,kBAAQ,SACX,GACF;AAAA,KAEJ;AAEJ;","names":[]}
|
package/dist/progress.js
CHANGED
|
@@ -8,7 +8,7 @@ var progress = tv({
|
|
|
8
8
|
track: "",
|
|
9
9
|
indicator: "",
|
|
10
10
|
center: "absolute inset-0 flex flex-col items-center justify-center text-center",
|
|
11
|
-
buffer: "absolute inset-y-0 left-0 -z-10 rounded-
|
|
11
|
+
buffer: "absolute inset-y-0 left-0 -z-10 rounded-sm bg-accent/25 transition-[width] duration-500 motion-reduce:transition-none",
|
|
12
12
|
frame: "flex w-full flex-col gap-1.5",
|
|
13
13
|
header: "flex flex-wrap items-baseline gap-x-2 gap-y-0.5 text-xs",
|
|
14
14
|
caption: "max-w-full shrink-0 grow truncate font-medium text-fg",
|
|
@@ -17,8 +17,8 @@ var progress = tv({
|
|
|
17
17
|
variants: {
|
|
18
18
|
variant: {
|
|
19
19
|
bar: {
|
|
20
|
-
root: "relative isolate w-full overflow-hidden rounded-
|
|
21
|
-
indicator: "kz-progress h-full rounded-
|
|
20
|
+
root: "relative isolate w-full overflow-hidden rounded-sm bg-surface-3",
|
|
21
|
+
indicator: "kz-progress h-full rounded-sm bg-linear-to-r from-accent to-accent-2 transition-[width] duration-500 motion-reduce:transition-none data-[state=indeterminate]:w-2/5"
|
|
22
22
|
},
|
|
23
23
|
ring: {
|
|
24
24
|
root: "inline-flex shrink-0 items-center justify-center",
|
package/dist/progress.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/progress/progress.tsx"],"sourcesContent":["// Server-safe: no hook, no context. role=\"progressbar\" with aria-valuenow / aria-valuemax (none when indeterminate),\n// named by `label`. A bar or a ring; the ring can hold content in its centre (an amount, a percentage).\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const progress = tv({\n slots: {\n root: \"relative\",\n track: \"\",\n indicator: \"\",\n center: \"absolute inset-0 flex flex-col items-center justify-center text-center\",\n buffer: \"absolute inset-y-0 left-0 -z-10 rounded-full bg-accent/25 transition-[width] duration-500 motion-reduce:transition-none\",\n frame: \"flex w-full flex-col gap-1.5\",\n header: \"flex flex-wrap items-baseline gap-x-2 gap-y-0.5 text-xs\",\n caption: \"max-w-full shrink-0 grow truncate font-medium text-fg\",\n figure: \"shrink-0 tabular-nums text-fg-secondary\",\n },\n variants: {\n variant: {\n bar: {\n root: \"relative isolate w-full overflow-hidden rounded-full bg-surface-3\",\n indicator:\n \"kz-progress h-full rounded-full bg-linear-to-r from-accent to-accent-2 transition-[width] duration-500 motion-reduce:transition-none \" +\n \"data-[state=indeterminate]:w-2/5\",\n },\n ring: {\n root: \"inline-flex shrink-0 items-center justify-center\",\n track: \"stroke-border-default\",\n indicator:\n \"stroke-accent transition-[stroke-dashoffset] duration-1000 motion-reduce:transition-none \" +\n \"data-[state=indeterminate]:origin-center data-[state=indeterminate]:animate-spin motion-reduce:data-[state=indeterminate]:animate-none\",\n },\n },\n size: { sm: {}, md: {}, lg: {} },\n status: {\n active: {},\n // Paused: the fill rests, striped — the task is waiting for someone, not broken.\n paused: { indicator: \"kz-progress-paused opacity-70\" },\n // Failed: the fill turns to the danger colour where it stopped.\n error: { indicator: \"from-danger to-danger stroke-danger\" },\n },\n },\n compoundVariants: [\n { variant: \"bar\", size: \"sm\", class: { root: \"h-1\" } },\n { variant: \"bar\", size: \"md\", class: { root: \"h-2\" } },\n { variant: \"bar\", size: \"lg\", class: { root: \"h-3\" } },\n { variant: \"ring\", size: \"sm\", class: { root: \"h-10 w-10\" } },\n { variant: \"ring\", size: \"md\", class: { root: \"h-20 w-20\" } },\n { variant: \"ring\", size: \"lg\", class: { root: \"h-36 w-36\" } },\n ],\n defaultVariants: { variant: \"bar\", size: \"md\", status: \"active\" },\n});\n\nexport type ProgressVariants = VariantProps<typeof progress>;\n\nexport type ProgressProps = Omit<React.ComponentProps<\"div\">, \"children\"> &\n ProgressVariants & {\n /** bar · ring (a ring holds its `children` in the centre). */\n variant?: ProgressVariants[\"variant\"];\n /** sm · md · lg: the bar's thickness, the ring's diameter. */\n size?: ProgressVariants[\"size\"];\n /** How far, between 0 and `max`. `null` or absent: indeterminate (a wait of unknown length). */\n value?: number | null;\n /** The value that means complete. */\n max?: number;\n /** The accessible name — passed translated (\"Upload\", \"Raised towards the goal\"). */\n label: string;\n /** The value in words for assistive technology (\"$420 of $1,000\") — default: the percentage. */\n valueText?: string;\n /** A ring's centre: an amount, a percentage, an icon. */\n children?: React.ReactNode;\n /** How far is already available beyond the value (a video buffered ahead), between 0 and `max` — bar only. */\n buffer?: number;\n /** Splits the bar or the ring into this many segments: the steps of a task, the parts of a goal. */\n segments?: number;\n /**\n * active · paused (the fill rests, striped: waiting for someone) · error (the fill turns to the danger colour where it stopped).\n * @default \"active\"\n */\n status?: ProgressVariants[\"status\"];\n /** Shows the label above the bar, with the percentage (or `valueText`) and `eta` — bar only. */\n showLabel?: boolean;\n /** The time left, in words (“About 2 min left”), shown with `showLabel` and read with the value — passed translated. */\n eta?: string;\n };\n\nconst STROKE = { sm: 12, md: 9, lg: 7 } as const;\n\n/** A progress bar or ring: `value` / `max`, indeterminate without a value. State: `data-state` (loading · complete · indeterminate). */\nexport function Progress({\n variant = \"bar\",\n size = \"md\",\n value,\n max = 100,\n label,\n valueText,\n className,\n children,\n buffer,\n segments,\n status = \"active\",\n showLabel,\n eta,\n ...props\n}: ProgressProps) {\n const s = progress({ variant, size, status });\n const maskId = `kz-seg-${React.useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n const known = typeof value === \"number\" && Number.isFinite(value);\n const ratio = known ? Math.min(1, Math.max(0, value / (max || 1))) : 0;\n const percent = Math.round(ratio * 100);\n const state = !known ? \"indeterminate\" : ratio >= 1 ? \"complete\" : \"loading\";\n const aria = {\n role: \"progressbar\" as const,\n \"aria-label\": label,\n \"aria-valuemin\": known ? 0 : undefined,\n \"aria-valuemax\": known ? max : undefined,\n \"aria-valuenow\": known ? Math.min(max, Math.max(0, value)) : undefined,\n \"aria-valuetext\": [known ? (valueText ?? `${percent}%`) : valueText, eta].filter(Boolean).join(\", \") || undefined,\n \"data-state\": state,\n \"data-status\": status === \"active\" ? undefined : status,\n \"data-value\": known ? value : undefined,\n \"data-variant\": variant,\n };\n if (variant === \"ring\") {\n const stroke = STROKE[size];\n const r = 50 - stroke / 2;\n return (\n <div {...aria} className={s.root({ className })} {...props}>\n <svg viewBox=\"0 0 100 100\" className=\"h-full w-full -rotate-90\" aria-hidden>\n {segments && segments > 1 && (\n <mask id={maskId}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" stroke=\"white\" strokeWidth={stroke + 2} pathLength={100} strokeDasharray={`${100 / segments - 2} 2`} />\n </mask>\n )}\n <g mask={segments && segments > 1 ? `url(#${maskId})` : undefined}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" strokeWidth={stroke} className={s.track()} />\n <circle\n cx=\"50\"\n cy=\"50\"\n r={r}\n fill=\"none\"\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n pathLength={100}\n strokeDasharray={100}\n strokeDashoffset={known ? 100 - percent : 75}\n data-state={state}\n className={s.indicator()}\n />\n </g>\n </svg>\n {children !== undefined && <div className={s.center()}>{children}</div>}\n </div>\n );\n }\n const segmented = segments && segments > 1 ? ({ \"--kz-segments\": segments } as React.CSSProperties) : undefined;\n const bufferRatio = typeof buffer === \"number\" && Number.isFinite(buffer) ? Math.min(1, Math.max(0, buffer / (max || 1))) : null;\n const bar = (\n <div {...aria} className={s.root({ className: [segmented && \"kz-progress-segmented\", className].filter(Boolean).join(\" \") || undefined })} style={segmented} {...props}>\n <div data-state={state} className={s.indicator()} style={known ? { width: `${ratio * 100}%` } : undefined} />\n {bufferRatio !== null && <div aria-hidden className={s.buffer()} style={{ width: `${bufferRatio * 100}%` }} />}\n </div>\n );\n if (!showLabel) return bar;\n const figure = [known ? (valueText ?? `${percent} %`) : valueText, eta].filter(Boolean).join(\" · \");\n return (\n <div className={s.frame()}>\n <div aria-hidden className={s.header()}>\n <span className={s.caption()}>{label}</span>\n {figure && <span className={s.figure()}>{figure}</span>}\n </div>\n {bar}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/progress/progress.tsx"],"sourcesContent":["// Server-safe: no hook, no context. role=\"progressbar\" with aria-valuenow / aria-valuemax (none when indeterminate),\n// named by `label`. A bar or a ring; the ring can hold content in its centre (an amount, a percentage).\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const progress = tv({\n slots: {\n root: \"relative\",\n track: \"\",\n indicator: \"\",\n center: \"absolute inset-0 flex flex-col items-center justify-center text-center\",\n buffer: \"absolute inset-y-0 left-0 -z-10 rounded-sm bg-accent/25 transition-[width] duration-500 motion-reduce:transition-none\",\n frame: \"flex w-full flex-col gap-1.5\",\n header: \"flex flex-wrap items-baseline gap-x-2 gap-y-0.5 text-xs\",\n caption: \"max-w-full shrink-0 grow truncate font-medium text-fg\",\n figure: \"shrink-0 tabular-nums text-fg-secondary\",\n },\n variants: {\n variant: {\n bar: {\n root: \"relative isolate w-full overflow-hidden rounded-sm bg-surface-3\",\n indicator:\n \"kz-progress h-full rounded-sm bg-linear-to-r from-accent to-accent-2 transition-[width] duration-500 motion-reduce:transition-none \" +\n \"data-[state=indeterminate]:w-2/5\",\n },\n ring: {\n root: \"inline-flex shrink-0 items-center justify-center\",\n track: \"stroke-border-default\",\n indicator:\n \"stroke-accent transition-[stroke-dashoffset] duration-1000 motion-reduce:transition-none \" +\n \"data-[state=indeterminate]:origin-center data-[state=indeterminate]:animate-spin motion-reduce:data-[state=indeterminate]:animate-none\",\n },\n },\n size: { sm: {}, md: {}, lg: {} },\n status: {\n active: {},\n // Paused: the fill rests, striped — the task is waiting for someone, not broken.\n paused: { indicator: \"kz-progress-paused opacity-70\" },\n // Failed: the fill turns to the danger colour where it stopped.\n error: { indicator: \"from-danger to-danger stroke-danger\" },\n },\n },\n compoundVariants: [\n { variant: \"bar\", size: \"sm\", class: { root: \"h-1\" } },\n { variant: \"bar\", size: \"md\", class: { root: \"h-2\" } },\n { variant: \"bar\", size: \"lg\", class: { root: \"h-3\" } },\n { variant: \"ring\", size: \"sm\", class: { root: \"h-10 w-10\" } },\n { variant: \"ring\", size: \"md\", class: { root: \"h-20 w-20\" } },\n { variant: \"ring\", size: \"lg\", class: { root: \"h-36 w-36\" } },\n ],\n defaultVariants: { variant: \"bar\", size: \"md\", status: \"active\" },\n});\n\nexport type ProgressVariants = VariantProps<typeof progress>;\n\nexport type ProgressProps = Omit<React.ComponentProps<\"div\">, \"children\"> &\n ProgressVariants & {\n /** bar · ring (a ring holds its `children` in the centre). */\n variant?: ProgressVariants[\"variant\"];\n /** sm · md · lg: the bar's thickness, the ring's diameter. */\n size?: ProgressVariants[\"size\"];\n /** How far, between 0 and `max`. `null` or absent: indeterminate (a wait of unknown length). */\n value?: number | null;\n /** The value that means complete. */\n max?: number;\n /** The accessible name — passed translated (\"Upload\", \"Raised towards the goal\"). */\n label: string;\n /** The value in words for assistive technology (\"$420 of $1,000\") — default: the percentage. */\n valueText?: string;\n /** A ring's centre: an amount, a percentage, an icon. */\n children?: React.ReactNode;\n /** How far is already available beyond the value (a video buffered ahead), between 0 and `max` — bar only. */\n buffer?: number;\n /** Splits the bar or the ring into this many segments: the steps of a task, the parts of a goal. */\n segments?: number;\n /**\n * active · paused (the fill rests, striped: waiting for someone) · error (the fill turns to the danger colour where it stopped).\n * @default \"active\"\n */\n status?: ProgressVariants[\"status\"];\n /** Shows the label above the bar, with the percentage (or `valueText`) and `eta` — bar only. */\n showLabel?: boolean;\n /** The time left, in words (“About 2 min left”), shown with `showLabel` and read with the value — passed translated. */\n eta?: string;\n };\n\nconst STROKE = { sm: 12, md: 9, lg: 7 } as const;\n\n/** A progress bar or ring: `value` / `max`, indeterminate without a value. State: `data-state` (loading · complete · indeterminate). */\nexport function Progress({\n variant = \"bar\",\n size = \"md\",\n value,\n max = 100,\n label,\n valueText,\n className,\n children,\n buffer,\n segments,\n status = \"active\",\n showLabel,\n eta,\n ...props\n}: ProgressProps) {\n const s = progress({ variant, size, status });\n const maskId = `kz-seg-${React.useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n const known = typeof value === \"number\" && Number.isFinite(value);\n const ratio = known ? Math.min(1, Math.max(0, value / (max || 1))) : 0;\n const percent = Math.round(ratio * 100);\n const state = !known ? \"indeterminate\" : ratio >= 1 ? \"complete\" : \"loading\";\n const aria = {\n role: \"progressbar\" as const,\n \"aria-label\": label,\n \"aria-valuemin\": known ? 0 : undefined,\n \"aria-valuemax\": known ? max : undefined,\n \"aria-valuenow\": known ? Math.min(max, Math.max(0, value)) : undefined,\n \"aria-valuetext\": [known ? (valueText ?? `${percent}%`) : valueText, eta].filter(Boolean).join(\", \") || undefined,\n \"data-state\": state,\n \"data-status\": status === \"active\" ? undefined : status,\n \"data-value\": known ? value : undefined,\n \"data-variant\": variant,\n };\n if (variant === \"ring\") {\n const stroke = STROKE[size];\n const r = 50 - stroke / 2;\n return (\n <div {...aria} className={s.root({ className })} {...props}>\n <svg viewBox=\"0 0 100 100\" className=\"h-full w-full -rotate-90\" aria-hidden>\n {segments && segments > 1 && (\n <mask id={maskId}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" stroke=\"white\" strokeWidth={stroke + 2} pathLength={100} strokeDasharray={`${100 / segments - 2} 2`} />\n </mask>\n )}\n <g mask={segments && segments > 1 ? `url(#${maskId})` : undefined}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" strokeWidth={stroke} className={s.track()} />\n <circle\n cx=\"50\"\n cy=\"50\"\n r={r}\n fill=\"none\"\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n pathLength={100}\n strokeDasharray={100}\n strokeDashoffset={known ? 100 - percent : 75}\n data-state={state}\n className={s.indicator()}\n />\n </g>\n </svg>\n {children !== undefined && <div className={s.center()}>{children}</div>}\n </div>\n );\n }\n const segmented = segments && segments > 1 ? ({ \"--kz-segments\": segments } as React.CSSProperties) : undefined;\n const bufferRatio = typeof buffer === \"number\" && Number.isFinite(buffer) ? Math.min(1, Math.max(0, buffer / (max || 1))) : null;\n const bar = (\n <div {...aria} className={s.root({ className: [segmented && \"kz-progress-segmented\", className].filter(Boolean).join(\" \") || undefined })} style={segmented} {...props}>\n <div data-state={state} className={s.indicator()} style={known ? { width: `${ratio * 100}%` } : undefined} />\n {bufferRatio !== null && <div aria-hidden className={s.buffer()} style={{ width: `${bufferRatio * 100}%` }} />}\n </div>\n );\n if (!showLabel) return bar;\n const figure = [known ? (valueText ?? `${percent} %`) : valueText, eta].filter(Boolean).join(\" · \");\n return (\n <div className={s.frame()}>\n <div aria-hidden className={s.header()}>\n <span className={s.caption()}>{label}</span>\n {figure && <span className={s.figure()}>{figure}</span>}\n </div>\n {bar}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/rail-nav.js
CHANGED
|
@@ -63,7 +63,7 @@ var railNav = tv({
|
|
|
63
63
|
item: "group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0",
|
|
64
64
|
icon: "relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5",
|
|
65
65
|
label: "max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only",
|
|
66
|
-
badge: "absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-
|
|
66
|
+
badge: "absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-sm bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]",
|
|
67
67
|
toggle: "hidden h-10 w-full items-center justify-center gap-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5",
|
|
68
68
|
body: "flex min-w-0 flex-1 flex-col max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]"
|
|
69
69
|
}
|
package/dist/rail-nav.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tooltip/tooltip.tsx","../src/floating.ts","../src/rail-nav/rail-nav.tsx"],"sourcesContent":["// Client (a portal). A short label for a control, on hover after `delayDuration` and on keyboard focus at once;\n// Escape dismisses it. It names nothing: the control keeps its own accessible name (an IconButton's `label`).\nimport { Tooltip as TooltipPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\n/** Optional, once near the root: shares `delayDuration` and the skip delay between tooltips. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\nexport type TooltipProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Content>, \"content\" | \"children\"> & {\n /** What the tooltip says — passed translated. */\n content: React.ReactNode;\n /** The trigger, rendered as is (`asChild`): a focusable element. */\n children: React.ReactNode;\n /** Open or closed (controlled), with `onOpenChange`. */\n open?: boolean;\n /** Open at first, uncontrolled. */\n defaultOpen?: boolean;\n /** Called when it opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Hover delay in ms before it opens (300 by default). */\n delayDuration?: number;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function Tooltip({\n content,\n children,\n open,\n defaultOpen,\n onOpenChange,\n delayDuration = 300,\n container,\n sideOffset = 6,\n collisionPadding = 8,\n className,\n ...props\n}: TooltipProps) {\n return (\n <TooltipPrimitive.Provider delayDuration={delayDuration}>\n <TooltipPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(floating, \"max-w-xs px-2.5 py-1.5 text-xs font-medium origin-(--radix-tooltip-content-transform-origin)\", className)}\n {...props}\n >\n {content}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n}\n","// The one surface of everything that floats next to its trigger (popover, menu, tooltip): a raised surface, a border,\n// the large shadow and the `kz-pop` entrance from the side Radix measured (`--radix-*-transform-origin`).\nexport const floating =\n \"kz-pop z-50 rounded-lg border border-border-default bg-surface-2 text-fg shadow-lg outline-hidden\";\n","// Client (the expand state, the arrow keys, the tooltip). The compact navigation of an application, read from Orazaka's\n// web client: a vertical rail of icons on a desktop — the product's mark on top, a tooltip on each icon, the current one\n// marked by an accent bar on its left edge, a footer for settings and the account — that becomes a bottom tab bar on a\n// phone. The same nodes in both: only the layout changes, so the items, their order and their words are written once.\n// The mark lives in the rail on a desktop; on a phone, where the rail has no room for it, `AppHeader` shows it (the rule\n// « one mark visible at every width »). Brand-aware through the tokens: `accent` scopes `.brand-<id>`.\nimport { Tooltip } from \"@krizaka/ui/tooltip\";\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { ChevronGlyph } from \"../glyphs\";\nimport type { BrandId } from \"../marks/ProductLogo\";\n\nexport const railNav = tv({\n slots: {\n shell: \"flex min-h-dvh w-full bg-surface-0 text-fg\",\n root:\n // Phone: a bottom tab bar, clear of the home indicator. Desktop: a sticky column that is only as wide as its icons.\n \"fixed inset-x-0 bottom-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] flex-row border-t border-border-subtle bg-surface-1 pb-[env(safe-area-inset-bottom)] \" +\n \"md:sticky md:inset-auto md:top-0 md:bottom-auto md:z-auto md:h-dvh md:w-14 md:shrink-0 md:flex-col md:border-t-0 md:border-r md:bg-surface-1 md:pb-0 \" +\n \"md:transition-[width] md:duration-300 motion-reduce:md:transition-none md:data-expanded:w-56\",\n // The mark is the rail's on a desktop; hidden on a phone (the header carries it there).\n mark: \"hidden h-14 w-full shrink-0 items-center justify-center md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-4\",\n group: \"flex min-w-0 flex-row items-stretch md:flex-col md:items-center md:gap-1 md:px-1.5 md:group-data-expanded/rail:items-stretch\",\n main: \"max-md:grow-(--rail-n) md:flex-1 md:py-2\",\n foot: \"max-md:grow-(--rail-n) md:border-t md:border-border-subtle md:py-2\",\n item:\n \"group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset \" +\n \"aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent \" +\n // The accent bar: on the top edge of a tab, on the left edge of a rail item.\n \"before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 \" +\n \"md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm \" +\n \"md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0\",\n icon: \"relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n label: \"max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only\",\n badge:\n \"absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-full bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]\",\n toggle:\n \"hidden h-10 w-full items-center justify-center gap-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset md:flex \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5\",\n body: \"flex min-w-0 flex-1 flex-col max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]\",\n },\n});\nconst s = railNav();\n\ninterface RailState {\n expanded: boolean;\n}\nconst RailContext = React.createContext<RailState | null>(null);\nconst useRail = () => {\n const ctx = React.useContext(RailContext);\n if (!ctx) throw new Error(\"RailNav parts must be inside <RailNav.Root>\");\n return ctx;\n};\n\n/** The frame of the page: the rail, then `RailNav.Body` (the header and the content). A row on a desktop. */\nexport function RailNavShell({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.shell({ className })} {...props} />;\n}\n\n/** The column beside the rail: the `AppHeader`, then the content. On a phone it keeps clear of the tab bar. */\nexport function RailNavBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport type RailNavRootProps = Omit<React.ComponentProps<\"nav\">, \"children\"> & {\n /** The navigation's accessible name (`Orazaka`, `Studio`). */\n label: string;\n /** The product's mark on top of the rail, as a link home (`<Link href=\"/\"><ProductLogo id=\"orazaka\" /></Link>`); named by the app (its `aria-label`). Hidden on a phone: `AppHeader` shows it there. */\n mark?: React.ReactNode;\n /** The product's brand: scopes its colours (`brand-orazaka`…) over the rail, so the accent follows. Omit it inside a page that already wears the brand. */\n accent?: BrandId;\n /** The main destinations: `RailNav.Item`, the ones you work in. Five at most so that they fit a phone's tab bar. */\n children: React.ReactNode;\n /** At the foot of the rail (settings, account), after the main items; on a phone they follow them in the same bar. `RailNav.Item`s or a control with `data-rail-item`. */\n footer?: React.ReactNode;\n /** Adds a button that widens the rail to show the words (desktop only). Needs `expandLabels`. */\n expandable?: boolean;\n /** Controlled width (pair with `onExpandedChange` to keep the choice). */\n expanded?: boolean;\n /** The starting width when uncontrolled. */\n defaultExpanded?: boolean;\n /** Called when the toggle widens or narrows the rail. */\n onExpandedChange?: (expanded: boolean) => void;\n /** The toggle's words, `[expand, collapse]`. */\n expandLabels?: readonly [string, string];\n};\n\nconst count = (node: React.ReactNode) => React.Children.toArray(node).length;\n\n/** Moves the focus along the rail's items with the arrows (↑ ↓ on the rail, ← → on the tab bar; both always work), Home and End. */\nfunction moveFocus(event: React.KeyboardEvent<HTMLElement>) {\n const keys: Record<string, number> = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 };\n const step = keys[event.key];\n if (step === undefined && event.key !== \"Home\" && event.key !== \"End\") return;\n const items = [...event.currentTarget.querySelectorAll<HTMLElement>(\"[data-rail-item]\")];\n if (items.length === 0) return;\n const here = items.findIndex((el) => el === document.activeElement || el.contains(document.activeElement));\n let next: number;\n if (event.key === \"Home\") next = 0;\n else if (event.key === \"End\") next = items.length - 1;\n else if (here < 0) next = step > 0 ? 0 : items.length - 1;\n else next = (here + step + items.length) % items.length;\n event.preventDefault();\n items[next]?.focus();\n}\n\n/** The rail: a vertical column of icons on a desktop, a bottom tab bar on a phone. */\nexport function RailNavRoot({\n label, mark, accent, children, footer, expandable, expanded: controlled, defaultExpanded = false, onExpandedChange, expandLabels, className, onKeyDown, ...props\n}: RailNavRootProps) {\n const [own, setOwn] = React.useState(defaultExpanded);\n const expanded = expandable ? (controlled ?? own) : false;\n const toggle = () => {\n if (controlled === undefined) setOwn(!expanded);\n onExpandedChange?.(!expanded);\n };\n const value = React.useMemo(() => ({ expanded }), [expanded]);\n return (\n <RailContext.Provider value={value}>\n <nav\n aria-label={label}\n data-expanded={expanded ? \"\" : undefined}\n className={cn(\"group/rail\", accent && \"brand-\" + accent, s.root({ className }))}\n onKeyDown={(e) => {\n onKeyDown?.(e);\n if (!e.defaultPrevented) moveFocus(e);\n }}\n {...props}\n >\n {mark && (\n <div data-brand-mark className={s.mark()}>\n {mark}\n </div>\n )}\n <div className={s.group({ className: s.main() })} style={{ [\"--rail-n\" as string]: Math.max(count(children), 1) }}>\n {children}\n </div>\n {(footer || expandable) && (\n <div className={s.group({ className: s.foot() })} style={{ [\"--rail-n\" as string]: Math.max(count(footer), 1) }}>\n {footer}\n {expandable && expandLabels && (\n <button type=\"button\" data-rail-item className={s.toggle()} aria-expanded={expanded} onClick={toggle}>\n <ChevronGlyph direction={expanded ? \"left\" : \"right\"} className=\"h-4 w-4 shrink-0\" />\n <span className={expanded ? undefined : \"sr-only\"}>{expanded ? expandLabels[1] : expandLabels[0]}</span>\n </button>\n )}\n </div>\n )}\n </nav>\n </RailContext.Provider>\n );\n}\n\nexport type RailNavItemProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The item's icon (a signature icon of `@krizaka/icons`): all that shows on a desktop rail. */\n icon: React.ReactNode;\n /** Its words: the accessible name, the tooltip, the tab's caption on a phone, the row's text when the rail is expanded. */\n label: string;\n /** This is the section the user is in: `aria-current=\"page\"`, the accent bar and the accent colour. */\n current?: boolean;\n /** A count (unread, pending) on the icon. Say it in words with `badgeLabel`. */\n badge?: React.ReactNode;\n /** The count in words (« 3 unread »), appended to the accessible name. */\n badgeLabel?: string;\n /** Renders your router's link with the item's look: pass it as the only child. */\n asChild?: boolean;\n children?: React.ReactElement;\n};\n\n/** A destination of the rail. */\nexport function RailNavItem({ icon, label, current, badge, badgeLabel, asChild, children, className, ...props }: RailNavItemProps) {\n const { expanded } = useRail();\n const Comp = asChild ? Slot.Root : \"a\";\n const inner = (\n <>\n <span className={s.icon()}>\n {icon}\n {badge != null && (typeof badge === \"string\" || typeof badge === \"number\") ? (\n // Drawn by CSS, so the count is no text of the link: the visible text stays the label, which the name `Chat, 2 unread` contains.\n <span className={s.badge()} data-count={badge} aria-hidden />\n ) : (\n badge != null && <span className={s.badge()} aria-hidden>{badge}</span>\n )}\n </span>\n <span className={s.label()}>{label}</span>\n </>\n );\n const link = (\n <Comp data-rail-item aria-label={badgeLabel ? `${label}, ${badgeLabel}` : label} aria-current={current ? \"page\" : undefined} className={s.item({ className })} {...props}>\n {asChild && children ? React.cloneElement(children, undefined, inner) : inner}\n </Comp>\n );\n // Expanded, the words are on the row; collapsed, the tooltip says them (Escape dismisses it, the keyboard focus shows it).\n return expanded ? link : <Tooltip content={label} side=\"right\">{link}</Tooltip>;\n}\n\nexport const RailNav = {\n Shell: RailNavShell,\n Root: RailNavRoot,\n Item: RailNavItem,\n Body: RailNavBody,\n};\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/tooltip/tooltip.tsx","../src/floating.ts","../src/rail-nav/rail-nav.tsx"],"sourcesContent":["// Client (a portal). A short label for a control, on hover after `delayDuration` and on keyboard focus at once;\n// Escape dismisses it. It names nothing: the control keeps its own accessible name (an IconButton's `label`).\nimport { Tooltip as TooltipPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\n/** Optional, once near the root: shares `delayDuration` and the skip delay between tooltips. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\nexport type TooltipProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Content>, \"content\" | \"children\"> & {\n /** What the tooltip says — passed translated. */\n content: React.ReactNode;\n /** The trigger, rendered as is (`asChild`): a focusable element. */\n children: React.ReactNode;\n /** Open or closed (controlled), with `onOpenChange`. */\n open?: boolean;\n /** Open at first, uncontrolled. */\n defaultOpen?: boolean;\n /** Called when it opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Hover delay in ms before it opens (300 by default). */\n delayDuration?: number;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function Tooltip({\n content,\n children,\n open,\n defaultOpen,\n onOpenChange,\n delayDuration = 300,\n container,\n sideOffset = 6,\n collisionPadding = 8,\n className,\n ...props\n}: TooltipProps) {\n return (\n <TooltipPrimitive.Provider delayDuration={delayDuration}>\n <TooltipPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(floating, \"max-w-xs px-2.5 py-1.5 text-xs font-medium origin-(--radix-tooltip-content-transform-origin)\", className)}\n {...props}\n >\n {content}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n}\n","// The one surface of everything that floats next to its trigger (popover, menu, tooltip): a raised surface, a border,\n// the large shadow and the `kz-pop` entrance from the side Radix measured (`--radix-*-transform-origin`).\nexport const floating =\n \"kz-pop z-50 rounded-lg border border-border-default bg-surface-2 text-fg shadow-lg outline-hidden\";\n","// Client (the expand state, the arrow keys, the tooltip). The compact navigation of an application, read from Orazaka's\n// web client: a vertical rail of icons on a desktop — the product's mark on top, a tooltip on each icon, the current one\n// marked by an accent bar on its left edge, a footer for settings and the account — that becomes a bottom tab bar on a\n// phone. The same nodes in both: only the layout changes, so the items, their order and their words are written once.\n// The mark lives in the rail on a desktop; on a phone, where the rail has no room for it, `AppHeader` shows it (the rule\n// « one mark visible at every width »). Brand-aware through the tokens: `accent` scopes `.brand-<id>`.\nimport { Tooltip } from \"@krizaka/ui/tooltip\";\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { ChevronGlyph } from \"../glyphs\";\nimport type { BrandId } from \"../marks/ProductLogo\";\n\nexport const railNav = tv({\n slots: {\n shell: \"flex min-h-dvh w-full bg-surface-0 text-fg\",\n root:\n // Phone: a bottom tab bar, clear of the home indicator. Desktop: a sticky column that is only as wide as its icons.\n \"fixed inset-x-0 bottom-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] flex-row border-t border-border-subtle bg-surface-1 pb-[env(safe-area-inset-bottom)] \" +\n \"md:sticky md:inset-auto md:top-0 md:bottom-auto md:z-auto md:h-dvh md:w-14 md:shrink-0 md:flex-col md:border-t-0 md:border-r md:bg-surface-1 md:pb-0 \" +\n \"md:transition-[width] md:duration-300 motion-reduce:md:transition-none md:data-expanded:w-56\",\n // The mark is the rail's on a desktop; hidden on a phone (the header carries it there).\n mark: \"hidden h-14 w-full shrink-0 items-center justify-center md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-4\",\n group: \"flex min-w-0 flex-row items-stretch md:flex-col md:items-center md:gap-1 md:px-1.5 md:group-data-expanded/rail:items-stretch\",\n main: \"max-md:grow-(--rail-n) md:flex-1 md:py-2\",\n foot: \"max-md:grow-(--rail-n) md:border-t md:border-border-subtle md:py-2\",\n item:\n \"group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset \" +\n \"aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent \" +\n // The accent bar: on the top edge of a tab, on the left edge of a rail item.\n \"before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 \" +\n \"md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm \" +\n \"md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0\",\n icon: \"relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n label: \"max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only\",\n badge:\n \"absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-sm bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]\",\n toggle:\n \"hidden h-10 w-full items-center justify-center gap-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset md:flex \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5\",\n body: \"flex min-w-0 flex-1 flex-col max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]\",\n },\n});\nconst s = railNav();\n\ninterface RailState {\n expanded: boolean;\n}\nconst RailContext = React.createContext<RailState | null>(null);\nconst useRail = () => {\n const ctx = React.useContext(RailContext);\n if (!ctx) throw new Error(\"RailNav parts must be inside <RailNav.Root>\");\n return ctx;\n};\n\n/** The frame of the page: the rail, then `RailNav.Body` (the header and the content). A row on a desktop. */\nexport function RailNavShell({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.shell({ className })} {...props} />;\n}\n\n/** The column beside the rail: the `AppHeader`, then the content. On a phone it keeps clear of the tab bar. */\nexport function RailNavBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport type RailNavRootProps = Omit<React.ComponentProps<\"nav\">, \"children\"> & {\n /** The navigation's accessible name (`Orazaka`, `Studio`). */\n label: string;\n /** The product's mark on top of the rail, as a link home (`<Link href=\"/\"><ProductLogo id=\"orazaka\" /></Link>`); named by the app (its `aria-label`). Hidden on a phone: `AppHeader` shows it there. */\n mark?: React.ReactNode;\n /** The product's brand: scopes its colours (`brand-orazaka`…) over the rail, so the accent follows. Omit it inside a page that already wears the brand. */\n accent?: BrandId;\n /** The main destinations: `RailNav.Item`, the ones you work in. Five at most so that they fit a phone's tab bar. */\n children: React.ReactNode;\n /** At the foot of the rail (settings, account), after the main items; on a phone they follow them in the same bar. `RailNav.Item`s or a control with `data-rail-item`. */\n footer?: React.ReactNode;\n /** Adds a button that widens the rail to show the words (desktop only). Needs `expandLabels`. */\n expandable?: boolean;\n /** Controlled width (pair with `onExpandedChange` to keep the choice). */\n expanded?: boolean;\n /** The starting width when uncontrolled. */\n defaultExpanded?: boolean;\n /** Called when the toggle widens or narrows the rail. */\n onExpandedChange?: (expanded: boolean) => void;\n /** The toggle's words, `[expand, collapse]`. */\n expandLabels?: readonly [string, string];\n};\n\nconst count = (node: React.ReactNode) => React.Children.toArray(node).length;\n\n/** Moves the focus along the rail's items with the arrows (↑ ↓ on the rail, ← → on the tab bar; both always work), Home and End. */\nfunction moveFocus(event: React.KeyboardEvent<HTMLElement>) {\n const keys: Record<string, number> = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 };\n const step = keys[event.key];\n if (step === undefined && event.key !== \"Home\" && event.key !== \"End\") return;\n const items = [...event.currentTarget.querySelectorAll<HTMLElement>(\"[data-rail-item]\")];\n if (items.length === 0) return;\n const here = items.findIndex((el) => el === document.activeElement || el.contains(document.activeElement));\n let next: number;\n if (event.key === \"Home\") next = 0;\n else if (event.key === \"End\") next = items.length - 1;\n else if (here < 0) next = step > 0 ? 0 : items.length - 1;\n else next = (here + step + items.length) % items.length;\n event.preventDefault();\n items[next]?.focus();\n}\n\n/** The rail: a vertical column of icons on a desktop, a bottom tab bar on a phone. */\nexport function RailNavRoot({\n label, mark, accent, children, footer, expandable, expanded: controlled, defaultExpanded = false, onExpandedChange, expandLabels, className, onKeyDown, ...props\n}: RailNavRootProps) {\n const [own, setOwn] = React.useState(defaultExpanded);\n const expanded = expandable ? (controlled ?? own) : false;\n const toggle = () => {\n if (controlled === undefined) setOwn(!expanded);\n onExpandedChange?.(!expanded);\n };\n const value = React.useMemo(() => ({ expanded }), [expanded]);\n return (\n <RailContext.Provider value={value}>\n <nav\n aria-label={label}\n data-expanded={expanded ? \"\" : undefined}\n className={cn(\"group/rail\", accent && \"brand-\" + accent, s.root({ className }))}\n onKeyDown={(e) => {\n onKeyDown?.(e);\n if (!e.defaultPrevented) moveFocus(e);\n }}\n {...props}\n >\n {mark && (\n <div data-brand-mark className={s.mark()}>\n {mark}\n </div>\n )}\n <div className={s.group({ className: s.main() })} style={{ [\"--rail-n\" as string]: Math.max(count(children), 1) }}>\n {children}\n </div>\n {(footer || expandable) && (\n <div className={s.group({ className: s.foot() })} style={{ [\"--rail-n\" as string]: Math.max(count(footer), 1) }}>\n {footer}\n {expandable && expandLabels && (\n <button type=\"button\" data-rail-item className={s.toggle()} aria-expanded={expanded} onClick={toggle}>\n <ChevronGlyph direction={expanded ? \"left\" : \"right\"} className=\"h-4 w-4 shrink-0\" />\n <span className={expanded ? undefined : \"sr-only\"}>{expanded ? expandLabels[1] : expandLabels[0]}</span>\n </button>\n )}\n </div>\n )}\n </nav>\n </RailContext.Provider>\n );\n}\n\nexport type RailNavItemProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The item's icon (a signature icon of `@krizaka/icons`): all that shows on a desktop rail. */\n icon: React.ReactNode;\n /** Its words: the accessible name, the tooltip, the tab's caption on a phone, the row's text when the rail is expanded. */\n label: string;\n /** This is the section the user is in: `aria-current=\"page\"`, the accent bar and the accent colour. */\n current?: boolean;\n /** A count (unread, pending) on the icon. Say it in words with `badgeLabel`. */\n badge?: React.ReactNode;\n /** The count in words (« 3 unread »), appended to the accessible name. */\n badgeLabel?: string;\n /** Renders your router's link with the item's look: pass it as the only child. */\n asChild?: boolean;\n children?: React.ReactElement;\n};\n\n/** A destination of the rail. */\nexport function RailNavItem({ icon, label, current, badge, badgeLabel, asChild, children, className, ...props }: RailNavItemProps) {\n const { expanded } = useRail();\n const Comp = asChild ? Slot.Root : \"a\";\n const inner = (\n <>\n <span className={s.icon()}>\n {icon}\n {badge != null && (typeof badge === \"string\" || typeof badge === \"number\") ? (\n // Drawn by CSS, so the count is no text of the link: the visible text stays the label, which the name `Chat, 2 unread` contains.\n <span className={s.badge()} data-count={badge} aria-hidden />\n ) : (\n badge != null && <span className={s.badge()} aria-hidden>{badge}</span>\n )}\n </span>\n <span className={s.label()}>{label}</span>\n </>\n );\n const link = (\n <Comp data-rail-item aria-label={badgeLabel ? `${label}, ${badgeLabel}` : label} aria-current={current ? \"page\" : undefined} className={s.item({ className })} {...props}>\n {asChild && children ? React.cloneElement(children, undefined, inner) : inner}\n </Comp>\n );\n // Expanded, the words are on the row; collapsed, the tooltip says them (Escape dismisses it, the keyboard focus shows it).\n return expanded ? link : <Tooltip content={label} side=\"right\">{link}</Tooltip>;\n}\n\nexport const RailNav = {\n Shell: RailNavShell,\n Root: RailNavRoot,\n Item: RailNavItem,\n Body: RailNavBody,\n};\n"],"mappings":"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","names":["jsx","jsxs"]}
|
package/dist/service-card.js
CHANGED
|
@@ -19,7 +19,7 @@ var serviceCard = tv({
|
|
|
19
19
|
titles: "flex min-w-0 flex-1 flex-col gap-1",
|
|
20
20
|
name: "m-0 font-display text-lg font-bold leading-tight tracking-tight text-fg",
|
|
21
21
|
facts: "m-0 flex list-none flex-wrap gap-x-2 gap-y-0.5 p-0 text-xs text-fg-secondary",
|
|
22
|
-
tag: "shrink-0 rounded-
|
|
22
|
+
tag: "shrink-0 rounded-sm bg-accent px-2 py-0.5 text-[10px] font-extrabold text-on-accent",
|
|
23
23
|
description: "m-0 text-sm leading-relaxed text-fg-secondary",
|
|
24
24
|
included: "m-0 flex list-none flex-col gap-1.5 p-0 text-sm text-fg-secondary",
|
|
25
25
|
includedItem: "flex items-start gap-2 [&>svg]:mt-0.5 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0 [&>svg]:text-fg-accent",
|
|
@@ -27,7 +27,7 @@ var serviceCard = tv({
|
|
|
27
27
|
priceBlock: "flex flex-col leading-none",
|
|
28
28
|
from: "mb-1 text-[11px] font-semibold text-fg-secondary",
|
|
29
29
|
price: "font-display text-2xl font-black tabular-nums text-fg",
|
|
30
|
-
action: "inline-flex min-h-9 items-center gap-1 rounded-
|
|
30
|
+
action: "inline-flex min-h-9 items-center gap-1 rounded-sm text-sm font-bold text-fg-accent no-underline after:absolute after:inset-0 after:content-[''] focus-visible:outline-hidden group-data-[selected]:text-fg"
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
33
|
var s = serviceCard();
|