@photon-ai/pho-ui 2.2.0 → 2.4.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 (69) hide show
  1. package/dist/chunks/basic-page-c_7Ii5Fr.js +1117 -0
  2. package/dist/chunks/basic-page-c_7Ii5Fr.js.map +1 -0
  3. package/dist/chunks/{button-BmhyLgy5.js → button-DNNs5RsT.js} +6 -6
  4. package/dist/chunks/{button-BmhyLgy5.js.map → button-DNNs5RsT.js.map} +1 -1
  5. package/dist/chunks/{dialog-DtFO7oy0.js → dialog-8SRNi_rv.js} +3 -3
  6. package/dist/chunks/{dialog-DtFO7oy0.js.map → dialog-8SRNi_rv.js.map} +1 -1
  7. package/dist/chunks/{error-Da7P5WZi.js → error-Crs-wqMC.js} +14 -14
  8. package/dist/chunks/{error-Da7P5WZi.js.map → error-Crs-wqMC.js.map} +1 -1
  9. package/dist/chunks/form-AiHbbw4m.js +17 -0
  10. package/dist/chunks/form-AiHbbw4m.js.map +1 -0
  11. package/dist/chunks/{input-QSAUO30c.js → input-DjvZoF8v.js} +48 -43
  12. package/dist/chunks/input-DjvZoF8v.js.map +1 -0
  13. package/dist/chunks/{input-group-5AtpIhC_.js → input-group-fc9_jD4d.js} +44 -38
  14. package/dist/chunks/input-group-fc9_jD4d.js.map +1 -0
  15. package/dist/chunks/kbd-DNI10uy7.js +18 -0
  16. package/dist/chunks/kbd-DNI10uy7.js.map +1 -0
  17. package/dist/chunks/{menu-Cgj3lq9z.js → menu-BQeprfxB.js} +5 -5
  18. package/dist/chunks/{menu-Cgj3lq9z.js.map → menu-BQeprfxB.js.map} +1 -1
  19. package/dist/chunks/scroll-area-Bu7egArU.js +166 -0
  20. package/dist/chunks/scroll-area-Bu7egArU.js.map +1 -0
  21. package/dist/chunks/sidebar-DvB-G0BP.js +231 -0
  22. package/dist/chunks/sidebar-DvB-G0BP.js.map +1 -0
  23. package/dist/chunks/toast-DoXaRPIZ.js +167 -0
  24. package/dist/chunks/toast-DoXaRPIZ.js.map +1 -0
  25. package/dist/components/button.js +1 -1
  26. package/dist/components/command.js +125 -172
  27. package/dist/components/command.js.map +1 -1
  28. package/dist/components/context-menu.js +23 -23
  29. package/dist/components/dialog.js +1 -1
  30. package/dist/components/error.js +1 -1
  31. package/dist/components/field.js +12 -5
  32. package/dist/components/field.js.map +1 -1
  33. package/dist/components/form.js +2 -14
  34. package/dist/components/input-group.js +1 -1
  35. package/dist/components/input.js +1 -1
  36. package/dist/components/kbd.js +2 -15
  37. package/dist/components/menu.js +1 -1
  38. package/dist/components/phone-input.js +1 -1
  39. package/dist/components/scroll-area.js +3 -2
  40. package/dist/components/toast.js +3 -57
  41. package/dist/index.js +65 -58
  42. package/dist/primitives.js +3 -3
  43. package/dist/sections/basic-page.js +15 -8
  44. package/dist/sections/sidebar.js +1 -1
  45. package/dist/src/components/command/command.d.ts +5 -4
  46. package/dist/src/components/field/field.d.ts +9 -0
  47. package/dist/src/components/input/input.d.ts +10 -1
  48. package/dist/src/components/input-group/input-group.d.ts +9 -2
  49. package/dist/src/components/scroll-area/index.d.ts +1 -0
  50. package/dist/src/components/scroll-area/scroll-area-edges.d.ts +11 -1
  51. package/dist/src/components/scroll-area/scroll-area.d.ts +15 -2
  52. package/dist/src/components/toast/index.d.ts +1 -1
  53. package/dist/src/components/toast/toast.d.ts +22 -7
  54. package/dist/src/sections/basic-page/basic-page.d.ts +210 -30
  55. package/dist/src/sections/basic-page/index.d.ts +1 -1
  56. package/dist/src/sections/sidebar/sidebar.d.ts +33 -3
  57. package/package.json +1 -1
  58. package/src/styles/pho.css +19 -0
  59. package/dist/chunks/basic-page-CB36yrpL.js +0 -643
  60. package/dist/chunks/basic-page-CB36yrpL.js.map +0 -1
  61. package/dist/chunks/input-QSAUO30c.js.map +0 -1
  62. package/dist/chunks/input-group-5AtpIhC_.js.map +0 -1
  63. package/dist/chunks/scroll-area-Cw4JFqNG.js +0 -152
  64. package/dist/chunks/scroll-area-Cw4JFqNG.js.map +0 -1
  65. package/dist/chunks/sidebar-BETMObNj.js +0 -186
  66. package/dist/chunks/sidebar-BETMObNj.js.map +0 -1
  67. package/dist/components/form.js.map +0 -1
  68. package/dist/components/kbd.js.map +0 -1
  69. package/dist/components/toast.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"basic-page-CB36yrpL.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 isValidElement,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type AnchorHTMLAttributes,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { IconChevronLeft, IconChevronRight } from \"@tabler/icons-react\";\nimport { ButtonLink, type ButtonLinkProps } from \"../../components/button\";\nimport { Error as ErrorLine } from \"../../components/error\";\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 */\nfunction Root({\n className,\n ...props\n}: ComponentProps<\"div\"> & { ref?: Ref<HTMLDivElement> }) {\n return (\n <div\n className={cn(\n \"relative mx-auto flex min-h-full w-full max-w-[44.5rem] min-w-0 flex-col px-5 pt-12 pb-12 *:min-w-0 has-[[data-basic-page-back]]:pt-16\",\n className,\n )}\n {...props}\n />\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 * 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 morphWordVisible = new Map<string, boolean>();\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 () => morphId != null && morphWordVisible.get(morphId) === true,\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) morphWordVisible.set(morphId, entry.isIntersecting);\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 morphWordVisible.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 // 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 >\n {morphId != null && !reduceMotion ? (\n <MorphLabel\n morphId={morphId}\n fromClassName=\"text-pho-secondary\"\n fly={flight.fly}\n morphRef={flight.ref}\n arrival={enter ? \"rise\" : undefined}\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\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, ...props }: BasicPageStackProps) {\n const reduceMotion = useReducedMotion();\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(\n \"mt-6 flex min-w-0 flex-col gap-10\",\n \"*:flex *:min-w-0 *:flex-col *:gap-3\",\n className,\n )}\n {...props}\n />\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\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 className={cn(\"flex min-w-0 flex-col\", className)}\n {...props}\n />\n );\n }\n return <div className={cn(\"flex min-w-0 flex-col\", className)} {...props} />;\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 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(\"text-pho-description px-5 text-xs font-normal\", className)}\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 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 {children}\n </AnimatedHeight>\n </div>\n );\n }\n return (\n <div className={cn(BASIC_PAGE_CARD, className)} {...props}>\n {children}\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}: ComponentProps<\"div\"> & { ref?: Ref<HTMLDivElement> }) {\n return <div className={cn(BASIC_PAGE_ITEM, className)} {...props} />;\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\"\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 return (\n <div\n className={cn(\n BASIC_PAGE_ROW,\n stacked && \"sm:flex-col sm:items-stretch sm:justify-start sm:gap-3\",\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 <p className=\"text-pho-primary text-base font-normal\">{label}</p>\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 </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,\n show,\n className,\n children,\n ...props\n}: BasicPageAlertProps) {\n const reduceMotion = useReducedMotion();\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\nexport interface BasicPageFooterProps extends ComponentProps<\"div\"> {\n /**\n * Animated presence for dirty-state bars: the card glides open/closed on a\n * height spring while the content fades. Omit for a static, always-visible\n * footer (no animation). No reveal plays on first mount — only on flips.\n */\n show?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * Trailing bar inside a card — typically a save status + submit button that\n * appears after the form is dirty. Same horizontal/vertical padding as a row.\n * Pass `show` (instead of conditional rendering) to animate the bar in and\n * out following the onboarding card's motion language.\n */\nfunction Footer({ show, className, ...props }: BasicPageFooterProps) {\n const reduceMotion = useReducedMotion();\n const bar = (\n <div\n className={cn(\n \"flex items-center justify-between gap-6 px-5 py-4\",\n className,\n )}\n {...props}\n />\n );\n\n if (show === undefined) return bar;\n\n return (\n <AnimatePresence initial={false}>\n {show ? (\n <motion.div\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 {bar}\n </motion.div>\n ) : null}\n </AnimatePresence>\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 * Which gap the presence variant compensates while collapsing —\n * `\"stack\"` for a Stack block (`gap-10`), `\"block\"` for an element\n * inside a block (`gap-3`). @default \"stack\"\n */\n gap?: \"stack\" | \"block\";\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 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 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\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 return (\n <AnimatePresence initial={false}>\n {show ? (\n <motion.div\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(\n \"overflow-hidden\",\n dividers && BASIC_PAGE_CARD_DIVIDERS,\n className,\n )}\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-[10.25px]` plus\n * the button's 8px icon-side padding, centred in the 32px control; the\n * glyph is 1.125em of the `sm` button's 14px type. Kept next to the trail's\n * own offset math.\n */\nconst BACK_CHEVRON_GHOST_POSITION =\n \"top-4 left-[18.25px] 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 `Root`'s reserved top\n * padding (vertically centered in the 64px zone) instead of taking layout\n * space, so `Title` sits at the same position whether or not a page has\n * 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 * The offsets align the first *label* glyph with the title glyph. Title\n * text sits 40px in (`px-5` root gutter + `px-5` title pad); inside a `sm`\n * ghost button the label sits 29.75px in (8px icon-side pad + 15.75px\n * chevron, 1.125em at the 14px `text-base`, + 4px gap + 2px label-span\n * `px-0.5`) — so `left` is the 10.25px difference. `top-4` centers the 32px\n * buttons in the 64px reserved zone. The chevron and the ghost hover pills\n * hang in the padding — the usual optical alignment for borderless controls.\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 // 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-[10.25px] 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 <li\n key={item.key ?? index}\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 ))}\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\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\"\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 return (\n <Link\n href={href}\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 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 </Link>\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 Reveal,\n};\n"],"x_google_ignoreList":[0],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"input-QSAUO30c.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 </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,152 +0,0 @@
1
- "use client";
2
- import { t as u } from "./cn-ChIgwEl3.js";
3
- import { createContext as S, useContext as k, useLayoutEffect as A, useRef as m } from "react";
4
- import { jsx as l, jsxs as x } from "react/jsx-runtime";
5
- import { ScrollArea as s } from "@base-ui/react/scroll-area";
6
- var C = "pointer-events-none absolute inset-x-0 z-10 h-8", L = 8, $ = 1;
7
- function N(t, e) {
8
- const n = 100 / (t + 1);
9
- return Array.from({ length: t }, (r, o) => ({
10
- blurPx: o / (t - 1) * e,
11
- window: [
12
- o * n,
13
- (o + 1) * n,
14
- (o + 2) * n,
15
- (o + 3) * n
16
- ]
17
- })).filter((r) => r.blurPx > 0);
18
- }
19
- var _ = N(L, $);
20
- function z(t, e) {
21
- const n = t === "top" ? "to top" : "to bottom", [r, o, i, a] = e;
22
- return `linear-gradient(${n}, transparent ${r}%, black ${o}%, black ${i}%, transparent ${a}%)`;
23
- }
24
- function P(t) {
25
- const e = t === "top" ? "to top" : "to bottom", n = "var(--background-color-pho-primary)";
26
- return `linear-gradient(${e}, color-mix(in oklab, ${n} 20%, transparent) 0%, ${n} 100%)`;
27
- }
28
- function h(t, e) {
29
- if (t)
30
- for (const n of t.children) {
31
- const r = n;
32
- if (r.dataset.scrollFade === "wash") {
33
- r.style.opacity = String(e);
34
- continue;
35
- }
36
- const o = `blur(${Number(r.dataset.blurPx) * e}px)`;
37
- r.style.backdropFilter = o, r.style.setProperty("-webkit-backdrop-filter", o);
38
- }
39
- }
40
- function g({ edge: t, edgeRef: e }) {
41
- return /* @__PURE__ */ x("div", {
42
- ref: e,
43
- "aria-hidden": !0,
44
- "data-edge": t,
45
- className: u(C, t === "top" ? "top-0" : "bottom-0"),
46
- children: [_.map(({ blurPx: n, window: r }, o) => {
47
- const i = z(t, r);
48
- return /* @__PURE__ */ l("div", {
49
- "data-blur-px": n,
50
- className: "absolute inset-0",
51
- style: {
52
- maskImage: i,
53
- WebkitMaskImage: i
54
- }
55
- }, o);
56
- }), /* @__PURE__ */ l("div", {
57
- "data-scroll-fade": "wash",
58
- className: "absolute inset-0 opacity-0",
59
- style: { background: P(t) }
60
- })]
61
- });
62
- }
63
- var E = S(null);
64
- function T() {
65
- const t = k(E);
66
- if (t == null) throw new Error("ScrollArea parts must be used inside ScrollArea.Root");
67
- return t;
68
- }
69
- function y(t) {
70
- return t <= 0 ? 0 : t >= 1 ? 1 : t;
71
- }
72
- function B(t, e) {
73
- typeof t == "function" ? t(e) : t && (t.current = e);
74
- }
75
- var F = s.Content, H = s.Corner;
76
- function U({ className: t, children: e, ...n }) {
77
- const r = m(null), o = m(null);
78
- return /* @__PURE__ */ l(s.Root, {
79
- className: u("relative overflow-hidden", t),
80
- ...n,
81
- children: /* @__PURE__ */ x(E.Provider, {
82
- value: {
83
- topEl: r,
84
- bottomEl: o
85
- },
86
- children: [
87
- e,
88
- /* @__PURE__ */ l(g, {
89
- edge: "top",
90
- edgeRef: r
91
- }),
92
- /* @__PURE__ */ l(g, {
93
- edge: "bottom",
94
- edgeRef: o
95
- })
96
- ]
97
- })
98
- });
99
- }
100
- function M({ className: t, ref: e, ...n }) {
101
- const { topEl: r, bottomEl: o } = T(), i = m(null);
102
- return A(() => {
103
- const a = i.current;
104
- if (!a) return;
105
- const d = () => {
106
- const v = r.current?.offsetHeight || o.current?.offsetHeight || 32, p = a.scrollHeight - a.clientHeight, w = p <= 0 ? 0 : y(a.scrollTop / v), R = p <= 0 ? 0 : y((p - a.scrollTop) / v);
107
- h(r.current, w), h(o.current, R);
108
- };
109
- let c = 0;
110
- const b = () => {
111
- c || (c = requestAnimationFrame(() => {
112
- c = 0, d();
113
- }));
114
- };
115
- d(), a.addEventListener("scroll", b, { passive: !0 });
116
- let f = null;
117
- return typeof ResizeObserver < "u" && (f = new ResizeObserver(d), f.observe(a), a.firstElementChild && f.observe(a.firstElementChild)), () => {
118
- a.removeEventListener("scroll", b), c && cancelAnimationFrame(c), f?.disconnect();
119
- };
120
- }, [r, o]), /* @__PURE__ */ l(s.Viewport, {
121
- className: u("outline-pho-brand h-full min-h-0 w-full overscroll-contain rounded-[inherit] focus-visible:outline-2 focus-visible:-outline-offset-1", t),
122
- ...n,
123
- ref: (a) => {
124
- i.current = a, B(e, a);
125
- }
126
- });
127
- }
128
- function O({ className: t, ...e }) {
129
- return /* @__PURE__ */ l(s.Scrollbar, {
130
- className: u("relative z-20 flex touch-none p-0.5 opacity-0 transition-opacity delay-300 select-none", "data-[hovering]:opacity-100 data-[hovering]:delay-0 data-[scrolling]:opacity-100 data-[scrolling]:delay-0 data-[scrolling]:duration-0", "data-[orientation=horizontal]:h-2.5 data-[orientation=horizontal]:flex-col data-[orientation=vertical]:w-2.5", t),
131
- ...e
132
- });
133
- }
134
- function j({ className: t, ...e }) {
135
- return /* @__PURE__ */ l(s.Thumb, {
136
- className: u("flex-1 rounded-full bg-[var(--border-color-pho-primary)]", t),
137
- ...e
138
- });
139
- }
140
- var Y = {
141
- Root: U,
142
- Viewport: M,
143
- Content: F,
144
- Scrollbar: O,
145
- Thumb: j,
146
- Corner: H
147
- };
148
- export {
149
- Y as t
150
- };
151
-
152
- //# sourceMappingURL=scroll-area-Cw4JFqNG.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scroll-area-Cw4JFqNG.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\nfunction washGradient(edge: \"top\" | \"bottom\") {\n const to = edge === \"top\" ? \"to top\" : \"to bottom\";\n const surface = \"var(--background-color-pho-primary)\";\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}: {\n edge: \"top\" | \"bottom\";\n edgeRef: Ref<HTMLDivElement>;\n}) {\n return (\n <div\n ref={edgeRef}\n aria-hidden\n data-edge={edge}\n className={cn(EDGE_CLASS, edge === \"top\" ? \"top-0\" : \"bottom-0\")}\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) }}\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 o } from "./cn-ChIgwEl3.js";
3
- import { n as I, r as N } from "./link-provider-9TFNyDqO.js";
4
- import { u as E } from "./button-BmhyLgy5.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
- }, oe = o(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", L = o("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 z({ className: r, inset: e = "base", ...a }) {
41
- return /* @__PURE__ */ t(b.Provider, {
42
- value: e,
43
- children: /* @__PURE__ */ t("aside", {
44
- className: o(x, g[e], r),
45
- ...a,
46
- "data-inset": e
47
- })
48
- });
49
- }
50
- function F({ className: r, ...e }) {
51
- const a = T(b);
52
- return /* @__PURE__ */ t("div", {
53
- className: o("flex items-center gap-2.5", B[a], r),
54
- ...e
55
- });
56
- }
57
- function V({ className: r, ...e }) {
58
- return /* @__PURE__ */ t("nav", {
59
- className: o("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: o("text-pho-description mb-2 px-2 text-xs font-normal", r),
72
- ...e
73
- });
74
- }
75
- function G({ className: r, columns: e, ...a }) {
76
- return /* @__PURE__ */ t("ul", {
77
- className: o("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
- ...a
79
- });
80
- }
81
- function H({ className: r, ...e }) {
82
- return /* @__PURE__ */ t("div", {
83
- className: o("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: a, children: i, href: s, external: m, ...d }) {
97
- const f = I(), y = k(() => c.create(f), [f]), h = o(O, e ? M : L, a), 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 q(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 J({ name: r, avatarSrc: e, initials: a, className: i, ...s }) {
134
- return /* @__PURE__ */ n(c.button, {
135
- type: "button",
136
- className: o(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: a ?? q(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 ae = {
165
- Root: z,
166
- Header: F,
167
- Nav: V,
168
- Group: U,
169
- GroupLabel: j,
170
- List: G,
171
- Item: P,
172
- Footer: H,
173
- AccountRow: J
174
- };
175
- export {
176
- x as a,
177
- ae as c,
178
- L as i,
179
- O as n,
180
- oe as o,
181
- M as r,
182
- g as s,
183
- B as t
184
- };
185
-
186
- //# sourceMappingURL=sidebar-BETMObNj.js.map