@photon-ai/pho-ui 2.3.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/chunks/basic-page-w6ftlo0h.js +1284 -0
  2. package/dist/chunks/basic-page-w6ftlo0h.js.map +1 -0
  3. package/dist/chunks/{dialog-fWS3A3Z-.js → dialog-8SRNi_rv.js} +2 -2
  4. package/dist/chunks/{dialog-fWS3A3Z-.js.map → dialog-8SRNi_rv.js.map} +1 -1
  5. package/dist/chunks/{input-CCd6XK7Z.js → input-DjvZoF8v.js} +45 -41
  6. package/dist/chunks/input-DjvZoF8v.js.map +1 -0
  7. package/dist/chunks/{input-group-5AtpIhC_.js → input-group-fc9_jD4d.js} +44 -38
  8. package/dist/chunks/input-group-fc9_jD4d.js.map +1 -0
  9. package/dist/chunks/kbd-DNI10uy7.js +18 -0
  10. package/dist/chunks/kbd-DNI10uy7.js.map +1 -0
  11. package/dist/chunks/{scroll-area-DkZHKfqH.js → scroll-area-Bu7egArU.js} +40 -26
  12. package/dist/chunks/scroll-area-Bu7egArU.js.map +1 -0
  13. package/dist/chunks/sidebar-DvB-G0BP.js +231 -0
  14. package/dist/chunks/sidebar-DvB-G0BP.js.map +1 -0
  15. package/dist/chunks/toast-DoXaRPIZ.js +167 -0
  16. package/dist/chunks/toast-DoXaRPIZ.js.map +1 -0
  17. package/dist/components/command.js +125 -172
  18. package/dist/components/command.js.map +1 -1
  19. package/dist/components/dialog.js +1 -1
  20. package/dist/components/input-group.js +1 -1
  21. package/dist/components/input.js +1 -1
  22. package/dist/components/kbd.js +2 -15
  23. package/dist/components/phone-input.js +1 -1
  24. package/dist/components/scroll-area.js +3 -2
  25. package/dist/components/toast.js +3 -57
  26. package/dist/index.js +65 -58
  27. package/dist/primitives.js +1 -1
  28. package/dist/sections/basic-page.js +15 -8
  29. package/dist/sections/sidebar.js +1 -1
  30. package/dist/src/components/command/command.d.ts +5 -4
  31. package/dist/src/components/input/input.d.ts +10 -1
  32. package/dist/src/components/input-group/input-group.d.ts +9 -2
  33. package/dist/src/components/scroll-area/index.d.ts +1 -0
  34. package/dist/src/components/scroll-area/scroll-area-edges.d.ts +6 -0
  35. package/dist/src/components/scroll-area/scroll-area.d.ts +15 -2
  36. package/dist/src/components/toast/index.d.ts +1 -1
  37. package/dist/src/components/toast/toast.d.ts +22 -7
  38. package/dist/src/sections/basic-page/basic-page.d.ts +140 -3
  39. package/dist/src/sections/basic-page/index.d.ts +1 -1
  40. package/dist/src/sections/sidebar/sidebar.d.ts +33 -3
  41. package/package.json +1 -1
  42. package/src/styles/pho.css +19 -0
  43. package/dist/chunks/basic-page-BkLG3Ybg.js +0 -942
  44. package/dist/chunks/basic-page-BkLG3Ybg.js.map +0 -1
  45. package/dist/chunks/input-CCd6XK7Z.js.map +0 -1
  46. package/dist/chunks/input-group-5AtpIhC_.js.map +0 -1
  47. package/dist/chunks/scroll-area-DkZHKfqH.js.map +0 -1
  48. package/dist/chunks/sidebar-Dt1F_CEP.js +0 -186
  49. package/dist/chunks/sidebar-Dt1F_CEP.js.map +0 -1
  50. package/dist/components/kbd.js.map +0 -1
  51. package/dist/components/toast.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"basic-page-BkLG3Ybg.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconChevronRight.mjs","../../src/sections/basic-page/basic-page.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.46.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M9 6l6 6l-6 6\", \"key\": \"svg-0\" }]];\nconst IconChevronRight = createReactComponent(\"outline\", \"chevron-right\", \"ChevronRight\", __iconNode);\n\nexport { __iconNode, IconChevronRight as default };\n//# sourceMappingURL=IconChevronRight.mjs.map\n","import {\n Children,\n createContext,\n Fragment,\n isValidElement,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type AnchorHTMLAttributes,\n type ComponentProps,\n type ReactNode,\n type Ref,\n type RefObject,\n} from \"react\";\nimport {\n AnimatePresence,\n motion,\n useIsPresent,\n useReducedMotion,\n} from \"motion/react\";\nimport { IconChevronLeft, IconChevronRight } from \"@tabler/icons-react\";\nimport {\n Button,\n ButtonLink,\n type ButtonLinkProps,\n type ButtonProps,\n} from \"../../components/button\";\nimport { Error as ErrorLine } from \"../../components/error\";\nimport { Form as FormElement } from \"../../components/form\";\nimport { Menu } from \"../../components/menu\";\nimport { AnimatedHeight } from \"../../utils/animated-height\";\nimport { cn } from \"../../utils/cn\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\n\n/**\n * BasicPage — Pho's standard content page: a page title, section titles, and\n * bordered cards of label/control rows. Settings, billing, members — any\n * single-column management surface.\n *\n * Spacing: wrap the page in `Root` (a 42rem column with `px-5` gutters,\n * vertical padding). `Stack` separates blocks (`gap-10`). Inside a block,\n * children share `gap-3`. Wrap a section title + description in `Header`\n * (no gap — title and description sit flush) so that pair stays tight —\n * don't put them as loose siblings.\n * Parts already carry `px-5`.\n *\n * Navigation: pages may drill into subpages. `RowLink` is a whole-row link\n * (trailing chevron) and `Back` returns to the parent — both render through\n * the host's `LinkProvider`; the URL itself stays the router's job. `Back`\n * floats in `Root`'s top padding, so `Title` never moves between pages that\n * have a back link and pages that don't.\n */\n\n/* ------------------------------- class map ------------------------------- */\n\n/** Card surface — border, corner, fill; no divider rules. */\nconst BASIC_PAGE_CARD_SURFACE =\n \"rounded-base border border-pho-secondary bg-pho-primary\";\n\n/**\n * Card divider rules — hairlines between direct children. A row followed by\n * an `Alert` drops its divider (the `:has()` rule) so the error line reads\n * as part of the row it belongs to — the alert's own bottom divider takes\n * over toward whatever follows. Kept separate from the surface so\n * `animateHeight` can move the dividers onto the measured content wrapper.\n */\nconst BASIC_PAGE_CARD_DIVIDERS =\n \"divide-y divide-pho-secondary [&>:has(+[data-basic-page-alert])]:border-b-0\";\n\n/** Bordered card that stacks rows with hairline dividers. */\nexport const BASIC_PAGE_CARD = `${BASIC_PAGE_CARD_SURFACE} ${BASIC_PAGE_CARD_DIVIDERS}`;\n\n/**\n * Standalone callout surface — featured block (invite form, notice, etc.).\n * Don't wrap in `Card`; this is the outer chrome.\n */\nexport const BASIC_PAGE_CALLOUT =\n \"flex min-w-0 flex-col gap-3 rounded-base border border-pho-secondary bg-pho-page p-5\";\n\n/**\n * One row — label (+ optional description) left, control right.\n * `min-h-[4.25rem]` (68px) keeps avatar/control rows from collapsing shorter\n * than a comfortable touch target.\n */\nexport const BASIC_PAGE_ROW =\n \"flex min-h-[4.25rem] min-w-0 flex-col gap-3 px-5 py-4 sm:flex-row sm:items-center sm:justify-between sm:gap-6\";\n\n/**\n * One card row that can host subviews. Same padding rhythm as a plain row —\n * an optional trailing `ItemPanel` breaks out of it on its own.\n */\nexport const BASIC_PAGE_ITEM = \"flex flex-col gap-3 px-5 py-4\";\n\n/**\n * Secondary strip closing an `Item` that is last in its card. Negative\n * margins escape the item's `px-5 pb-4` so the gray sheet runs edge-to-edge\n * and owns the row's bottom padding. The body above stays square and the\n * sheet's top is flush against it; only the bottom rounds, nesting into the\n * card's 12px corner (11px inside the 1px border). Content lands back on the\n * item's left gutter.\n */\nexport const BASIC_PAGE_ITEM_PANEL =\n \"-mx-5 -mb-4 flex items-center rounded-b-[calc(0.75rem-1px)] bg-pho-secondary py-1 pr-3 pl-5\";\n\n/**\n * Mid-list variant — the full-bleed sheet only reads well against the card's\n * bottom corner, so when later rows follow, the panel becomes an inset chip\n * instead: fully rounded at the small-control radius, overhanging the text\n * gutter by 8px per side (content stays aligned with the body above), and\n * leaving the row's own bottom padding and the card's hairline divider alone.\n * `-mt-1.5` collapses the item's `gap-3` (12px) to an effective `gap-1.5` (6px).\n */\nexport const BASIC_PAGE_ITEM_PANEL_DIVIDED =\n \"-mx-2 -mt-1.5 flex items-center rounded-sm bg-pho-secondary px-2 py-0.5\";\n\n/* --------------------------------- motion -------------------------------- */\n\n/**\n * One spring for every BasicPage motion — the `Stack` entrance, `Title` /\n * `Header` enter, `Reveal`, the Title ↔ Back morph, and the `Alert` /\n * `Footer` height reveals. Measured off a 60fps iOS push: ~330ms with a\n * long, gentle glide, everything co-landing. Essentially critically damped\n * (an overshooting edge would show clipped content).\n */\nconst ENTRANCE_SPRING = {\n type: \"spring\",\n stiffness: 400,\n damping: 40,\n} as const;\n\n/** Fade paired with the spring — spans most of the glide. */\nconst ENTRANCE_FADE = { duration: 0.25, ease: \"easeOut\" } as const;\n\n/**\n * Rise distance for the `Reveal` / `Stack` / `enter` entrances — small\n * travel; the content surfaces, it doesn't slide in.\n */\nconst REVEAL_RISE_PX = 12;\n\n/* --------------------------------- parts --------------------------------- */\n\n/**\n * Page chrome — centered column at the standard content width. Hosts\n * `Title` + `Stack` (and any route-level siblings). Prefer this over\n * ad-hoc `max-w-*` wrappers in the app shell.\n *\n * `44.5rem` = the 42rem (`2xl`) content column plus the two `px-5` gutters,\n * so wide viewports render exactly as before while narrow ones keep a 20px\n * breathing edge instead of running content into the viewport.\n *\n * `relative` anchors `Back`, which floats in the top padding. The top zone\n * is conditional (`:has()`): pages carrying a `Back` reserve 64px for it;\n * pages without one keep the tighter 48px so the title doesn't sit low.\n *\n * The column is also a `min-h-full` flex stack: when the host gives it a\n * height context (an app shell's scroll pane), a full-page state can claim\n * the leftover viewport with `flex-1` — `ErrorView className=\"flex-1\"`\n * centers itself vertically below the title. Hosts without a height context\n * see a normal column; regular pages are unaffected.\n *\n * Root itself never animates — the page entrance lives on `Stack`, so\n * `Title` and `Back` (the page chrome) stay put while the body below rises\n * in.\n */\nexport interface BasicPageRootProps extends ComponentProps<\"div\"> {\n ref?: Ref<HTMLDivElement>;\n /**\n * Condense on scroll — on by default. Once the title has scrolled out of\n * the pane, a sticky bar pins to the top with the way back and the page\n * name: the large title collapsing into its bar. It assembles itself\n * from `Title` and the trail's tail crumb; nothing to wire. Pass `false`\n * for a page that should scroll away whole.\n */\n condense?: boolean;\n}\n\nfunction Root({\n condense = true,\n className,\n children,\n ...props\n}: BasicPageRootProps) {\n const [title, setTitle] = useState<{\n label: ReactNode;\n el: HTMLElement | null;\n } | null>(null);\n const [tail, setTail] = useState<CondenseTail | null>(null);\n const registry = useMemo<CondenseRegistry>(() => ({ setTitle, setTail }), []);\n // The page is a full-width shell that owns the chrome — the trail in its\n // top-left corner, the condensing bar across its top — around a centered\n // content column. The chrome belongs to the pane, not the column: on a\n // wide pane the way back stays at the corner while the column centers.\n return (\n <div\n data-basic-page-root=\"\"\n className={cn(\n \"relative flex min-h-full w-full min-w-0 flex-col\",\n className,\n )}\n {...props}\n >\n {condense && <CondenseBar title={title} tail={tail} />}\n <div\n data-basic-page-column=\"\"\n className=\"mx-auto flex w-full max-w-[44.5rem] min-w-0 flex-1 flex-col px-5 pt-12 pb-12 *:min-w-0 has-[[data-basic-page-back]]:pt-16\"\n >\n {condense ? (\n <CondenseContext.Provider value={registry}>\n {children}\n </CondenseContext.Provider>\n ) : (\n children\n )}\n </div>\n </div>\n );\n}\n\n/**\n * The condensed header — hidden until the whole heading has left the\n * scrollport (observed against the nearest scrollable ancestor), then fades\n * in pinned to the top: the tail crumb as the way back at the left, the\n * page name centered. Unmounted while hidden so it never catches focus or\n * clicks meant for the trail beneath it. It stacks above a scroll area's\n * own top edge (`z-20` over its `z-10`), whose gradient blur would\n * otherwise sit on the title text.\n */\nfunction CondenseBar({\n title,\n tail,\n}: {\n title: { label: ReactNode; el: HTMLElement | null } | null;\n tail: CondenseTail | null;\n}) {\n const reduceMotion = useReducedMotion();\n const [condensed, setCondensed] = useState(false);\n const el = title?.el ?? null;\n useEffect(() => {\n if (el == null || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(\n ([entry]) => setCondensed(entry != null && !entry.isIntersecting),\n { root: findScrollParent(el) },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [el]);\n return (\n <div\n data-basic-page-condense=\"\"\n className=\"sticky top-0 z-20 h-0 overflow-visible\"\n >\n <AnimatePresence>\n {condensed && (\n <motion.div\n initial={{\n opacity: 0,\n y: reduceMotion ? 0 : CONDENSE_BAR_RISE_PX,\n }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: reduceMotion ? 0 : CONDENSE_BAR_RISE_PX }}\n transition={CONDENSE_BAR_ENTER}\n // Three columns, the outer two equal, so the page name sits at\n // the bar's center whatever the way back is wide, never under it;\n // a long name truncates in its own cell. A name that is itself a\n // flex row (a word and a badge) centers as a block, which\n // text-align alone would not do.\n className=\"border-pho-secondary bg-pho-page/85 relative grid h-12 grid-cols-[1fr_minmax(0,auto)_1fr] items-center border-b px-3 backdrop-blur\"\n >\n <div className=\"flex min-w-0 items-center justify-start\">\n {tail != null && (\n <ButtonLink\n variant=\"ghost\"\n size=\"sm\"\n href={tail.href}\n onClick={tail.onClick}\n prefix={\n <span className=\"inline-flex [&>svg]:size-[1.125em] [&>svg]:shrink-0\">\n <IconChevronLeft />\n </span>\n }\n className=\"min-w-max\"\n >\n {tail.label}\n </ButtonLink>\n )}\n </div>\n <span className=\"text-pho-primary block max-w-full min-w-0 truncate text-center text-base font-medium\">\n {title?.label}\n </span>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n}\n\n/**\n * Slug for hash targets — \"Danger zone\" → `danger-zone`. Empty / non-string\n * children yield no id; pass an explicit `id` to override or `id=\"\"` to opt out.\n */\nfunction slugifyHeading(value: string): string {\n return value\n .normalize(\"NFKD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nfunction headingIdFromChildren(children: ReactNode): string | undefined {\n if (typeof children !== \"string\" && typeof children !== \"number\") {\n return undefined;\n }\n const slug = slugifyHeading(String(children));\n return slug || undefined;\n}\n\n/** Resolve `id`: explicit wins; `\"\"` opts out; else slug from plain-text children. */\nfunction resolveHeadingId(\n id: string | undefined,\n children: ReactNode,\n): string | undefined {\n if (id === \"\") return undefined;\n if (id != null) return id;\n return headingIdFromChildren(children);\n}\n\n/**\n * Namespaced Motion `layoutId` for the Title ↔ Back shared-element morph —\n * give a parent page's `Title` and its subpage's `Back` the same `morphId`\n * and the word itself travels between the two: the large title shrinks into\n * the back link on drill-in, and grows back on return.\n */\nconst morphLayoutId = (id: string) => `basic-page-morph-${id}`;\n\n/** The morph rides the page-tier entrance spring — one glide, everywhere. */\nconst MORPH_TRANSITION = { layout: ENTRANCE_SPRING } as const;\n\n/**\n * Chevron entrance for a morphing `Back`, measured off a 60fps iOS push\n * (sub-pixel tracking of the recording): the arrow emerges from under the\n * left edge of the arriving word at ~62% of the flight — sliding left by\n * ~2/3 of its own width with a strong ease-out while fading in over ~120ms\n * — and lands together with the word, which is still gliding its last few\n * pixels the whole time. Nothing is sequential.\n */\nconst MORPH_CHEVRON_RISE_X = 10;\nconst MORPH_CHEVRON_ENTER = {\n delay: 0.2,\n duration: 0.12,\n ease: \"easeOut\",\n} as const;\n\n/**\n * Ink crossfade for the morphing word — iOS redraws the word in the\n * destination's ink and fades the origin-ink rendition out over the first\n * half of the flight, so the word takes off in the color it had and lands\n * in the color it gets. `MorphLabel` mounts the ghost only while a layout\n * animation is actually running, so static renders never see it.\n */\nconst MORPH_INK_FADE = { duration: 0.18, ease: \"easeOut\" } as const;\n\n/**\n * Deeper than one level, the back link's slot is already occupied when a\n * navigation happens, and iOS treats the chevron as furniture: it stays put\n * across pushes and pops between subpages, and only the label changes.\n * Measured off the WLAN → Succade push and its pop in the same recording:\n *\n * - **Push** — the outgoing back label leaves as the old title shrinks\n * into its place: iOS slides it the whole way under the chevron in\n * ~130ms; here it fades out with a short drift in that direction — the\n * full slide read as a whoosh next to a word that is still arriving.\n * - **Pop** — the incoming back label slides right out from under the\n * chevron, starting ~40% into the title's return flight, ~150ms.\n * - **Pop to the root** — no back link remains; the chevron fades out in\n * place over the first frames while the word grows into the title.\n */\nconst BACK_LABEL_LEAVE_X = -8;\nconst BACK_LABEL_LEAVE = { duration: 0.16, ease: \"easeOut\" } as const;\nconst BACK_LABEL_ARRIVE = {\n delay: 0.14,\n duration: 0.16,\n ease: \"easeOut\",\n} as const;\nconst BACK_CHEVRON_LEAVE = { duration: 0.12, ease: \"easeOut\" } as const;\n\n/**\n * Trails (breadcrumb navs) currently mounted — one per page. Read at render\n * by an arriving `Breadcrumbs` or morphing `Title`: the outgoing page's\n * trail is still mounted at that moment, so the arriving side knows one is\n * on its way out, and how long it was, and can play the depth transition —\n * hold the chevron, see the old label off, fade a separator, or fade the\n * chevron when no trail returns. `useLayoutEffect` keeps the list exact\n * within a commit: an outgoing trail's cleanup runs before an incoming\n * trail's mount effect.\n */\nconst mountedTrails: { labels: ReactNode[] }[] = [];\n\nfunction useTrailPresence(labels: ReactNode[]) {\n const entry = useRef({ labels });\n entry.current.labels = labels;\n useLayoutEffect(() => {\n const self = entry.current;\n mountedTrails.push(self);\n return () => {\n mountedTrails.splice(mountedTrails.indexOf(self), 1);\n };\n }, []);\n}\n\n/** The trail on its way out at this render, if any — snapshot at mount. */\nfunction useDepartingTrail() {\n const [departing] = useState<{ labels: ReactNode[] } | null>(() => {\n const last = mountedTrails[mountedTrails.length - 1];\n return last ? { labels: [...last.labels] } : null;\n });\n return departing;\n}\n\n/**\n * Condensing header — the page's way back once the title has scrolled away.\n * `Root condense` renders a sticky bar in the reserved top zone; `Title` and\n * `Breadcrumbs` report what belongs in it (the heading, the tail crumb)\n * through this context, so the bar assembles itself and consumers only set\n * the flag. The bar stays out of the way until the whole heading has left\n * the scrollport, then fades in pinned to the top.\n */\ninterface CondenseTail {\n label: ReactNode;\n href: string;\n onClick?: ComponentProps<\"a\">[\"onClick\"];\n}\n\ninterface CondenseRegistry {\n setTitle: (\n title: { label: ReactNode; el: HTMLElement | null } | null,\n ) => void;\n setTail: (tail: CondenseTail | null) => void;\n}\n\nconst CondenseContext = createContext<CondenseRegistry | null>(null);\n\nconst CONDENSE_BAR_ENTER = { duration: 0.2, ease: \"easeOut\" } as const;\nconst CONDENSE_BAR_RISE_PX = -8;\n\n/** Nearest scrollable ancestor — the observer root; `null` means viewport. */\nfunction findScrollParent(el: HTMLElement): Element | null {\n if (typeof getComputedStyle !== \"function\") return null;\n for (\n let node = el.parentElement;\n node != null && node !== document.body;\n node = node.parentElement\n ) {\n const { overflowY } = getComputedStyle(node);\n if (overflowY === \"auto\" || overflowY === \"scroll\") return node;\n }\n return null;\n}\n\n/**\n * A shared element can only fly between two points the user has seen. Each\n * morph word tracks whether it is on screen (keyed by `morphId`); when the\n * other end mounts, it flies only if the word it continues was visible.\n * A title scrolled out of view yields a plain fade at the destination\n * instead of a dive in from off-screen.\n */\nconst morphWordSeen = new Map<string, { visible: boolean; el: Element }>();\n\n/**\n * A flight is worth it only over a short distance. The title sits at the\n * column's left edge, the crumb in the page's top-left corner, so the\n * distance between the two ends is the column's inset from the page's\n * edge. Up to a short word's width the morph reads as one word moving\n * up; on a wide pane the column centers far from the corner, the flight\n * becomes a long streak across empty space, and the word fades across\n * instead (the same arrival it plays when the other end was never seen).\n * Measured when the flight is decided, against the page the word is\n * leaving (still mounted at that render), so a window resized since that\n * page loaded is judged as it is now, not as it was.\n */\nconst MORPH_FLIGHT_MAX_INSET = 96;\n\n/** The column's inset from the page's left edge, for a word inside a `Root`. */\nfunction columnInset(el: Element): number {\n const root = el.closest(\"[data-basic-page-root]\");\n const column = root?.querySelector(\"[data-basic-page-column]\");\n if (!root || !column) return 0;\n return (\n column.getBoundingClientRect().left - root.getBoundingClientRect().left\n );\n}\n\n/**\n * Mount-locked flight decision + live visibility tracking for a morph word.\n * `fly` is read from the registry once at mount (was the other end on\n * screen?); the ref then feeds this word's own visibility back for the next\n * navigation. No-ops without `IntersectionObserver` (jsdom, SSR).\n */\nfunction useMorphFlight(morphId: string | undefined) {\n const [fly] = useState(() => {\n if (morphId == null) return false;\n const seen = morphWordSeen.get(morphId);\n return (\n seen != null &&\n seen.visible &&\n seen.el.isConnected &&\n columnInset(seen.el) <= MORPH_FLIGHT_MAX_INSET\n );\n });\n const ref = useRef<HTMLSpanElement | null>(null);\n useEffect(() => {\n if (morphId == null || typeof IntersectionObserver === \"undefined\") return;\n const el = ref.current;\n if (!el) return;\n const observer = new IntersectionObserver(([entry]) => {\n if (entry) {\n morphWordSeen.set(morphId, { visible: entry.isIntersecting, el });\n }\n });\n observer.observe(el);\n return () => {\n observer.disconnect();\n // The other end reads the registry while rendering — before this\n // cleanup runs in the same commit — so clearing here keeps a page-swap\n // flight intact while a later, unrelated mount (the list re-entered\n // from the sidebar) starts fresh instead of trusting stale sight.\n morphWordSeen.delete(morphId);\n };\n }, [morphId]);\n return { fly, ref };\n}\n\n/** How a morph word shows up when it is not flying in. */\ntype MorphArrival = \"fade\" | \"rise\" | \"slide\";\n\nconst MORPH_ARRIVALS = {\n // Back label with nothing to fly from — a plain fade.\n fade: {\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n transition: { opacity: ENTRANCE_FADE },\n },\n // Subpage title behind a departing morph — rises from just below.\n rise: {\n initial: { opacity: 0, y: REVEAL_RISE_PX },\n animate: { opacity: 1, y: 0 },\n transition: { y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE },\n },\n // Back label on a pop between subpages — out from under the chevron.\n slide: {\n initial: { x: \"-100%\" },\n animate: { x: 0 },\n transition: { x: BACK_LABEL_ARRIVE },\n },\n} as const;\n\n/**\n * The shared-element word of a Title ↔ Back morph. While the box flies, an\n * origin-ink copy of the word sits on top and fades out (the iOS snapshot\n * crossfade); the copy only exists during a real layout animation. When the\n * flight is skipped (`fly` false — the other end wasn't on screen, or there\n * is no other end yet), the layout snap is instant and the word appears in\n * place, or plays its `arrival` instead: a fade, a rise on the entrance\n * spring (`Title`'s `enter`), or a slide out from under the back chevron.\n */\nfunction MorphLabel({\n morphId,\n fromClassName,\n fly,\n morphRef,\n arrival,\n className,\n children,\n}: {\n morphId: string;\n /** Ink the word arrives FROM (the other end's text color). */\n fromClassName: string;\n /** Fly the layout box — the other end was on screen at navigation. */\n fly: boolean;\n morphRef: React.Ref<HTMLSpanElement>;\n /** Entrance to play when not flying; omit to appear in place. */\n arrival?: MorphArrival;\n /** Extra classes on the flying span (Title's ellipsis lives here). */\n className?: string;\n children: ReactNode;\n}) {\n const [crossfading, setCrossfading] = useState(false);\n const arriving = !fly && arrival != null ? MORPH_ARRIVALS[arrival] : null;\n return (\n <motion.span\n ref={morphRef}\n layoutId={morphLayoutId(morphId)}\n initial={arriving?.initial}\n animate={arriving?.animate}\n transition={\n fly\n ? MORPH_TRANSITION\n : { layout: { duration: 0 }, ...arriving?.transition }\n }\n onLayoutAnimationStart={() => {\n if (fly) setCrossfading(true);\n }}\n onLayoutAnimationComplete={() => setCrossfading(false)}\n className={cn(\"relative inline-block\", className)}\n >\n {children}\n {crossfading && (\n <motion.span\n aria-hidden\n initial={{ opacity: 1 }}\n animate={{ opacity: 0 }}\n transition={MORPH_INK_FADE}\n // The ghost retires itself: a zero-distance \"flight\" (a crumb that\n // stays put between pages) starts a layout animation that never\n // reports completion.\n onAnimationComplete={() => setCrossfading(false)}\n className={cn(\"absolute inset-0\", fromClassName)}\n >\n {children}\n </motion.span>\n )}\n </motion.span>\n );\n}\n\nexport interface BasicPageTitleProps extends ComponentProps<\"h1\"> {\n /**\n * Shared-element key. Pair with the same `morphId` on the subpage's\n * `Back` and the word morphs between title and back link across the\n * navigation. Skipped under reduced motion.\n */\n morphId?: string;\n /**\n * Rise this title into its line on mount — for a subpage title whose line\n * an inbound Title ↔ Back morph departs from. The moment the word lifts\n * off, this title floats up from just below it (the Stack physics), so\n * the two form one upward stream and never overlap. Combines with\n * `morphId` for a mid-level page (a list that is itself a subpage): the\n * word rises in when the page is entered from its parent and flies in\n * from the back link when returned to from its own subpage. Skipped\n * under reduced motion.\n */\n enter?: boolean;\n ref?: Ref<HTMLHeadingElement>;\n}\n\n/**\n * Ellipsis for a title word that moves. A morphing word flies in from the\n * back link's line above, and an entering word rises from below the\n * baseline: both spend part of the animation outside the heading's box, so\n * the heading itself must not clip — the `overflow: hidden` that\n * `truncate` brings lives on the moving span instead. `align-top` keeps an\n * `inline-block` with hidden overflow from taking its baseline at the\n * bottom edge, which would push the line box (and everything under the\n * title) down by the descender.\n */\nconst TITLE_MOTION_LABEL = \"max-w-full min-w-0 truncate align-top\";\n\n/**\n * Page title — largest heading on the surface. Plain-text children get a slug\n * `id` for hash targets (`#profile`); the heading itself is not a link.\n * Long names ellipsize; keep trailing accessories (`Badge`, status) as\n * `shrink-0` siblings of a `min-w-0 truncate` label inside a `flex min-w-0`\n * row so they stay visible.\n */\nfunction Title({\n id,\n morphId,\n enter,\n className,\n children,\n ...props\n}: BasicPageTitleProps) {\n const headingId = resolveHeadingId(id, children);\n const reduceMotion = useReducedMotion();\n const flight = useMorphFlight(morphId);\n const departingTrail = useDepartingTrail();\n const moving = !reduceMotion && (morphId != null || enter === true);\n // How the word shows up when it is not flying in: `enter` rises it from\n // below; so does a pop (a trail on its way out) whose flight was declined\n // for distance, rather than letting the title simply appear.\n const arrival: MorphArrival | undefined =\n enter || departingTrail != null ? \"rise\" : undefined;\n // Under `Root condense`, hand the bar this heading — its words and its\n // element, so the bar knows what to say and when the heading is gone.\n const condense = useContext(CondenseContext);\n const headingRef = useRef<HTMLHeadingElement | null>(null);\n useLayoutEffect(() => {\n if (condense == null) return;\n condense.setTitle({ label: children, el: headingRef.current });\n return () => condense.setTitle(null);\n }, [condense, children]);\n // A word flying in from a trail while that trail's page leaves: if no\n // trail takes over the slot (a pop to the root), its chevron is left to\n // this title to fade out. Decided after the commit's mount effects, so a\n // page that brings its own trail (a pop between subpages) keeps the\n // chevron still instead of ghosting one under it.\n const [chevronGhost, setChevronGhost] = useState(\n flight.fly && departingTrail != null,\n );\n useLayoutEffect(() => {\n if (mountedTrails.length > 0) setChevronGhost(false);\n }, []);\n return (\n <h1\n id={headingId}\n className={cn(\n \"text-display-base text-pho-primary max-w-full min-w-0 scroll-mt-12 px-5 font-medium\",\n // A static title ellipsizes on the heading; a moving one hands the\n // clip to its span so the flight / rise is never cut off.\n moving ? \"whitespace-nowrap\" : \"truncate\",\n className,\n )}\n {...props}\n ref={(node: HTMLHeadingElement | null) => {\n headingRef.current = node;\n const forwarded = (props as { ref?: Ref<HTMLHeadingElement> }).ref;\n if (typeof forwarded === \"function\") forwarded(node);\n else if (forwarded != null) forwarded.current = node;\n }}\n >\n {morphId != null && !reduceMotion ? (\n <MorphLabel\n morphId={morphId}\n fromClassName=\"text-pho-secondary\"\n fly={flight.fly}\n morphRef={flight.ref}\n arrival={arrival}\n className={TITLE_MOTION_LABEL}\n >\n {children}\n </MorphLabel>\n ) : enter && !reduceMotion ? (\n <motion.span\n initial={{ opacity: 0, y: REVEAL_RISE_PX }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n className={cn(\"inline-block\", TITLE_MOTION_LABEL)}\n >\n {children}\n </motion.span>\n ) : (\n children\n )}\n {chevronGhost && (\n <motion.span\n aria-hidden\n initial={{ opacity: 1 }}\n animate={{ opacity: 0 }}\n transition={BACK_CHEVRON_LEAVE}\n onAnimationComplete={() => setChevronGhost(false)}\n className={cn(\n \"text-pho-secondary pointer-events-none absolute inline-flex items-center\",\n BACK_CHEVRON_GHOST_POSITION,\n )}\n >\n <IconChevronLeft />\n </motion.span>\n )}\n </h1>\n );\n}\n\n/**\n * Arrival — content that replaces a skeleton reveals on its own. `Stack`\n * watches its `aria-busy`: the render in which it flips from true to false\n * is an arrival, and the rows and items mounting in that render rise in,\n * each on its own, dividers intact. Nothing else counts as arriving: a\n * remount under a new `key`, a row the user toggled on, a page's first\n * render (the stack's entrance covers that) all appear plainly. The\n * declaration is the `aria-busy` a loading page carries anyway.\n */\nconst ArrivalContext = createContext(false);\n\nfunction useArrival() {\n const arriving = useContext(ArrivalContext);\n const reduceMotion = useReducedMotion();\n const [arrives] = useState(() => arriving && !reduceMotion);\n return arrives;\n}\n\n/**\n * Leaving — a row removed from a `Card` collapses and fades out on its own.\n * `Card` keeps departing children around until their exit has played; a\n * row knows it is leaving through presence and clips itself meanwhile.\n * Padding and the divider's border go to zero with the height, so the rows\n * below close up smoothly. Under reduced motion both moments are instant.\n */\nconst ROW_EXIT = {\n height: 0,\n opacity: 0,\n paddingTop: 0,\n paddingBottom: 0,\n borderTopWidth: 0,\n} as const;\nconst ROW_TRANSITION = {\n y: ENTRANCE_SPRING,\n opacity: ENTRANCE_FADE,\n height: ENTRANCE_SPRING,\n paddingTop: ENTRANCE_SPRING,\n paddingBottom: ENTRANCE_SPRING,\n borderTopWidth: ENTRANCE_SPRING,\n} as const;\n\nfunction useRowMotion() {\n const arrives = useArrival();\n const isPresent = useIsPresent();\n const reduceMotion = useReducedMotion();\n return {\n initial: arrives ? { opacity: 0, y: REVEAL_RISE_PX } : false,\n animate: { opacity: 1, y: 0 },\n exit: ROW_EXIT,\n transition: reduceMotion ? { duration: 0 } : ROW_TRANSITION,\n leaving: !isPresent,\n } as const;\n}\n\n/**\n * Development only: the rhythm is the system's, and a wrapper that brings\n * its own gap is the one mistake that keeps recurring. After mount, a\n * container looks at what it got and says so in the console when a block\n * is spaced by some other number. Lint catches the classes; this catches\n * what lint cannot see (a className built at runtime, a host component's\n * own wrapper). Silent where no stylesheet applies (tests, SSR).\n */\n// Guarded: the browser has no `process` global, and this runs at import.\nconst RHYTHM_CHECK =\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\nfunction useRhythmCheck(\n ref: RefObject<HTMLElement | null>,\n part: string,\n own: number,\n child: (el: Element) => number | null,\n) {\n useEffect(() => {\n if (!RHYTHM_CHECK || ref.current == null) return;\n if (typeof getComputedStyle !== \"function\") return;\n const gapOf = (el: Element) => {\n const value = getComputedStyle(el).rowGap;\n return value === \"\" || value === \"normal\" ? null : parseFloat(value);\n };\n const ownGap = gapOf(ref.current);\n if (ownGap != null && ownGap !== own) {\n console.warn(\n `[BasicPage.${part}] spaced at ${ownGap}px instead of ${own}px. Spacing is the system's: Stack gap-10 between blocks, a block gap-3, Fields gap-5. Remove the class and move the wrapper instead.`,\n ref.current,\n );\n }\n for (const el of Array.from(ref.current.children)) {\n const expected = child(el);\n if (expected == null) continue;\n if (getComputedStyle(el).display === \"contents\") continue;\n const gap = gapOf(el);\n if (gap != null && gap !== expected) {\n console.warn(\n `[BasicPage.${part}] a child is spaced at ${gap}px instead of ${expected}px. Spacing is the system's: Stack gap-10 between blocks, a block gap-3, Fields gap-5. Remove the class and move the wrapper instead.`,\n el,\n );\n }\n }\n });\n}\n\nexport interface BasicPageStackProps extends Omit<\n ComponentProps<\"div\">,\n RevealMotionConflicts\n> {\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Vertical stack under the page title. Blocks (forms / sections) use `gap-10`;\n * each block lays out its children with `gap-3`.\n *\n * Mounting plays the page entrance: the stack rises 12px and fades in on the\n * Card-shell / Command spring while `Title` / `Back` above stay put. What\n * that means per state:\n *\n * - **Entering the page** — whatever the page first shows (skeleton\n * included) rides in with its stack.\n * - **Skeleton in a separate component** — swapping it for the loaded\n * return mounts a fresh stack, so the entrance replays as the\n * data-arrival animation. That's the right feel for shapes the skeleton\n * couldn't predict (lists of unknown length).\n * - **1:1 skeleton** — keep ONE stack mounted and branch its children\n * (`{pending ? bones : content}`): values then fill in place with no\n * motion.\n *\n * Static under reduced motion.\n */\nfunction Stack({ className, children, ...props }: BasicPageStackProps) {\n const reduceMotion = useReducedMotion();\n const stackRef = useRef<HTMLDivElement | null>(null);\n // Blocks run at gap-3; a Fields sheet placed as a block runs at its own.\n useRhythmCheck(stackRef, \"Stack\", 40, (el) =>\n el.hasAttribute(\"data-basic-page-fields\") ? 20 : 12,\n );\n // The render in which `aria-busy` goes from true to false is an arrival:\n // what mounts in it reveals. Compared against the previous render, so a\n // page that never loads never arrives, and a later remount does not.\n const busy = props[\"aria-busy\"];\n const isBusy = busy === true || busy === \"true\";\n const wasBusy = useRef(isBusy);\n const arriving = wasBusy.current && !isBusy;\n useEffect(() => {\n wasBusy.current = isBusy;\n });\n return (\n <motion.div\n ref={(node: HTMLDivElement | null) => {\n stackRef.current = node;\n const forwarded = (props as { ref?: Ref<HTMLDivElement> }).ref;\n if (typeof forwarded === \"function\") forwarded(node);\n else if (forwarded != null) forwarded.current = node;\n }}\n data-basic-page-stack=\"\"\n initial={reduceMotion ? false : { opacity: 0, y: REVEAL_RISE_PX }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n className={cn(\n \"mt-6 flex min-w-0 flex-col gap-10\",\n // Each block lays out its parts at gap-3; a Fields sheet placed as a\n // block keeps its own field rhythm.\n \"*:flex *:min-w-0 *:flex-col [&>*:not([data-basic-page-fields])]:gap-3\",\n className,\n )}\n {...props}\n >\n <ArrivalContext.Provider value={arriving}>\n {children}\n </ArrivalContext.Provider>\n </motion.div>\n );\n}\n\n/**\n * Title + optional description pair. No gap between them — the block's\n * `gap-3` only applies between this header and the card.\n */\nexport interface BasicPageHeaderProps extends Omit<\n ComponentProps<\"div\">,\n RevealMotionConflicts\n> {\n /**\n * Rise this header into place on mount — the Header flavor of `Title`'s\n * `enter`, for a subpage title that carries a description: the pair\n * floats up from below the departing morph word as one block. Put `enter`\n * here and NOT on the `Title` inside. Skipped under reduced motion.\n */\n enter?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/** Title + description as one block, spaced from the card below like a title is. */\nconst BASIC_PAGE_HEADER =\n \"flex min-w-0 flex-col mb-3 [[data-basic-page-stack]>*>&]:mb-0\";\n\nfunction Header({ enter, className, ...props }: BasicPageHeaderProps) {\n const reduceMotion = useReducedMotion();\n if (enter && !reduceMotion) {\n return (\n <motion.div\n initial={{ opacity: 0, y: REVEAL_RISE_PX }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n data-basic-page-header=\"\"\n className={cn(BASIC_PAGE_HEADER, className)}\n {...props}\n />\n );\n }\n return (\n <div\n data-basic-page-header=\"\"\n className={cn(BASIC_PAGE_HEADER, className)}\n {...props}\n />\n );\n}\n\n/**\n * Section heading — same padding as the page title, smaller type. Hashable via\n * slug `id` (not a link).\n */\nfunction SectionTitle({\n id,\n className,\n children,\n ...props\n}: ComponentProps<\"h2\"> & { ref?: Ref<HTMLHeadingElement> }) {\n const headingId = resolveHeadingId(id, children);\n return (\n <h2\n id={headingId}\n className={cn(\n \"text-display-xs text-pho-primary max-w-full min-w-0 scroll-mt-12 truncate px-5 font-medium\",\n // The gap to the card is the title's own, so a wrapper between the\n // Stack and the block (a form, a Reveal) never loses it. As a Stack\n // block's direct child the block's gap-3 already spaces it; inside\n // a Header the pair's own gap does.\n \"mb-3 [[data-basic-page-header]>&]:mb-0 [[data-basic-page-stack]>*>&]:mb-0\",\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n );\n}\n\n/**\n * Supporting copy under a section title. Same display step as the title;\n * color + normal weight keep it secondary. Always wrap with `Header`.\n */\nfunction Description({\n className,\n ...props\n}: ComponentProps<\"p\"> & { ref?: Ref<HTMLParagraphElement> }) {\n return (\n <p\n className={cn(\n \"text-display-xs text-pho-description px-5 font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Optional caption below a section's `Card` (outside the card). One step\n * smaller than `Description` (`text-xs`). Not the card-internal dirty-state\n * `Footer`.\n */\nfunction SectionFooter({\n className,\n ...props\n}: ComponentProps<\"p\"> & { ref?: Ref<HTMLParagraphElement> }) {\n return (\n <p\n className={cn(\n \"text-pho-description px-5 text-xs font-normal\",\n \"mt-3 [[data-basic-page-stack]>*>&]:mt-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface BasicPageCardProps extends ComponentProps<\"div\"> {\n /**\n * Glide the card's height when its content swaps — bones becoming a\n * different number of rows, a row created or revoked, an inline state\n * change. The height follows the content on the page spring instead of\n * jumping. Reserve it for cards whose contents change while mounted.\n */\n animateHeight?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/** Bordered card that stacks rows with hairline dividers. */\nfunction Card({\n animateHeight,\n className,\n children,\n ...props\n}: BasicPageCardProps) {\n // Departing rows stay until their exit has played. `toArray` keys static\n // children by their position, so a conditional row that goes away is\n // seen as itself leaving, not as the last row; list rows bring their own\n // keys (by data id, never by index). Presence never blocks an entrance:\n // rows decide that themselves (only an arrival plays one), so bones and\n // the rows replacing them may even share a position.\n const rows = <AnimatePresence>{Children.toArray(children)}</AnimatePresence>;\n if (animateHeight) {\n return (\n <div\n className={cn(\n BASIC_PAGE_CARD_SURFACE,\n \"min-h-0 overflow-hidden\",\n className,\n )}\n {...props}\n >\n <AnimatedHeight\n transition={ENTRANCE_SPRING}\n className={BASIC_PAGE_CARD_DIVIDERS}\n >\n {rows}\n </AnimatedHeight>\n </div>\n );\n }\n return (\n <div className={cn(BASIC_PAGE_CARD, className)} {...props}>\n {rows}\n </div>\n );\n}\n\n/**\n * One card row that can host subviews. Padding matches a plain row, so use it\n * for any row that may grow an `ItemPanel` — primary content goes straight in\n * as children; the panel, when present, is the last child.\n *\n * ```tsx\n * <BasicPage.Card>\n * <BasicPage.Item>\n * …name, meta, actions…\n * <BasicPage.ItemPanel divided>…secret / expanded content…</BasicPage.ItemPanel>\n * </BasicPage.Item>\n * …later siblings (pass `divided` on the panel above)…\n * </BasicPage.Card>\n * ```\n */\nfunction Item({\n className,\n ...props\n}: Omit<ComponentProps<\"div\">, RevealMotionConflicts> & {\n ref?: Ref<HTMLDivElement>;\n}) {\n const { leaving, ...rowMotion } = useRowMotion();\n return (\n <motion.div\n {...rowMotion}\n className={cn(BASIC_PAGE_ITEM, leaving && \"overflow-hidden\", className)}\n {...props}\n />\n );\n}\n\nexport interface BasicPageItemPanelProps extends ComponentProps<\"div\"> {\n /**\n * Set when later card rows follow this item. The panel then renders as an\n * inset rounded chip (keeping the card's own divider) instead of the\n * full-bleed bottom sheet, which only reads well against the card's corner.\n * @default false\n */\n divided?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Secondary strip at the end of an `Item`. When the item closes the card,\n * it's a gray sheet flush under the body, full-bleed and owning the row's\n * bottom padding, rounding only into the card's bottom corner. Pass `divided`\n * when later card rows follow — the panel becomes an inset rounded chip and\n * the card's hairline divider stays in charge. Content is already a centered\n * flex row either way.\n */\nfunction ItemPanel({\n divided = false,\n className,\n ...props\n}: BasicPageItemPanelProps) {\n return (\n <div\n className={cn(\n divided ? BASIC_PAGE_ITEM_PANEL_DIVIDED : BASIC_PAGE_ITEM_PANEL,\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Standalone callout. Pair with `CalloutTitle` / `CalloutDescription` (and\n * optional actions) for a featured block — e.g. an invite form. Do not wrap\n * in `Card`; this is already the outer surface.\n *\n * Pass `icon` for a decorative glyph anchored to the header block (first\n * child) — typically a Tabler outline icon. The icon is aria-hidden; keep\n * meaning in the title/description.\n */\nfunction Callout({\n className,\n icon,\n children,\n ...props\n}: ComponentProps<\"div\"> & {\n ref?: Ref<HTMLDivElement>;\n /** Decorative icon, top-right of the header (first child). */\n icon?: ReactNode;\n}) {\n // Treat boolean false (and other empty values) as absent — `icon={cond &&\n // <Icon />}` is a common pattern and must not reserve header padding.\n if (icon == null || icon === false || icon === true) {\n return (\n <div className={cn(BASIC_PAGE_CALLOUT, className)} {...props}>\n {children}\n </div>\n );\n }\n\n const [header, ...rest] = Children.toArray(children);\n\n return (\n <div className={cn(BASIC_PAGE_CALLOUT, className)} {...props}>\n <div className=\"relative\">\n <div className=\"min-w-0 pr-16\">{header}</div>\n <div\n aria-hidden\n className=\"text-pho-description pointer-events-none absolute top-1/2 right-0 size-14 -translate-y-1/2 opacity-50 [&>svg]:size-full\"\n >\n {icon}\n </div>\n </div>\n {rest}\n </div>\n );\n}\n\n/** Callout heading — same type as `SectionTitle`. Hashable via slug `id`. */\nfunction CalloutTitle({\n id,\n className,\n children,\n ...props\n}: ComponentProps<\"h2\"> & { ref?: Ref<HTMLHeadingElement> }) {\n const headingId = resolveHeadingId(id, children);\n return (\n <h2\n id={headingId}\n className={cn(\n \"text-display-xs text-pho-primary max-w-full min-w-0 scroll-mt-12 truncate font-medium\",\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n );\n}\n\n/** Supporting copy under a callout title. */\nfunction CalloutDescription({\n className,\n ...props\n}: ComponentProps<\"p\"> & { ref?: Ref<HTMLParagraphElement> }) {\n return (\n <p\n className={cn(\n \"text-display-xs text-pho-description font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface BasicPageRowProps extends Omit<\n ComponentProps<\"div\">,\n \"title\" | RevealMotionConflicts\n> {\n /** Left-side field name — plain text, or compose with a trailing hint. */\n label: ReactNode;\n /** Optional helper under the label. */\n description?: ReactNode;\n /** Associates the label with a control id. When omitted, the label is not a `<label>`. */\n htmlFor?: string;\n /**\n * Stack the label above a full-width control instead of the default\n * label-left / control-right layout at `sm+`. Keeps the compact `gap-3`\n * rhythm — the default row's `justify-between` would otherwise stretch\n * label and control apart under `min-h-[4.25rem]`.\n */\n stacked?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * One row: label (+ optional description) left, control right.\n * Pass `htmlFor` when the row wraps a labelled input; omit it for display/\n * action rows (avatar, danger-zone delete). Pass `stacked` for full-width\n * controls that sit under the label.\n */\nfunction Row({\n label,\n description,\n htmlFor,\n stacked = false,\n className,\n children,\n ...props\n}: BasicPageRowProps) {\n const { leaving, ...rowMotion } = useRowMotion();\n return (\n <motion.div\n {...rowMotion}\n className={cn(\n BASIC_PAGE_ROW,\n stacked && \"sm:flex-col sm:items-stretch sm:justify-start sm:gap-3\",\n leaving && \"overflow-hidden\",\n className,\n )}\n {...props}\n >\n <div className=\"min-w-0\">\n {htmlFor ? (\n <label\n htmlFor={htmlFor}\n className=\"text-pho-primary block text-base font-normal\"\n >\n {label}\n </label>\n ) : (\n // A div, not a p: the label slot takes composed content (an\n // identity with its avatar, a loading bone) as well as a name.\n <div className=\"text-pho-primary text-base font-normal\">{label}</div>\n )}\n {description ? (\n <p className=\"text-pho-description text-xs\">{description}</p>\n ) : null}\n </div>\n <div\n className={cn(\n \"flex w-full min-w-0 items-center gap-2 sm:w-auto\",\n stacked && \"sm:w-full\",\n )}\n >\n {children}\n </div>\n </motion.div>\n );\n}\n\n/** Read-only value on the right side of a row (email, etc.). */\nfunction Value({\n className,\n ...props\n}: ComponentProps<\"p\"> & { ref?: Ref<HTMLParagraphElement> }) {\n return (\n <p\n className={cn(\n \"text-pho-description max-w-full min-w-0 truncate text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport interface BasicPageAlertProps extends Omit<\n ComponentProps<\"div\">,\n \"children\"\n> {\n /** The caught value — a problem body, an `Error` wrapping one, or unknown. */\n error?: unknown;\n /** Override the derived message. */\n children?: ReactNode;\n /**\n * Explicit presence override — defaults to whether there is anything to\n * show, so the reveal plays as the mutation's error comes and goes.\n */\n show?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Server error under a row, still inside the card — the partial failure\n * (\"Couldn't update your name\"), rendered by `Error` from the problem body.\n * Keep it mounted and pass the mutation's error: the line reveals and\n * collapses on `Footer`'s height spring + fade. The card drops its divider\n * above the line so it reads as part of the row it belongs to. Matches card\n * horizontal padding — don't re-apply `px-5`.\n *\n * For a page that failed to load outright, swap the stack for an `ErrorView`\n * instead.\n */\nfunction Alert({\n error: errorProp,\n show,\n className,\n children,\n ...props\n}: BasicPageAlertProps) {\n const reduceMotion = useReducedMotion();\n // Inside `Form`, with no `error` of its own, the alert shows the form's.\n const form = useContext(FormContext);\n const error = errorProp ?? form?.error ?? undefined;\n const hasContent = error != null || children != null;\n // Explicit `show` cannot force an empty animated slot — ErrorLine returns\n // null when there is nothing to render.\n const visible = (show ?? true) && hasContent;\n return (\n <AnimatePresence initial={false}>\n {visible ? (\n <motion.div\n data-basic-page-alert=\"\"\n className=\"overflow-hidden\"\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: \"auto\", opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={\n reduceMotion\n ? { duration: 0 }\n : { height: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }\n }\n >\n <ErrorLine\n error={error}\n className={cn(\"px-5 pb-3\", className)}\n {...props}\n >\n {children}\n </ErrorLine>\n </motion.div>\n ) : null}\n </AnimatePresence>\n );\n}\n\n/* ------------------------------- forms ---------------------------------- */\n\ninterface FormContextValue {\n pending: boolean;\n dirty: boolean;\n error: unknown;\n}\n\nconst FormContext = createContext<FormContextValue | null>(null);\n\n/** Field errors keyed by `name`, the shape Base UI `Form` maps onto fields. */\nexport type BasicPageFormErrors = Record<string, string | string[]>;\n\nexport interface BasicPageFormProps<\n Values extends Record<string, unknown> = Record<string, unknown>,\n> extends Omit<\n ComponentProps<typeof FormElement>,\n \"onFormSubmit\" | \"errors\" | \"action\"\n> {\n /**\n * The save. Receives the field values keyed by `name`, after native\n * validation passed. Resolve to finish; return `{ errors }` to put\n * messages on fields; throw (a `Problem`, an `Error`) for the form's\n * `Alert`. While it runs, every control and the submit are disabled.\n */\n action?: (\n values: Values,\n ) =>\n | void\n | { errors?: BasicPageFormErrors }\n | Promise<void | { errors?: BasicPageFormErrors }>;\n /** Field errors to start with — from a previous round trip. */\n errors?: BasicPageFormErrors;\n}\n\n/**\n * The form. A `<form>` that owns the save lifecycle so the page parts can\n * read it: `Submit` shows pending, `Footer show=\"dirty\"` appears after the\n * first edit and leaves when the action lands, `Alert` shows what the\n * action threw, and field errors the action returns land under their\n * fields. Uncontrolled by design — give fields `defaultValue` and a `name`,\n * and remount with `key` when the record changes; there is no state to\n * seed. Lay the fields out in `Fields` (the form card, its `Footer` inside\n * at the bottom), or keep a `Card` of `Row`s for a settings page that\n * saves, its `Footer` following the card one block gap below.\n *\n * The form adds no spacing. Inside a `Stack`, one form around a card and\n * its footer is one block; a form that spans several blocks goes around\n * the `Stack` instead, and the blocks keep the Stack's rhythm.\n */\nfunction Form<Values extends Record<string, unknown>>({\n action,\n errors: initialErrors,\n className,\n children,\n onChange,\n ...props\n}: BasicPageFormProps<Values>) {\n const [pending, setPending] = useState(false);\n const [dirty, setDirty] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const [errors, setErrors] = useState<BasicPageFormErrors>(\n initialErrors ?? {},\n );\n const context = useMemo(\n () => ({ pending, dirty, error }),\n [pending, dirty, error],\n );\n return (\n <FormContext.Provider value={context}>\n <FormElement\n errors={errors}\n onFormSubmit={async (values) => {\n if (action == null) return;\n setPending(true);\n setError(null);\n try {\n const result = await action(values as Values);\n const fieldErrors = result?.errors;\n if (fieldErrors != null && Object.keys(fieldErrors).length > 0) {\n setErrors(fieldErrors);\n return;\n }\n setErrors({});\n setDirty(false);\n } catch (caught) {\n setError(caught);\n } finally {\n setPending(false);\n }\n }}\n onChange={(event) => {\n setDirty(true);\n setError(null);\n // A field edited after a round trip drops the message it came back\n // with; the next submit validates it fresh.\n const name = (event.target as { name?: string }).name;\n if (name && name in errors) {\n setErrors((current) => {\n const { [name]: _dropped, ...rest } = current;\n return rest;\n });\n }\n onChange?.(event);\n }}\n // No spacing of its own. Transparent to layout, so whatever the form\n // wraps keeps the rhythm of where it sits: several blocks inside a\n // Stack stay Stack blocks, a card and its footer inside a block stay\n // that block's children. As a Stack's direct child it is one block\n // itself (a card and its footer), spaced by the Stack's block rule.\n className={cn(\n \"contents [[data-basic-page-stack]>&]:flex [[data-basic-page-stack]>&]:min-w-0 [[data-basic-page-stack]>&]:flex-col\",\n className,\n )}\n {...props}\n >\n <fieldset\n disabled={pending}\n aria-busy={pending || undefined}\n className=\"contents\"\n >\n {children}\n </fieldset>\n </FormElement>\n </FormContext.Provider>\n );\n}\n\n/** The card's field padding, matched to `Row` (`px-5 py-4`). */\nconst BASIC_PAGE_FIELDS =\n \"flex min-w-0 flex-col gap-5 p-5 [&>[data-basic-page-alert]]:-mx-5 [&>[data-basic-page-alert]]:-mt-2 [&>[data-basic-page-alert]]:-mb-5 [&>[data-basic-page-footer]]:pr-0 [&>[data-basic-page-reveal]]:flex [&>[data-basic-page-reveal]]:flex-col [&>[data-basic-page-reveal]]:gap-5\";\n\n/**\n * The form card: labelled fields stacked, label above control, one rhythm\n * (`gap-5`). Where a `Card` of `Row`s is a table of settings, this is a\n * sheet to fill in — a create page, a long edit. `Input` brings its own\n * label and hint; wrap other controls in `Field`. `Alert` and `Footer`\n * sit inside, at the bottom — unlike a `Card` of rows, a sheet keeps its\n * submit: the button's box lines up with the fields' edge.\n */\nfunction Fields({\n className,\n ...props\n}: ComponentProps<\"div\"> & { ref?: Ref<HTMLDivElement> }) {\n const fieldsRef = useRef<HTMLDivElement | null>(null);\n // Only the sheet's own rhythm: a field's internal gap is the field's.\n useRhythmCheck(fieldsRef, \"Fields\", 20, () => null);\n return (\n <div\n data-basic-page-fields=\"\"\n className={cn(BASIC_PAGE_CARD_SURFACE, BASIC_PAGE_FIELDS, className)}\n {...props}\n ref={(node: HTMLDivElement | null) => {\n fieldsRef.current = node;\n const forwarded = props.ref;\n if (typeof forwarded === \"function\") forwarded(node);\n else if (forwarded != null) forwarded.current = node;\n }}\n />\n );\n}\n\n/** Fields side by side from `sm` (a first and last name), stacked below. */\nfunction Inline({\n className,\n ...props\n}: ComponentProps<\"div\"> & { ref?: Ref<HTMLDivElement> }) {\n return (\n <div\n className={cn(\n \"flex min-w-0 flex-col gap-5 *:min-w-0 sm:flex-row sm:gap-3 sm:*:flex-1\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** The submit. A small effect `Button`, pending while the action runs. */\nfunction Submit({\n children = \"Save changes\",\n ...props\n}: Omit<ButtonProps, \"type\">) {\n const form = useContext(FormContext);\n return (\n <Button\n type=\"submit\"\n variant=\"effect\"\n size=\"sm\"\n loading={form?.pending}\n {...props}\n >\n {children}\n </Button>\n );\n}\n\nexport interface BasicPageFooterProps extends ComponentProps<\"div\"> {\n /**\n * Animated presence for the dirty-state action: the card glides\n * open/closed on a height spring while the button fades. Omit for a\n * static, always-visible footer (no animation). No reveal plays on first\n * mount — only on flips.\n */\n show?: boolean | \"dirty\";\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Save action for a card. After a `Card` of rows it sits outside, below the\n * surface, its trailing edge on the rows' text edge, so the card\n * holds only rows; inside `Fields` it sits at the bottom of the sheet.\n * Typically a submit button that appears after the form is dirty; pass\n * `show` (instead of conditional rendering) to animate it in and out\n * following the onboarding card's motion language.\n */\nfunction Footer({ show: showProp, className, ...props }: BasicPageFooterProps) {\n // `show=\"dirty\"`: inside `Form`, present once something was edited, gone\n // again once the action lands.\n const form = useContext(FormContext);\n const show = showProp === \"dirty\" ? (form?.dirty ?? false) : showProp;\n const bar = (\n <div\n data-basic-page-footer=\"\"\n // The button's trailing edge lines up with the card's text, not its\n // border: the card's 1px border and `px-5` put the text edge 21px\n // in, and the effect button's 1.5px rim is a box-shadow outside its\n // box — so the box sits 22.5px in and the rim's outer edge meets the\n // text edge.\n className={cn(\n \"flex items-center justify-end gap-3 pr-[calc(1.25rem+2.5px)]\",\n className,\n )}\n {...props}\n />\n );\n if (show === undefined) return bar;\n // A block below the card: the reveal compensates the block gap above it,\n // so the card's bottom edge does not move while the footer is away.\n // Never clipped: the button shows whole from the first frame and fades\n // in as the space below the card opens.\n return (\n <Reveal show={show} gap=\"block\" clip={false}>\n {bar}\n </Reveal>\n );\n}\n\n/**\n * DOM handlers whose React signatures clash with Motion's gesture props of\n * the same name on `motion.*` elements — excluded from `Reveal`'s public API\n * (same policy as Button).\n */\ntype RevealMotionConflicts =\n | \"onAnimationStart\"\n | \"onAnimationEnd\"\n | \"onAnimationIteration\"\n | \"onDrag\"\n | \"onDragStart\"\n | \"onDragEnd\"\n | \"onDragEnter\"\n | \"onDragExit\"\n | \"onDragLeave\"\n | \"onDragOver\"\n | \"onDrop\";\n\nexport interface BasicPageRevealProps extends Omit<\n ComponentProps<\"div\">,\n RevealMotionConflicts\n> {\n /**\n * Animated presence for a `Stack` block that comes and goes: keep the\n * block mounted and drive it with `show` — it glides open and closed\n * (height + fade) on the page spring, with the Stack's `gap-10`\n * compensated so nothing jumps when it fully collapses. Omit `show` for\n * the one-shot data-arrival entrance.\n */\n show?: boolean;\n /**\n * Clip the block while its height animates (the default). Pass `false`\n * for a block whose content must show whole from the first frame — a\n * button with a rim, a shadow — and let it fade in as the space opens.\n */\n clip?: boolean;\n /**\n * Which gap the presence variant compensates while collapsing —\n * `\"stack\"` for a Stack block (`gap-10`), `\"fields\"` for a field in a\n * `Fields` sheet (`gap-5`), `\"block\"` for an element\n * inside a block (`gap-3`). @default \"stack\"\n */\n gap?: \"stack\" | \"block\" | \"fields\";\n /**\n * Set when this wraps multiple `Card` rows — the extra element Reveal\n * needs for `AnimatePresence` sits between them and the card's own\n * `divide-y`, so the hairlines between the wrapped rows disappear unless\n * this restores them. Leave off for content that isn't a run of rows.\n */\n dividers?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Exactly one surrounding flex gap — the presence variant trades this much\n * margin against its height so neighbours glide to their final positions\n * instead of snapping by a gap when the block unmounts. `dividers` rows sit\n * in a `divide-y` card with no flex `gap` at all, so they get no\n * compensation — `gap` would otherwise overshoot into the next row's padding\n * as the block collapses.\n */\nconst GAP_COMPENSATION = {\n stack: \"-2.5rem\",\n block: \"-0.75rem\",\n fields: \"-1.25rem\",\n none: \"0px\",\n} as const;\n\n/**\n * Data-arrival entrance for regions whose shape the skeleton couldn't\n * predict — a list of unknown length, a region that depends on the data.\n * Wrap that region (keeping `Title` and 1:1 chrome outside): once the shape\n * is known it rises 12px and fades in on the Card-shell / Command spring,\n * the same physics as the `Footer` / `Alert` reveals. When the skeleton\n * mirrors the loaded layout element for element, skip the reveal — values\n * fill into a shape that never moves. The page *entrance* is separate and\n * already built into `Stack`: whatever the page first shows (including the\n * skeleton) rides that. Static under reduced motion.\n *\n * With `show`, Reveal becomes an animated-presence block instead (the\n * `Footer` grammar): a whole section of the Stack that appears or leaves at\n * runtime glides open/closed while its neighbours follow.\n */\nfunction Reveal({\n show,\n clip = true,\n gap = \"stack\",\n dividers,\n className,\n ...props\n}: BasicPageRevealProps) {\n const reduceMotion = useReducedMotion();\n // Card rows carry their own padding and a divide-y border, not a flex\n // gap — dividers always means zero gap to compensate for.\n const gapCompensation = GAP_COMPENSATION[dividers ? \"none\" : gap];\n const nodeRef = useRef<HTMLDivElement | null>(null);\n // The first render with `show` plays no animation (AnimatePresence\n // `initial={false}`); any later mount does.\n const animatesOnMount = useRef(show !== true);\n useEffect(() => {\n animatesOnMount.current = true;\n }, []);\n const clipOn = () => {\n if (clip && nodeRef.current) nodeRef.current.style.overflow = \"hidden\";\n };\n const clipOff = () => {\n if (nodeRef.current) nodeRef.current.style.overflow = \"\";\n };\n\n if (show === undefined) {\n return (\n <motion.div\n initial={reduceMotion ? false : { opacity: 0, y: REVEAL_RISE_PX }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ y: ENTRANCE_SPRING, opacity: ENTRANCE_FADE }}\n className={cn(dividers && BASIC_PAGE_CARD_DIVIDERS, className)}\n {...props}\n />\n );\n }\n\n // Clip only while the height animates. At rest the block is unclipped, so\n // a button's rim, a focus ring, or a shadow at its edge shows whole. The\n // toggle goes through the DOM: on exit AnimatePresence keeps a frozen\n // clone whose props no longer update, but its handlers still reach the\n // node. A block mounting with the animation (a later `show`) starts\n // clipped; the first render with `show` plays no animation and stays open.\n return (\n <AnimatePresence initial={false}>\n {show ? (\n <motion.div\n data-basic-page-reveal=\"\"\n ref={(node: HTMLDivElement | null) => {\n nodeRef.current = node;\n if (clip && node && animatesOnMount.current) {\n node.style.overflow = \"hidden\";\n }\n }}\n onAnimationStart={clipOn}\n onAnimationComplete={clipOff}\n initial={{\n height: 0,\n opacity: 0,\n marginTop: gapCompensation,\n }}\n animate={{ height: \"auto\", opacity: 1, marginTop: 0 }}\n exit={{ height: 0, opacity: 0, marginTop: gapCompensation }}\n transition={\n reduceMotion\n ? { duration: 0 }\n : {\n height: ENTRANCE_SPRING,\n marginTop: ENTRANCE_SPRING,\n opacity: ENTRANCE_FADE,\n }\n }\n className={cn(dividers && BASIC_PAGE_CARD_DIVIDERS, className)}\n {...props}\n />\n ) : null}\n </AnimatePresence>\n );\n}\n\n/* ------------------------------- navigation ------------------------------ */\n\n/**\n * Where the trail's chevron sits, in `Root` coordinates, for the ghost a\n * root `Title` fades out on a pop: the nav's `top-4 left-3` plus the\n * button's 8px icon-side padding, centred in the 32px control; the glyph\n * is 1.125em of the `sm` button's 14px type. Kept next to the trail's own\n * offset.\n */\nconst BACK_CHEVRON_GHOST_POSITION =\n \"top-4 left-5 h-8 text-base [&>svg]:size-[1.125em] [&>svg]:shrink-0\";\n\n/** Tailwind's `sm` — below it the trail collapses to its last crumb. */\nconst TRAIL_WIDE_QUERY = \"(min-width: 40rem)\";\n\nfunction isNarrowViewport() {\n return (\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n !window.matchMedia(TRAIL_WIDE_QUERY).matches\n );\n}\n\ninterface TrailItemContextValue {\n index: number;\n count: number;\n /** The trail on its way out at this render, if any. */\n departing: { labels: ReactNode[] } | null;\n /** Below `sm` — only the last crumb shows, with the chevron; decided at mount. */\n narrow: boolean;\n}\n\nconst TrailItemContext = createContext<TrailItemContextValue | null>(null);\n\nexport interface BasicPageBreadcrumbsProps extends ComponentProps<\"nav\"> {\n /** `Crumb`s, root-most first; the last one is the immediate parent. */\n children: ReactNode;\n}\n\n/**\n * The trail above the title — where this page sits, root-most crumb first,\n * ending with the immediate parent; the current page is the `Title` below.\n * Place inside `Root`, before `Title`. It floats in the page's top-left\n * corner instead of taking layout space, and the column reserves a 64px\n * top zone for it, so `Title` sits at the same position whether or not a\n * page has one.\n *\n * One form at every depth: `‹ parent / parent / parent` — the chevron opens\n * the trail (it is the way up), slashes separate the crumbs (they are the\n * path), one crumb or many. Below `sm` the path collapses to `‹ parent` —\n * the last crumb alone. Crumbs render through the host's `LinkProvider`.\n *\n * Four crumbs or more, the middle folds: `‹ root / … / parent / parent`,\n * with the folded pages behind the ellipsis as a menu. The trail keeps a\n * width ceiling at any depth, and the fold never touches the tail, so the\n * title morph is unaffected.\n *\n * It sits in the page's top-left corner — `top-4 left-3`, the chevron ink\n * 20px from the edge, the column gutter's width — as chrome of the pane,\n * not of the column: on a wide pane it stays at the corner while the\n * column centers. `top-4` centers the 32px buttons in the 64px reserved\n * zone; the ghost hover pills hang in the corner padding.\n *\n * Motion between pages: the tail crumb is the morph partner of the child\n * page's `Title` (pair their `morphId`s); everything before it holds still.\n * On a push the trail grows by one — a separator emerges from under the\n * arriving word; on a pop it loses its tail — the word grows back into the\n * title and the spare separator fades. Collapsed, it behaves as `Back`.\n */\nfunction Breadcrumbs({\n className,\n children,\n ...props\n}: BasicPageBreadcrumbsProps) {\n const items = Children.toArray(children).filter(isValidElement);\n const labels = items.map(\n (item) => (item.props as { children?: ReactNode }).children ?? null,\n );\n const departing = useDepartingTrail();\n useTrailPresence(labels);\n const [narrow] = useState(isNarrowViewport);\n const reduceMotion = useReducedMotion();\n const count = items.length;\n const Link = useLinkComponent();\n // Wide trails fold: first crumb, an ellipsis holding the middle, the last\n // two. The trail keeps a width ceiling at any depth, and the morph always\n // involves the tail, which the fold never touches. Collapsed (below sm)\n // the whole path is already one crumb — nothing to fold.\n const folded = !narrow && count >= TRAIL_FOLD_AT;\n // Under `Root condense`, the bar borrows the tail crumb as its way back.\n const condense = useContext(CondenseContext);\n const tailProps =\n count > 0 ? (items[count - 1]?.props as BasicPageCrumbProps) : null;\n const tailLabel = tailProps?.children ?? \"Back\";\n const tailHref = tailProps?.href;\n const tailClick = tailProps?.onClick;\n useLayoutEffect(() => {\n if (condense == null || tailHref == null) return;\n condense.setTail({ label: tailLabel, href: tailHref, onClick: tailClick });\n return () => condense.setTail(null);\n }, [condense, tailLabel, tailHref, tailClick]);\n // A pop, wide: the trail lost its tail — the separator that stood before\n // it has nothing to precede any more and fades where it was.\n const [spareSeparator, setSpareSeparator] = useState(\n !reduceMotion &&\n !narrow &&\n departing != null &&\n departing.labels.length > count,\n );\n return (\n <nav\n aria-label=\"Breadcrumb\"\n data-basic-page-back=\"\"\n className={cn(\n \"absolute top-4 left-3 flex min-w-max items-center\",\n className,\n )}\n {...props}\n >\n <ol className=\"m-0 flex list-none items-center p-0\">\n {items.map((item, index) => {\n if (folded && index > 0 && index < count - 2) return null;\n return (\n <Fragment key={item.key ?? index}>\n {folded && index === count - 2 && (\n <li className=\"m-0 flex items-center max-sm:hidden\">\n <span aria-hidden className={TRAIL_SEPARATOR}>\n {TRAIL_SEPARATOR_GLYPH}\n </span>\n <Menu.Root>\n <Menu.Trigger\n render={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Hidden pages\"\n className=\"px-2\"\n >\n {TRAIL_FOLD_GLYPH}\n </Button>\n }\n />\n <Menu.Portal>\n <Menu.Positioner align=\"start\" sideOffset={4}>\n <Menu.Popup>\n {items.slice(1, count - 2).map((hidden, i) => {\n const crumb = hidden.props as BasicPageCrumbProps;\n return (\n <Menu.LinkItem\n key={hidden.key ?? i}\n render={\n <Link\n href={crumb.href}\n onClick={crumb.onClick}\n />\n }\n >\n {crumb.children ?? \"Back\"}\n </Menu.LinkItem>\n );\n })}\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n </Menu.Root>\n </li>\n )}\n <li\n className={cn(\n \"m-0 flex items-center\",\n index < count - 1 && \"max-sm:hidden\",\n )}\n >\n <TrailItemContext.Provider\n value={{ index, count, departing, narrow }}\n >\n {item}\n </TrailItemContext.Provider>\n </li>\n </Fragment>\n );\n })}\n {spareSeparator && (\n <li aria-hidden className=\"m-0 flex items-center max-sm:hidden\">\n <motion.span\n initial={{ opacity: 1 }}\n animate={{ opacity: 0 }}\n transition={BACK_CHEVRON_LEAVE}\n onAnimationComplete={() => setSpareSeparator(false)}\n className={TRAIL_SEPARATOR}\n >\n {TRAIL_SEPARATOR_GLYPH}\n </motion.span>\n </li>\n )}\n </ol>\n </nav>\n );\n}\n\n/**\n * `/` between crumbs — description ink, tucked into the buttons' padding.\n * A slash, not a chevron: the trail opens with `‹`, and a `›` after it read\n * as two directions at once. The `‹` is the way up; the slashes are the\n * path.\n */\nconst TRAIL_SEPARATOR =\n \"text-pho-description -mx-1 inline-flex shrink-0 text-base select-none\";\nconst TRAIL_SEPARATOR_GLYPH = \"/\";\n\n/**\n * Wide trails fold at this many crumbs: the first stays (it opens the\n * trail), the middle collapses into an ellipsis menu, the last two stay\n * (where you are, and the step above). Four 160px crumbs and their slashes\n * would pass the 672px content column; the fold caps the trail's width at\n * any depth.\n */\nconst TRAIL_FOLD_AT = 4;\nconst TRAIL_FOLD_GLYPH = \"…\";\n\nexport interface BasicPageCrumbProps extends Omit<\n ButtonLinkProps,\n \"variant\" | \"size\" | \"shape\" | \"prefix\" | \"suffix\" | \"svgOnly\" | \"href\"\n> {\n /** Destination — rendered through the host's `LinkProvider`. */\n href: string;\n /** Label — name the page. @default \"Back\" */\n children?: ReactNode;\n /**\n * Shared-element key. Pair with the same `morphId` on that page's `Title`\n * and the word morphs between title and crumb across the navigation.\n * Skipped under reduced motion.\n */\n morphId?: string;\n}\n\n/**\n * One step of the trail — a small ghost `ButtonLink`. Only meaningful\n * inside `Breadcrumbs`, which decides what shows at which width and which\n * crumb is the tail; `Back` is the one-crumb shorthand.\n */\nfunction Crumb({\n href,\n className,\n morphId,\n children = \"Back\",\n ...props\n}: BasicPageCrumbProps) {\n const trail = useContext(TrailItemContext);\n const reduceMotion = useReducedMotion();\n const morphing = morphId != null && !reduceMotion;\n const flight = useMorphFlight(morphing ? morphId : undefined);\n if (trail == null) {\n throw new Error(\n \"BasicPage.Crumb must be rendered inside BasicPage.Breadcrumbs\",\n );\n }\n const { index, count, departing, narrow } = trail;\n const first = index === 0;\n const last = index === count - 1;\n const grew = departing != null && departing.labels.length < count;\n const shrank = departing != null && departing.labels.length > count;\n // Is this crumb new on screen? Wide: only a tail the trail just grew by\n // (or any tail with no trail before it — a cold mount, the first push).\n // Collapsed: the tail is always the one visible crumb, so a change of\n // trail always changes what shows.\n const newHere = last && (departing == null || grew || narrow);\n // Wide, the chevron opens the trail (first crumb); collapsed, it leads\n // the tail (the only crumb). Both, when they are the same crumb.\n const chevron = first || last;\n const chevronClass =\n first && last ? \"\" : first ? \"max-sm:hidden\" : \"sm:hidden\";\n // Between subpages the chevron is already there — it holds still. Only\n // the first push (no trail on the way out) brings it in with the word.\n const chevronHolds = departing != null;\n // How the label shows up when nothing flies in. Collapsed and a pop: out\n // from under the chevron; a crumb that was already there: no entrance.\n const arrival: MorphArrival | undefined = !last\n ? undefined\n : narrow\n ? shrank\n ? \"slide\"\n : \"fade\"\n : newHere\n ? \"fade\"\n : undefined;\n // Collapsed and a push: the old tail label leaves as the new one arrives\n // in the same slot. Wide, the old tail simply stays as the crumb before.\n const [leavingLabel, setLeavingLabel] = useState<ReactNode>(\n morphing && narrow && flight.fly && departing != null && !shrank\n ? departing.labels[departing.labels.length - 1]\n : null,\n );\n const animateChevron = morphing && chevron && !chevronHolds;\n const animateSeparator =\n morphing && !first && last && (departing == null || grew);\n\n return (\n <>\n {!first && (\n <span aria-hidden className={cn(TRAIL_SEPARATOR, \"max-sm:hidden\")}>\n {animateSeparator ? (\n <motion.span\n initial={\n flight.fly\n ? { opacity: 0, x: MORPH_CHEVRON_RISE_X }\n : { opacity: 0 }\n }\n animate={flight.fly ? { opacity: 1, x: 0 } : { opacity: 1 }}\n transition={flight.fly ? MORPH_CHEVRON_ENTER : ENTRANCE_FADE}\n className=\"inline-flex\"\n >\n {TRAIL_SEPARATOR_GLYPH}\n </motion.span>\n ) : (\n TRAIL_SEPARATOR_GLYPH\n )}\n </span>\n )}\n <ButtonLink\n variant=\"ghost\"\n size=\"sm\"\n href={href}\n prefix={\n chevron ? (\n animateChevron ? (\n // Mirrors the slot's direct-child svg sizing — the fade\n // wrapper sits between the slot and the icon.\n <motion.span\n initial={\n flight.fly\n ? { opacity: 0, x: MORPH_CHEVRON_RISE_X }\n : { opacity: 0 }\n }\n animate={flight.fly ? { opacity: 1, x: 0 } : { opacity: 1 }}\n transition={flight.fly ? MORPH_CHEVRON_ENTER : ENTRANCE_FADE}\n className={cn(\n \"inline-flex [&>svg]:size-[1.125em] [&>svg]:shrink-0\",\n chevronClass,\n )}\n >\n <IconChevronLeft />\n </motion.span>\n ) : (\n <span\n className={cn(\n \"inline-flex [&>svg]:size-[1.125em] [&>svg]:shrink-0\",\n chevronClass,\n )}\n >\n <IconChevronLeft />\n </span>\n )\n ) : (\n // An empty slot keeps every crumb on the icon-side padding, so a\n // crumb measures the same whether or not it is showing a chevron\n // — a label must not shift by 2px when it changes role.\n <span className=\"hidden\" />\n )\n }\n className={cn(\"min-w-max\", className)}\n {...props}\n >\n {morphing && morphId != null ? (\n // The word's box: unclipped while a flight is possible, clipped at\n // its left edge while the label slides out from under the chevron.\n // The departing label sits on top as its own layer so the arriving\n // word is never affected by it. A block, not an inline-block: hidden\n // overflow on an inline-block moves its baseline to the bottom edge\n // and would grow the button by the descender. Crumbs before the tail\n // ellipsize; the tail stays whole so its flight is never clipped.\n <span\n className={cn(\n \"relative block\",\n !flight.fly && arrival === \"slide\" && \"overflow-hidden\",\n !last && \"max-w-40 truncate\",\n )}\n >\n <MorphLabel\n morphId={morphId}\n fromClassName=\"text-pho-primary\"\n fly={flight.fly}\n morphRef={flight.ref}\n arrival={arrival}\n >\n {children}\n </MorphLabel>\n {leavingLabel != null && (\n <motion.span\n aria-hidden\n initial={{ x: 0, opacity: 1 }}\n animate={{ x: BACK_LABEL_LEAVE_X, opacity: 0 }}\n transition={BACK_LABEL_LEAVE}\n onAnimationComplete={() => setLeavingLabel(null)}\n className=\"pointer-events-none absolute inset-y-0 left-0 whitespace-nowrap\"\n >\n {leavingLabel}\n </motion.span>\n )}\n </span>\n ) : (\n <span className={cn(\"block\", !last && \"max-w-40 truncate\")}>\n {children}\n </span>\n )}\n </ButtonLink>\n </>\n );\n}\n\nexport type BasicPageBackProps = BasicPageCrumbProps;\n\n/**\n * Back link for a subpage one level down — the one-crumb `Breadcrumbs`:\n * `‹ parent`, floating in `Root`'s reserved top padding, morphing with the\n * parent's `Title` when they share a `morphId`. Deeper pages list the whole\n * path with `Breadcrumbs` + `Crumb` instead.\n */\nfunction Back({ className, ...props }: BasicPageBackProps) {\n return (\n <Breadcrumbs className={className}>\n <Crumb {...props} />\n </Breadcrumbs>\n );\n}\n\nexport interface BasicPageRowLinkProps extends Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n \"href\" | \"title\" | RevealMotionConflicts\n> {\n /** Left-side field name — plain text, or compose with a trailing badge. */\n label: ReactNode;\n /** Optional helper under the label. */\n description?: ReactNode;\n /** Optional media left of the label (e.g. project avatar). */\n leading?: ReactNode;\n /** Subpage destination — rendered through the host's `LinkProvider`. */\n href: string;\n /** Optional trailing value before the chevron (compose with `Value`). */\n children?: ReactNode;\n ref?: Ref<HTMLAnchorElement>;\n}\n\n/**\n * A row that navigates — the whole row is one link into a subpage, with a\n * trailing chevron cue. Always horizontal: a column stack would park the\n * chevron under the label on narrow viewports. Hover lifts the row, and\n * first/last rows follow the card's corner radius.\n */\nfunction RowLink({\n label,\n description,\n leading,\n href,\n className,\n children,\n ...props\n}: BasicPageRowLinkProps) {\n const Link = useLinkComponent();\n const MotionLink = useMemo(() => motion.create(Link), [Link]);\n const { leaving, ...rowMotion } = useRowMotion();\n return (\n <MotionLink\n href={href}\n {...rowMotion}\n {...props}\n className={cn(\n // Same padding / min-height as `BASIC_PAGE_ROW`, but never `flex-col`\n // — navigation rows keep label left and chevron right at every width.\n \"flex min-h-[4.25rem] min-w-0 flex-row items-center justify-between gap-6 px-5 py-4\",\n \"group outline-pho-brand hover:bg-pho-primary-hover cursor-pointer transition-colors focus-visible:outline-2 focus-visible:-outline-offset-2\",\n // Hover wash follows the card's rounding (minus the 1px border).\n \"first:rounded-t-[calc(var(--radius-base)-1px)] last:rounded-b-[calc(var(--radius-base)-1px)]\",\n leaving && \"overflow-hidden\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex min-w-0 flex-1 items-center\",\n leading != null && \"gap-3\",\n )}\n >\n {leading}\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 items-center gap-1\">\n {typeof label === \"string\" || typeof label === \"number\" ? (\n <p className=\"text-pho-primary truncate text-base font-medium\">\n {label}\n </p>\n ) : (\n label\n )}\n </div>\n {description ? (\n <div className=\"text-pho-description truncate text-xs\">\n {description}\n </div>\n ) : null}\n </div>\n </div>\n <div className=\"flex min-w-0 items-center justify-end gap-2\">\n {children != null ? <div className=\"min-w-0\">{children}</div> : null}\n <IconChevronRight\n aria-hidden\n className=\"text-pho-secondary group-hover:text-pho-secondary-hover size-4 shrink-0 transition-colors\"\n />\n </div>\n </MotionLink>\n );\n}\n\n/* -------------------------------- assembly ------------------------------- */\n\n/**\n * Basic page layout. One stack, one gap rhythm — only title scale differs:\n *\n * ```tsx\n * <BasicPage.Root>\n * <BasicPage.Title>Profile</BasicPage.Title>\n * <BasicPage.Stack>\n * <form>\n * <BasicPage.Card>\n * <BasicPage.Row label=\"Name\" htmlFor=\"first-name\">\n * <Input id=\"first-name\" size=\"sm\" />\n * </BasicPage.Row>\n * </BasicPage.Card>\n * </form>\n * <form>\n * <BasicPage.Header>\n * <BasicPage.SectionTitle>Agent profile</BasicPage.SectionTitle>\n * <BasicPage.Description>…</BasicPage.Description>\n * </BasicPage.Header>\n * <BasicPage.Card>…</BasicPage.Card>\n * </form>\n * <div>\n * <BasicPage.SectionTitle>Danger zone</BasicPage.SectionTitle>\n * <BasicPage.Card>\n * <BasicPage.Row label=\"Delete account\" description=\"…\">\n * <Button color=\"destructive\" size=\"sm\">Delete</Button>\n * </BasicPage.Row>\n * </BasicPage.Card>\n * </div>\n * <BasicPage.Callout icon={<IconMail stroke={1.25} />}>\n * <BasicPage.Header>\n * <BasicPage.CalloutTitle>Invitations</BasicPage.CalloutTitle>\n * <BasicPage.CalloutDescription>…</BasicPage.CalloutDescription>\n * </BasicPage.Header>\n * …invite form…\n * </BasicPage.Callout>\n * </BasicPage.Stack>\n * </BasicPage.Root>\n * ```\n *\n * Subpage — `Back` above the title, `RowLink` rows to drill in:\n *\n * ```tsx\n * <BasicPage.Root>\n * <BasicPage.Back href=\"/settings\">Settings</BasicPage.Back>\n * <BasicPage.Title>Billing</BasicPage.Title>\n * <BasicPage.Stack>\n * <div>\n * <BasicPage.Card>\n * <BasicPage.RowLink label=\"Invoices\" href=\"/settings/invoices\">\n * <BasicPage.Value>12 documents</BasicPage.Value>\n * </BasicPage.RowLink>\n * </BasicPage.Card>\n * </div>\n * </BasicPage.Stack>\n * </BasicPage.Root>\n * ```\n */\nexport const BasicPage = {\n Root,\n Breadcrumbs,\n Crumb,\n Back,\n Title,\n Stack,\n Header,\n SectionTitle,\n Description,\n SectionFooter,\n Card,\n Item,\n ItemPanel,\n Callout,\n CalloutTitle,\n CalloutDescription,\n Row,\n RowLink,\n Value,\n Alert,\n Footer,\n Form,\n Fields,\n Inline,\n Submit,\n Reveal,\n};\n"],"x_google_ignoreList":[0],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"input-CCd6XK7Z.js","names":["__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconEyeOff.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconEye.mjs","../../src/components/input/input.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.46.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M10.585 10.587a2 2 0 0 0 2.829 2.828\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M16.681 16.673a8.717 8.717 0 0 1 -4.681 1.327c-3.6 0 -6.6 -2 -9 -6c1.272 -2.12 2.712 -3.678 4.32 -4.674m2.86 -1.146a9.055 9.055 0 0 1 1.82 -.18c3.6 0 6.6 2 9 6c-.666 1.11 -1.379 2.067 -2.138 2.87\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M3 3l18 18\", \"key\": \"svg-2\" }]];\nconst IconEyeOff = createReactComponent(\"outline\", \"eye-off\", \"EyeOff\", __iconNode);\n\nexport { __iconNode, IconEyeOff as default };\n//# sourceMappingURL=IconEyeOff.mjs.map\n","/**\n * @license @tabler/icons-react v3.46.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6\", \"key\": \"svg-1\" }]];\nconst IconEye = createReactComponent(\"outline\", \"eye\", \"Eye\", __iconNode);\n\nexport { __iconNode, IconEye as default };\n//# sourceMappingURL=IconEye.mjs.map\n","import {\n useState,\n type ComponentType,\n type InputHTMLAttributes,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport {\n IconAlertCircleFilled,\n IconEye,\n IconEyeOff,\n} from \"@tabler/icons-react\";\nimport { Field } from \"@base-ui/react/field\";\nimport { cn } from \"../../utils/cn\";\n\nexport type InputSize = \"sm\" | \"md\" | \"lg\";\n\n// Control padding per size. The wrapper carries a 2px inset (`p-0.5`) so the\n// control's border box — and the browser's autofill fill it paints — sits\n// inside the ring instead of over it; these paddings are the documented\n// effective padding (sm/md 12/8px, lg 14/10px) minus that 2px inset, so the\n// text position and total field height are unchanged.\nconst SIZE_PAD: Record<InputSize, string> = {\n // 16px on small viewports — iOS zooms into any focused field under 16px.\n sm: \"px-2.5 py-1.5 text-md md:text-base\",\n md: \"px-2.5 py-1.5 text-md\",\n lg: \"px-3 py-2 text-md\",\n};\n// Effective icon clearance minus the wrapper's 2px inset.\nconst LEADING_PAD: Record<InputSize, string> = {\n sm: \"pl-8.5\",\n md: \"pl-9.5\",\n lg: \"pl-10\",\n};\n// Icons are absolutely positioned, so they're placed from the wrapper's\n// padding edge — which, with no border, is the visible field edge; the\n// wrapper's `p-0.5` does not offset them.\nconst LEADING_ICON_POS: Record<InputSize, string> = {\n sm: \"left-3 size-4\",\n md: \"left-3 size-5\",\n lg: \"left-3.5 size-5\",\n};\n// Wrapper corner radius — `rounded-base` (12px) at every size; `lg` also gets\n// `squircle` superellipse smoothing (the ring is a box-shadow on this wrapper,\n// so it follows the border-radius automatically).\nconst SIZE_RADIUS: Record<InputSize, string> = {\n sm: \"rounded-base\",\n md: \"rounded-base\",\n lg: \"squircle rounded-base\",\n};\n// Concentric inner-curve cover, `lg` only. Nested corner radii must follow\n// innerRadius = outerRadius − inset, so the hairline's inner edge at a 12px\n// outer radius is 11px at rest (ring-1) and 10px when focused (ring-2).\n// Browsers derive that automatically for plain round corners, but with\n// `corner-shape: superellipse(...)` shipping engines still scale (rather than\n// offset) the inner shadow curve, which renders the ring visibly thicker at\n// the four corners (see w3c/csswg-drafts#12961). This ::before repaints the\n// field surface over everything inside the correct concentric curve — a round\n// radius is the right parallel-offset approximation of the mild superellipse —\n// so the ring reads as a uniform hairline in every engine. `isolate` +\n// `-z-10` slot the cover above the wrapper's background/ring but below the\n// control's text, icons, and autofill fill. `sm`/`md` have no corner-shape,\n// so the native (already concentric) rendering is kept there.\n// The ::before is absolutely positioned, so its inset is measured from the\n// wrapper's border box (border 0): 1px in at rest, 2px in when focused.\nconst SIZE_RING_COVER: Record<InputSize, string> = {\n sm: \"\",\n md: \"\",\n lg: cn(\n \"isolate before:pointer-events-none before:absolute before:-z-10 before:content-['']\",\n \"before:bg-pho-primary before:inset-px before:rounded-[calc(var(--radius-base)-1px)]\",\n // Invalid sits between rest (1px) and focus (2px) — keep the cover concentric.\n \"data-[invalid]:before:inset-[1.5px] data-[invalid]:before:rounded-[calc(var(--radius-base)-1.5px)]\",\n \"has-[input:focus-visible]:before:inset-0.5 has-[input:focus-visible]:before:rounded-[calc(var(--radius-base)-2px)]\",\n \"before:transition-[inset,border-radius] before:duration-100 before:ease-linear\",\n ),\n};\n// The control's border box sits 2px inside the wrapper (its `p-0.5` inset),\n// clear of both ring widths, so the browser's autofill fill paints inside the\n// hairline instead of over it. Rounding follows inner = outer − gap, derived\n// from the token with calc. Round (not squircle) — the parallel offset of\n// the wrapper's mild superellipse is effectively circular.\nconst SIZE_AUTOFILL_RADIUS: Record<InputSize, string> = {\n sm: \"autofill:rounded-[calc(var(--radius-base)-2px)]\",\n md: \"autofill:rounded-[calc(var(--radius-base)-2px)]\",\n lg: \"autofill:rounded-[calc(var(--radius-base)-2px)]\",\n};\n\nexport interface InputProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"size\"\n> {\n /** Field label (associated for accessibility). */\n label?: ReactNode;\n /** Helper text below the field; rendered in the error color when `invalid`. */\n hint?: ReactNode;\n /** Size variant. @default \"md\" */\n size?: InputSize;\n /** Render the invalid state (ring + icon + error-colored hint). */\n invalid?: boolean;\n /** Leading icon component (e.g. a Tabler icon). */\n icon?: ComponentType<{ className?: string }>;\n /** Node rendered at the right edge of the label row (e.g. \"Forgot?\"). */\n labelTrailing?: ReactNode;\n /** Class applied to the input wrapper. */\n wrapperClassName?: string;\n ref?: Ref<HTMLInputElement>;\n}\n\n/**\n * Text input built on Base UI `Field` (label/description a11y wiring) with\n * Pho's bordered surface, leading icon, invalid state, and a built-in password\n * reveal toggle.\n */\nexport function Input({\n label,\n hint,\n size = \"md\",\n invalid,\n icon: Icon,\n labelTrailing,\n disabled,\n required,\n type = \"text\",\n className,\n wrapperClassName,\n id,\n ref,\n ...props\n}: InputProps) {\n const [reveal, setReveal] = useState(false);\n const isPassword = type === \"password\";\n const resolvedType = isPassword && reveal ? \"text\" : type;\n const hasLeadingIcon = Boolean(Icon);\n const hasTrailingIcon = isPassword || invalid;\n\n return (\n <Field.Root\n disabled={disabled}\n className=\"group/field flex w-full flex-col gap-1.5\"\n >\n {label && (\n <div className=\"flex items-center justify-between gap-2\">\n <Field.Label className=\"text-pho-secondary flex cursor-default items-center gap-0.5 text-base font-medium\">\n {label}\n {required && <span className=\"text-pho-brand\">*</span>}\n </Field.Label>\n {labelTrailing}\n </div>\n )}\n\n <div\n data-invalid={invalid || undefined}\n className={cn(\n // Flat field surface — hairline ring only; elevation shadows are\n // reserved for floating layers (menus/popovers/dialogs). `p-0.5`\n // insets the control 2px (the focused ring width) so its background\n // and the browser's autofill fill nest inside the ring; the size\n // maps compensate so effective padding/height are unchanged.\n \"bg-pho-primary ring-pho-primary relative flex w-full items-center p-0.5 ring-1 transition-shadow duration-100 ease-linear ring-inset\",\n SIZE_RADIUS[size],\n SIZE_RING_COVER[size],\n \"has-[input:focus-visible]:ring-pho-brand has-[input:focus-visible]:ring-2\",\n // Invalid is mid-weight: thicker than the 1px rest hairline, thinner\n // than the 2px focus ring. Rest uses the subtle error ink; focus\n // steps up to the solid error (same hue, full opacity).\n \"data-[invalid]:ring-pho-error-subtle data-[invalid]:has-[input:focus-visible]:ring-pho-error data-[invalid]:ring-[1.5px]\",\n \"group-data-[disabled]/field:cursor-not-allowed group-data-[disabled]/field:opacity-50\",\n wrapperClassName,\n )}\n >\n {Icon && (\n <Icon\n className={cn(\n \"text-pho-secondary pointer-events-none absolute\",\n LEADING_ICON_POS[size],\n )}\n />\n )}\n\n <Field.Control\n ref={ref}\n id={id}\n type={resolvedType}\n required={required}\n {...props}\n className={cn(\n \"text-pho-primary placeholder:text-pho-placeholder m-0 w-full bg-transparent outline-none disabled:cursor-not-allowed\",\n SIZE_PAD[size],\n SIZE_AUTOFILL_RADIUS[size],\n hasLeadingIcon && LEADING_PAD[size],\n // 34px + the wrapper's 2px inset = the previous 36px clearance.\n hasTrailingIcon && \"pr-8.5\",\n className,\n )}\n />\n\n {invalid && !isPassword && (\n <IconAlertCircleFilled className=\"text-pho-error pointer-events-none absolute right-3 size-4\" />\n )}\n\n {isPassword && (\n <button\n type=\"button\"\n // Reachable by click but skipped in tab order so Tab moves field→field.\n tabIndex={-1}\n aria-label=\"Toggle password visibility\"\n onClick={() => setReveal((v) => !v)}\n className=\"text-pho-secondary hover:text-pho-secondary-hover absolute right-3 flex cursor-pointer items-center transition duration-100 ease-linear focus:outline-none\"\n >\n {reveal ? (\n <IconEyeOff className=\"size-4\" />\n ) : (\n <IconEye className=\"size-4\" />\n )}\n </button>\n )}\n </div>\n\n {hint && (\n <Field.Description\n className={cn(\n \"text-pho-description text-base\",\n invalid && \"text-pho-error\",\n )}\n >\n {hint}\n </Field.Description>\n )}\n {/* Validation and server errors routed here by Field / Form. */}\n <Field.Error className=\"text-pho-error text-base\" />\n </Field.Root>\n );\n}\n\nInput.displayName = \"Input\";\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"input-group-5AtpIhC_.js","names":[],"sources":["../../src/components/input-group/input-group.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n type ComponentProps,\n type ElementType,\n type HTMLAttributes,\n type InputHTMLAttributes,\n type PointerEvent,\n type Ref,\n} from \"react\";\nimport { Field } from \"@base-ui/react/field\";\nimport { Separator as BaseSeparator } from \"@base-ui/react/separator\";\nimport { cn } from \"../../utils/cn\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\nexport type InputGroupSize = \"sm\" | \"md\" | \"lg\";\n\n/** Lets `Addon` and the control read the Root's size/invalid state. */\nconst InputGroupContext = createContext<{\n size: InputGroupSize;\n invalid: boolean;\n}>({ size: \"md\", invalid: false });\n\n// Mirrors Input's size math (see input.tsx): the group surface carries the\n// horizontal padding and text scale, the control carries the vertical\n// padding. Effective metrics — sm/md 12/8px, lg 14/10px — land the same\n// 36/40/44px field heights, so grouped and plain inputs align in a form.\nconst SIZE_ROOT: Record<InputGroupSize, string> = {\n // 16px on small viewports — iOS zooms into any focused field under 16px.\n sm: \"gap-2 px-3 text-md md:text-base\",\n md: \"gap-2 px-3 text-md\",\n lg: \"gap-2 px-3.5 text-md\",\n};\n// `my-0.5` insets the control 2px (the focused ring width) so the browser's\n// autofill fill nests inside the ring; `py` makes up the rest of the height.\nconst SIZE_CONTROL: Record<InputGroupSize, string> = {\n sm: \"my-0.5 py-1.5\",\n md: \"my-0.5 py-1.5\",\n lg: \"my-0.5 py-2\",\n};\n// In-field icon size per group size — same scale as Input's leading icon.\nconst SIZE_ADDON_ICON: Record<InputGroupSize, string> = {\n sm: \"[&_svg]:size-4\",\n md: \"[&_svg]:size-5\",\n lg: \"[&_svg]:size-5\",\n};\n// `lg` gets the squircle treatment like Input; sm/md stay plain round.\nconst SIZE_RADIUS: Record<InputGroupSize, string> = {\n sm: \"rounded-base\",\n md: \"rounded-base\",\n lg: \"squircle rounded-base\",\n};\n// Concentric inner-curve cover for the `lg` squircle — same engine workaround\n// as Input (see input.tsx `SIZE_RING_COVER` for the full story).\nconst SIZE_RING_COVER: Record<InputGroupSize, string> = {\n sm: \"\",\n md: \"\",\n lg: cn(\n \"isolate before:pointer-events-none before:absolute before:-z-10 before:content-['']\",\n \"before:bg-pho-primary before:inset-px before:rounded-[calc(var(--radius-base)-1px)]\",\n // Invalid sits between rest (1px) and focus (2px) — keep the cover concentric.\n \"data-[invalid]:before:inset-[1.5px] data-[invalid]:before:rounded-[calc(var(--radius-base)-1.5px)]\",\n \"has-[:focus-visible]:before:inset-0.5 has-[:focus-visible]:before:rounded-[calc(var(--radius-base)-2px)]\",\n \"before:transition-[inset,border-radius] before:duration-100 before:ease-linear\",\n ),\n};\n\nexport interface InputGroupRootProps extends HTMLAttributes<HTMLDivElement> {\n /** Size variant, matching Input's scale. @default \"md\" */\n size?: InputGroupSize;\n /** Render the invalid state (error ring; `aria-invalid` on the control). */\n invalid?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * The shared field surface: one hairline ring around the control and its\n * addons, with the same focus / invalid / disabled treatment as `Input`.\n * Clicking anywhere on the surface (addon text, icons, blank space) focuses\n * the control, so the whole group reads as a single field.\n */\nfunction Root({\n size = \"md\",\n invalid,\n className,\n onPointerDown,\n ref,\n ...props\n}: InputGroupRootProps) {\n const handlePointerDown = (event: PointerEvent<HTMLDivElement>) => {\n onPointerDown?.(event);\n if (event.defaultPrevented) return;\n // Interactive children keep their own pointer behavior (and the control\n // itself keeps native caret placement).\n const target = event.target as HTMLElement;\n if (target.closest(\"input, button, a, select, textarea, label\")) return;\n const input = event.currentTarget.querySelector(\"input\");\n if (!input || input.disabled) return;\n // Focus the control instead of the wrapper — and don't blur it again.\n event.preventDefault();\n input.focus();\n };\n\n return (\n <InputGroupContext.Provider value={{ size, invalid: Boolean(invalid) }}>\n <div\n ref={ref}\n data-invalid={invalid || undefined}\n onPointerDown={handlePointerDown}\n className={cn(\n // Flat field surface — hairline ring only, same as Input; elevation\n // shadows are reserved for floating layers.\n \"bg-pho-primary ring-pho-primary relative flex w-full cursor-text items-center ring-1 transition-shadow duration-100 ease-linear ring-inset\",\n SIZE_ROOT[size],\n SIZE_RADIUS[size],\n SIZE_RING_COVER[size],\n // Any focusable child (input, a Select trigger, an addon button)\n // lights the shared ring — including an open Select popup.\n \"has-[:focus-visible]:ring-pho-brand has-[:focus-visible]:ring-2\",\n \"has-[button[data-popup-open]]:ring-pho-brand has-[button[data-popup-open]]:ring-2\",\n // Invalid is mid-weight: thicker than the 1px rest hairline, thinner\n // than the 2px focus / open ring. Rest uses the subtle error ink;\n // focus / open steps up to the solid error.\n \"data-[invalid]:ring-pho-error-subtle data-[invalid]:has-[:focus-visible]:ring-pho-error data-[invalid]:has-[button[data-popup-open]]:ring-pho-error data-[invalid]:ring-[1.5px]\",\n \"has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50\",\n className,\n )}\n {...props}\n />\n </InputGroupContext.Provider>\n );\n}\n\nexport interface InputGroupInputProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"size\"\n> {\n ref?: Ref<HTMLInputElement>;\n}\n\n/**\n * The text control. Rendered as Base UI `Field.Control`, so inside a\n * `Field.Root` it picks up the label and description wiring automatically;\n * standalone it behaves as a plain `<input>` (pass `aria-label` then).\n */\nfunction GroupInput({ className, ref, ...props }: InputGroupInputProps) {\n const { size, invalid } = useContext(InputGroupContext);\n return (\n <Field.Control\n ref={ref}\n aria-invalid={invalid || undefined}\n {...props}\n className={cn(\n \"text-pho-primary placeholder:text-pho-placeholder m-0 w-full min-w-0 flex-1 bg-transparent outline-none disabled:cursor-not-allowed\",\n // Rounding for the autofill fill nested 2px inside the ring.\n \"autofill:rounded-[calc(var(--radius-base)-2px)]\",\n SIZE_CONTROL[size],\n className,\n )}\n />\n );\n}\n\n/**\n * Inline content beside the control — prefix/suffix text, an icon, a `Kbd`\n * hint, or a small button. Text and icons render in the secondary tone so the\n * value stays the loudest thing on the surface.\n */\nfunction Addon({\n className,\n ref,\n ...props\n}: HTMLAttributes<HTMLDivElement> & { ref?: Ref<HTMLDivElement> }) {\n const { size } = useContext(InputGroupContext);\n return (\n <div\n ref={ref}\n className={cn(\n \"text-pho-secondary flex shrink-0 items-center gap-1 select-none\",\n \"[&_svg]:shrink-0\",\n SIZE_ADDON_ICON[size],\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * A hairline between segments — turns an addon into a boxed section\n * (`https:// │ workspace │ .photon.dev`).\n */\nfunction GroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: StyledProps<typeof BaseSeparator>) {\n return (\n <BaseSeparator\n orientation={orientation}\n className={cn(\n // `my-0.5` keeps the line 2px clear of the ring (children paint over\n // the inset box-shadow, so a full-bleed line would notch it) — the\n // same inset the control itself uses, covering the focused 2px ring.\n \"my-0.5 w-px shrink-0 self-stretch bg-[var(--border-color-pho-secondary)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Input Group — one field surface shared by a text control and its addons:\n * prefix/suffix text, icons, keyboard hints, or a trailing button. Same\n * ring, sizes, and focus / invalid / disabled behavior as `Input`, so grouped\n * and plain fields align in the same form. For a leading icon alone, plain\n * `Input` with `icon` is enough.\n */\nexport const InputGroup = {\n Root,\n Input: GroupInput,\n Addon,\n Separator: GroupSeparator,\n};\n"],"mappings":";;;;;;AAyBA,IAAM,IAAoB,EAGvB;AAAA,EAAE,MAAM;AAAA,EAAM,SAAS;AAAM,CAAC,GAM3B,IAA4C;AAAA,EAEhD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAGM,IAA+C;AAAA,EACnD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAEM,IAAkD;AAAA,EACtD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAEM,IAA8C;AAAA,EAClD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAGM,IAAkD;AAAA,EACtD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI,EACF,uFACA,uFAEA,sGACA,4GACA,gFACF;AACF;AAgBA,SAAS,EAAK,EACZ,MAAA,IAAO,MACP,SAAA,GACA,WAAA,GACA,eAAA,GACA,KAAA,GACA,GAAG,EAAA,GACmB;AACtB,QAAM,IAAA,CAAqB,MAAwC;AAMjE,QALA,IAAgB,CAAK,GACjB,EAAM,oBAGK,EAAM,OACV,QAAQ,2CAA2C,EAAG;AACjE,UAAM,IAAQ,EAAM,cAAc,cAAc,OAAO;AACvD,IAAI,CAAC,KAAS,EAAM,aAEpB,EAAM,eAAe,GACrB,EAAM,MAAM;AAAA,EACd;AAEA,SACE,gBAAA,EAAC,EAAkB,UAAnB;AAAA,IAA4B,OAAO;AAAA,MAAE,MAAA;AAAA,MAAM,SAAS,EAAQ;AAAA,IAAS;AAAA,IACnE,UAAA,gBAAA,EAAC,OAAD;AAAA,MACO,KAAA;AAAA,MACL,gBAAc,KAAW;AAAA,MACzB,eAAe;AAAA,MACf,WAAW,EAGT,8IACA,EAAU,CAAA,GACV,EAAY,CAAA,GACZ,EAAgB,CAAA,GAGhB,mEACA,qFAIA,mLACA,2EACA,CACF;AAAA,MACA,GAAI;AAAA,IACL,CAAA;AAAA,EACyB,CAAA;AAEhC;AAcA,SAAS,EAAW,EAAE,WAAA,GAAW,KAAA,GAAK,GAAG,EAAA,GAA+B;AACtE,QAAM,EAAE,MAAA,GAAM,SAAA,EAAA,IAAY,EAAW,CAAiB;AACtD,SACE,gBAAA,EAAC,EAAM,SAAP;AAAA,IACO,KAAA;AAAA,IACL,gBAAc,KAAW;AAAA,IACzB,GAAI;AAAA,IACJ,WAAW,EACT,uIAEA,mDACA,EAAa,CAAA,GACb,CACF;AAAA,EACD,CAAA;AAEL;AAOA,SAAS,EAAM,EACb,WAAA,GACA,KAAA,GACA,GAAG,EAAA,GAC8D;AACjE,QAAM,EAAE,MAAA,EAAA,IAAS,EAAW,CAAiB;AAC7C,SACE,gBAAA,EAAC,OAAD;AAAA,IACO,KAAA;AAAA,IACL,WAAW,EACT,mEACA,oBACA,EAAgB,CAAA,GAChB,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAMA,SAAS,EAAe,EACtB,WAAA,GACA,aAAA,IAAc,YACd,GAAG,EAAA,GACiC;AACpC,SACE,gBAAA,EAAC,GAAD;AAAA,IACe,aAAA;AAAA,IACb,WAAW,EAIT,4EACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AASA,IAAa,IAAa;AAAA,EACxB,MAAA;AAAA,EACA,OAAO;AAAA,EACP,OAAA;AAAA,EACA,WAAW;AACb"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"scroll-area-DkZHKfqH.js","names":[],"sources":["../../src/components/scroll-area/scroll-area-edges.tsx","../../src/components/scroll-area/scroll-area.tsx"],"sourcesContent":["import { type Ref } from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Overlay strip height — a short ramp, not a banner. `h-8` = 32px. */\nexport const EDGE_CLASS = \"pointer-events-none absolute inset-x-0 z-10 h-8\";\nexport const EDGE_REVEAL_PX = 32;\n\nconst BLUR_LAYER_COUNT = 8;\nconst BLUR_MAX_PX = 1;\n\nfunction buildBlurLayers(count: number, maxPx: number) {\n const segment = 100 / (count + 1);\n return Array.from({ length: count }, (_, i) => ({\n blurPx: (i / (count - 1)) * maxPx,\n window: [\n i * segment,\n (i + 1) * segment,\n (i + 2) * segment,\n (i + 3) * segment,\n ] as const,\n })).filter((layer) => layer.blurPx > 0);\n}\n\nconst BLUR_LAYERS = buildBlurLayers(BLUR_LAYER_COUNT, BLUR_MAX_PX);\n\nfunction edgeMask(edge: \"top\" | \"bottom\", window: readonly number[]) {\n const toEdge = edge === \"top\" ? \"to top\" : \"to bottom\";\n const [a, b, c, d] = window;\n return `linear-gradient(${toEdge}, transparent ${a}%, black ${b}%, black ${c}%, transparent ${d}%)`;\n}\n\nconst DEFAULT_SURFACE = \"var(--background-color-pho-primary)\";\n\nfunction washGradient(edge: \"top\" | \"bottom\", surface: string) {\n const to = edge === \"top\" ? \"to top\" : \"to bottom\";\n return `linear-gradient(${to}, color-mix(in oklab, ${surface} 20%, transparent) 0%, ${surface} 100%)`;\n}\n\nexport function paintEdge(node: HTMLDivElement | null, progress: number) {\n if (!node) return;\n for (const child of node.children) {\n const el = child as HTMLElement;\n if (el.dataset.scrollFade === \"wash\") {\n el.style.opacity = String(progress);\n continue;\n }\n const blur = `blur(${Number(el.dataset.blurPx) * progress}px)`;\n el.style.backdropFilter = blur;\n el.style.setProperty(\"-webkit-backdrop-filter\", blur);\n }\n}\n\nexport function Edge({\n edge,\n edgeRef,\n surface = DEFAULT_SURFACE,\n className,\n}: {\n edge: \"top\" | \"bottom\";\n edgeRef: Ref<HTMLDivElement>;\n /** The surface the wash fades into — the card by default, or a page. */\n surface?: string;\n /** Position override — the strip sits at the named edge unless placed. */\n className?: string;\n}) {\n return (\n <div\n ref={edgeRef}\n aria-hidden\n data-edge={edge}\n className={cn(\n EDGE_CLASS,\n className ?? (edge === \"top\" ? \"top-0\" : \"bottom-0\"),\n )}\n >\n {BLUR_LAYERS.map(({ blurPx, window }, index) => {\n const mask = edgeMask(edge, window);\n return (\n <div\n key={index}\n data-blur-px={blurPx}\n className=\"absolute inset-0\"\n style={{\n maskImage: mask,\n WebkitMaskImage: mask,\n }}\n />\n );\n })}\n <div\n data-scroll-fade=\"wash\"\n className=\"absolute inset-0 opacity-0\"\n style={{ background: washGradient(edge, surface) }}\n />\n </div>\n );\n}\n","import {\n createContext,\n useContext,\n useLayoutEffect,\n useRef,\n type ComponentProps,\n type ElementType,\n type Ref,\n type RefObject,\n} from \"react\";\nimport { ScrollArea as BaseScrollArea } from \"@base-ui/react/scroll-area\";\nimport { cn } from \"../../utils/cn\";\nimport { Edge, EDGE_REVEAL_PX, paintEdge } from \"./scroll-area-edges\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\nconst ScrollAreaContext = createContext<{\n topEl: RefObject<HTMLDivElement | null>;\n bottomEl: RefObject<HTMLDivElement | null>;\n} | null>(null);\n\nfunction useScrollAreaContext() {\n const ctx = useContext(ScrollAreaContext);\n if (ctx == null) {\n throw new Error(\"ScrollArea parts must be used inside ScrollArea.Root\");\n }\n return ctx;\n}\n\nfunction clamp01(n: number) {\n if (n <= 0) return 0;\n if (n >= 1) return 1;\n return n;\n}\n\nfunction assignRef<T>(ref: Ref<T> | undefined, node: T | null) {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref) {\n // React 18 types `RefObject.current` as readonly; the write is legal.\n (ref as { current: T | null }).current = node;\n }\n}\n\nconst Content = BaseScrollArea.Content;\nconst Corner = BaseScrollArea.Corner;\n\nfunction Root({\n className,\n children,\n ...props\n}: StyledProps<typeof BaseScrollArea.Root>) {\n const topEl = useRef<HTMLDivElement | null>(null);\n const bottomEl = useRef<HTMLDivElement | null>(null);\n\n return (\n <BaseScrollArea.Root\n className={cn(\"relative overflow-hidden\", className)}\n {...props}\n >\n <ScrollAreaContext.Provider value={{ topEl, bottomEl }}>\n {children}\n <Edge edge=\"top\" edgeRef={topEl} />\n <Edge edge=\"bottom\" edgeRef={bottomEl} />\n </ScrollAreaContext.Provider>\n </BaseScrollArea.Root>\n );\n}\n\nfunction Viewport({\n className,\n ref,\n ...props\n}: StyledProps<typeof BaseScrollArea.Viewport>) {\n const { topEl, bottomEl } = useScrollAreaContext();\n const viewportRef = useRef<HTMLElement | null>(null);\n\n useLayoutEffect(() => {\n const viewport = viewportRef.current;\n if (!viewport) return;\n\n const paint = () => {\n const reveal =\n topEl.current?.offsetHeight ||\n bottomEl.current?.offsetHeight ||\n EDGE_REVEAL_PX;\n const maxScroll = viewport.scrollHeight - viewport.clientHeight;\n const top = maxScroll <= 0 ? 0 : clamp01(viewport.scrollTop / reveal);\n const bottom =\n maxScroll <= 0 ? 0 : clamp01((maxScroll - viewport.scrollTop) / reveal);\n paintEdge(topEl.current, top);\n paintEdge(bottomEl.current, bottom);\n };\n\n let frame = 0;\n const onScroll = () => {\n if (frame) return;\n frame = requestAnimationFrame(() => {\n frame = 0;\n paint();\n });\n };\n\n paint();\n viewport.addEventListener(\"scroll\", onScroll, { passive: true });\n let observer: ResizeObserver | null = null;\n if (typeof ResizeObserver !== \"undefined\") {\n observer = new ResizeObserver(paint);\n observer.observe(viewport);\n if (viewport.firstElementChild) {\n observer.observe(viewport.firstElementChild);\n }\n }\n return () => {\n viewport.removeEventListener(\"scroll\", onScroll);\n if (frame) cancelAnimationFrame(frame);\n observer?.disconnect();\n };\n }, [topEl, bottomEl]);\n\n return (\n <BaseScrollArea.Viewport\n className={cn(\n \"outline-pho-brand h-full min-h-0 w-full overscroll-contain rounded-[inherit] focus-visible:outline-2 focus-visible:-outline-offset-1\",\n className,\n )}\n {...props}\n ref={(node) => {\n viewportRef.current = node;\n assignRef(ref, node);\n }}\n />\n );\n}\n\nfunction Scrollbar({\n className,\n ...props\n}: StyledProps<typeof BaseScrollArea.Scrollbar>) {\n return (\n <BaseScrollArea.Scrollbar\n className={cn(\n \"relative z-20 flex touch-none p-0.5 opacity-0 transition-opacity delay-300 select-none\",\n \"data-[hovering]:opacity-100 data-[hovering]:delay-0 data-[scrolling]:opacity-100 data-[scrolling]:delay-0 data-[scrolling]:duration-0\",\n \"data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=vertical]:w-2.5\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Thumb({\n className,\n ...props\n}: StyledProps<typeof BaseScrollArea.Thumb>) {\n return (\n <BaseScrollArea.Thumb\n className={cn(\n \"flex-1 rounded-full bg-[var(--border-color-pho-primary)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Scroll area built on Base UI `ScrollArea` — a capped region with overlay\n * scrollbars and progressive edge fade. Approaching rows blur (0 → 1px) and\n * wash into the surface; strength tracks scroll distance over one strip\n * height. Give `Root` a fixed size; put content in `Viewport` → `Content`\n * and add a `Scrollbar` → `Thumb` per axis.\n */\nexport const ScrollArea = {\n Root,\n Viewport,\n Content,\n Scrollbar,\n Thumb,\n Corner,\n};\n"],"mappings":"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"}
@@ -1,186 +0,0 @@
1
- "use client";
2
- import { t as a } from "./cn-ChIgwEl3.js";
3
- import { n as I, r as N } from "./link-provider-9TFNyDqO.js";
4
- import { u as E } from "./button-DNNs5RsT.js";
5
- import { t as R } from "./createReactComponent-BqCmnqfX.js";
6
- import { t as _ } from "./IconArrowUpRight-DGgKzQwV.js";
7
- import { n as l } from "./avatar-BkmGDIqf.js";
8
- import { createContext as A, isValidElement as S, useContext as T, useMemo as k } from "react";
9
- import { Fragment as w, jsx as t, jsxs as n } from "react/jsx-runtime";
10
- import { motion as c } from "motion/react";
11
- var C = [
12
- ["path", {
13
- d: "M4 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",
14
- key: "svg-0"
15
- }],
16
- ["path", {
17
- d: "M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",
18
- key: "svg-1"
19
- }],
20
- ["path", {
21
- d: "M18 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",
22
- key: "svg-2"
23
- }]
24
- ], D = R("outline", "dots", "Dots", C), u = {
25
- initial: !1,
26
- whileTap: { scale: 0.97 },
27
- transition: {
28
- type: "spring",
29
- stiffness: 200,
30
- damping: 30,
31
- mass: 0.1
32
- }
33
- }, x = "border-pho-secondary bg-pho-page sticky top-0 flex h-dvh w-64 shrink-0 flex-col border-r", g = {
34
- base: "px-4 pt-5 pb-4",
35
- sm: "px-3 pt-4 pb-3"
36
- }, ae = a(x, g.base), B = {
37
- base: "mb-6 px-2",
38
- sm: "mb-3 px-0"
39
- }, O = "outline-pho-brand flex min-h-9 w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-base transition-colors focus-visible:outline-2 focus-visible:-outline-offset-1", M = "bg-pho-primary text-pho-primary ring-pho-secondary font-medium ring-1 ring-inset *:data-icon:text-pho-primary", F = a("text-pho-secondary *:data-icon:text-pho-secondary", "hover:bg-pho-primary hover:text-pho-primary hover:*:data-icon:text-pho-primary"), b = A("base");
40
- function L({ className: r, inset: e = "base", ...o }) {
41
- return /* @__PURE__ */ t(b.Provider, {
42
- value: e,
43
- children: /* @__PURE__ */ t("aside", {
44
- className: a(x, g[e], r),
45
- ...o,
46
- "data-inset": e
47
- })
48
- });
49
- }
50
- function z({ className: r, ...e }) {
51
- const o = T(b);
52
- return /* @__PURE__ */ t("div", {
53
- className: a("flex items-center gap-2.5", B[o], r),
54
- ...e
55
- });
56
- }
57
- function V({ className: r, ...e }) {
58
- return /* @__PURE__ */ t("nav", {
59
- className: a("flex flex-1 flex-col gap-6 overflow-y-auto", r),
60
- ...e
61
- });
62
- }
63
- function U({ className: r, ...e }) {
64
- return /* @__PURE__ */ t("div", {
65
- className: r,
66
- ...e
67
- });
68
- }
69
- function j({ className: r, ...e }) {
70
- return /* @__PURE__ */ t("div", {
71
- className: a("text-pho-description mb-2 px-2 text-xs font-normal", r),
72
- ...e
73
- });
74
- }
75
- function G({ className: r, columns: e, ...o }) {
76
- return /* @__PURE__ */ t("ul", {
77
- className: a("m-0 list-none p-0 *:m-0", e ? "grid grid-cols-2 gap-x-2 gap-y-0.5" : "flex flex-col gap-0.5", r),
78
- ...o
79
- });
80
- }
81
- function H({ className: r, ...e }) {
82
- return /* @__PURE__ */ t("div", {
83
- className: a("mt-4 flex flex-col gap-0.5", r),
84
- ...e
85
- });
86
- }
87
- function p(r) {
88
- if (r == null || r === !1) return null;
89
- let e = null;
90
- return N(r) ? e = /* @__PURE__ */ t(r, {}) : S(r) && (e = r), e == null ? null : /* @__PURE__ */ t("span", {
91
- "data-icon": !0,
92
- className: "pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-4 [&>svg]:shrink-0",
93
- children: e
94
- });
95
- }
96
- function P({ icon: r, active: e, className: o, children: i, href: s, external: m, ...d }) {
97
- const f = I(), y = k(() => c.create(f), [f]), h = a(O, e ? M : F, o), v = /* @__PURE__ */ t("span", {
98
- className: "min-w-0 flex-1 truncate",
99
- children: i
100
- });
101
- return s !== void 0 ? /* @__PURE__ */ t("li", { children: /* @__PURE__ */ n(y, {
102
- href: s,
103
- "aria-current": e ? "page" : void 0,
104
- ...m && {
105
- target: "_blank",
106
- rel: "noopener noreferrer"
107
- },
108
- ...d,
109
- className: h,
110
- ...u,
111
- children: [
112
- p(r),
113
- v,
114
- m && /* @__PURE__ */ n(w, { children: [p(/* @__PURE__ */ t(_, { "aria-hidden": !0 })), /* @__PURE__ */ t("span", {
115
- className: "sr-only",
116
- children: "(opens in a new tab)"
117
- })] })
118
- ]
119
- }) }) : /* @__PURE__ */ t("li", { children: /* @__PURE__ */ n(c.button, {
120
- type: "button",
121
- "aria-current": e ? "page" : void 0,
122
- ...d,
123
- className: h,
124
- ...u,
125
- children: [p(r), v]
126
- }) });
127
- }
128
- var W = "group outline-pho-brand flex w-full cursor-pointer items-center gap-2 rounded-base p-2 text-left focus-visible:outline-2 focus-visible:outline-offset-2";
129
- function $(r) {
130
- const e = r.split(/\s+/).filter(Boolean);
131
- return ((e[0]?.[0] ?? r[0] ?? "?") + (e.length >= 2 ? e[e.length - 1]?.[0] ?? "" : "")).toUpperCase();
132
- }
133
- function q({ name: r, avatarSrc: e, initials: o, className: i, ...s }) {
134
- return /* @__PURE__ */ n(c.button, {
135
- type: "button",
136
- className: a(W, i),
137
- ...s,
138
- ...u,
139
- children: [
140
- /* @__PURE__ */ n(l.Root, {
141
- size: "xs",
142
- children: [e && /* @__PURE__ */ t(l.Image, {
143
- src: e,
144
- alt: ""
145
- }), /* @__PURE__ */ t(l.Fallback, { children: o ?? $(r) })]
146
- }),
147
- /* @__PURE__ */ t("span", {
148
- className: "text-pho-primary min-w-0 flex-1 truncate text-base",
149
- children: r
150
- }),
151
- /* @__PURE__ */ t("span", {
152
- "aria-hidden": !0,
153
- className: E({
154
- variant: "outlined",
155
- size: "sm",
156
- shape: "circle",
157
- className: "group-hover:bg-pho-primary-hover group-hover:text-pho-secondary-hover group-data-[popup-open]:bg-pho-primary-hover group-data-[popup-open]:text-pho-secondary-hover p-1"
158
- }),
159
- children: /* @__PURE__ */ t(D, { className: "size-4" })
160
- })
161
- ]
162
- });
163
- }
164
- var oe = {
165
- Root: L,
166
- Header: z,
167
- Nav: V,
168
- Group: U,
169
- GroupLabel: j,
170
- List: G,
171
- Item: P,
172
- Footer: H,
173
- AccountRow: q
174
- };
175
- export {
176
- x as a,
177
- oe as c,
178
- F as i,
179
- O as n,
180
- ae as o,
181
- M as r,
182
- g as s,
183
- B as t
184
- };
185
-
186
- //# sourceMappingURL=sidebar-Dt1F_CEP.js.map