@photon-ai/pho-ui 4.11.0 → 4.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/animated-height-zr7BmFY1.js +56 -0
- package/dist/chunks/animated-height-zr7BmFY1.js.map +1 -0
- package/dist/chunks/basic-page-6dDfY33L.js +2197 -0
- package/dist/chunks/basic-page-6dDfY33L.js.map +1 -0
- package/dist/chunks/box-search-C9EVZgcb.js +56 -0
- package/dist/chunks/box-search-C9EVZgcb.js.map +1 -0
- package/dist/chunks/{chat-B0WIgEyM.js → chat-Bu8UyIbT.js} +207 -205
- package/dist/chunks/chat-Bu8UyIbT.js.map +1 -0
- package/dist/chunks/{checkbox-CLPmblNA.js → checkbox-CwvoEJhd.js} +2 -2
- package/dist/chunks/{checkbox-CLPmblNA.js.map → checkbox-CwvoEJhd.js.map} +1 -1
- package/dist/chunks/choice-card-_Ocs0iUj.js +17 -0
- package/dist/chunks/choice-card-_Ocs0iUj.js.map +1 -0
- package/dist/chunks/chrome-Ds7WykBJ.js +14 -0
- package/dist/chunks/chrome-Ds7WykBJ.js.map +1 -0
- package/dist/chunks/{command-iYvU6Mhf.js → command-D5g49VqR.js} +3 -3
- package/dist/chunks/{command-iYvU6Mhf.js.map → command-D5g49VqR.js.map} +1 -1
- package/dist/chunks/{data-table-B1dmrN6r.js → data-table-hzZb7Otx.js} +58 -56
- package/dist/chunks/{data-table-B1dmrN6r.js.map → data-table-hzZb7Otx.js.map} +1 -1
- package/dist/chunks/{dialog-MPvem7yV.js → dialog-ChS0tdHa.js} +120 -116
- package/dist/chunks/dialog-ChS0tdHa.js.map +1 -0
- package/dist/chunks/{filter-bar-B-oYYBsU.js → filter-bar-C4sPEjw1.js} +63 -66
- package/dist/chunks/filter-bar-C4sPEjw1.js.map +1 -0
- package/dist/chunks/ghost-search-8PzP73zS.js +50 -0
- package/dist/chunks/ghost-search-8PzP73zS.js.map +1 -0
- package/dist/chunks/{input-DjvZoF8v.js → input-fFWvPJOf.js} +2 -1
- package/dist/chunks/{input-DjvZoF8v.js.map → input-fFWvPJOf.js.map} +1 -1
- package/dist/chunks/{trace-D1fOFzJt.js → trace-DyjsBY-S.js} +15 -13
- package/dist/chunks/{trace-D1fOFzJt.js.map → trace-DyjsBY-S.js.map} +1 -1
- package/dist/components/chat.js +1 -1
- package/dist/components/checkbox.js +1 -1
- package/dist/components/command.js +1 -1
- package/dist/components/data-table.js +4 -3
- package/dist/components/dialog.js +1 -1
- package/dist/components/field.js +34 -29
- package/dist/components/field.js.map +1 -1
- package/dist/components/filter-bar.js +1 -1
- package/dist/components/input.js +1 -1
- package/dist/components/radio-group.js +64 -59
- package/dist/components/radio-group.js.map +1 -1
- package/dist/components/scope.js +418 -0
- package/dist/components/scope.js.map +1 -0
- package/dist/components/trace.js +1 -1
- package/dist/index.js +176 -175
- package/dist/motion.js +61 -36
- package/dist/motion.js.map +1 -1
- package/dist/sections/basic-page.js +2 -2
- package/dist/src/components/chat/chat.d.ts +7 -4
- package/dist/src/components/dialog/dialog.d.ts +9 -1
- package/dist/src/components/field/field.d.ts +11 -1
- package/dist/src/components/input-group/box-search.d.ts +29 -0
- package/dist/src/components/radio-group/radio-card.d.ts +11 -4
- package/dist/src/components/scope/index.d.ts +1 -0
- package/dist/src/components/scope/scope.d.ts +98 -0
- package/dist/src/motion/index.d.ts +52 -0
- package/dist/src/sections/basic-page/basic-page.d.ts +145 -15
- package/dist/src/sections/basic-page/index.d.ts +1 -1
- package/dist/src/utils/animated-height.d.ts +16 -7
- package/dist/src/utils/choice-card.d.ts +8 -1
- package/dist/src/utils/ghost-search.d.ts +19 -3
- package/package.json +5 -1
- package/dist/chunks/animated-height-I44sUq0n.js +0 -48
- package/dist/chunks/animated-height-I44sUq0n.js.map +0 -1
- package/dist/chunks/basic-page-B5FsORRi.js +0 -1885
- package/dist/chunks/basic-page-B5FsORRi.js.map +0 -1
- package/dist/chunks/chat-B0WIgEyM.js.map +0 -1
- package/dist/chunks/choice-card-BVNP1NB6.js +0 -17
- package/dist/chunks/choice-card-BVNP1NB6.js.map +0 -1
- package/dist/chunks/dialog-MPvem7yV.js.map +0 -1
- package/dist/chunks/filter-bar-B-oYYBsU.js.map +0 -1
- package/dist/chunks/ghost-search-CNVs9k1o.js +0 -34
- package/dist/chunks/ghost-search-CNVs9k1o.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chat-B0WIgEyM.js","names":["__iconNode","__iconNode","__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowLeft.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowUp.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconUser.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconUsers.mjs","../../src/components/chat/chat.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\": \"M5 12l14 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M5 12l6 6\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M5 12l6 -6\", \"key\": \"svg-2\" }]];\nconst IconArrowLeft = createReactComponent(\"outline\", \"arrow-left\", \"ArrowLeft\", __iconNode);\n\nexport { __iconNode, IconArrowLeft as default };\n//# sourceMappingURL=IconArrowLeft.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\": \"M12 5l0 14\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M18 11l-6 -6\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M6 11l6 -6\", \"key\": \"svg-2\" }]];\nconst IconArrowUp = createReactComponent(\"outline\", \"arrow-up\", \"ArrowUp\", __iconNode);\n\nexport { __iconNode, IconArrowUp as default };\n//# sourceMappingURL=IconArrowUp.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\": \"M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2\", \"key\": \"svg-1\" }]];\nconst IconUser = createReactComponent(\"outline\", \"user\", \"User\", __iconNode);\n\nexport { __iconNode, IconUser as default };\n//# sourceMappingURL=IconUser.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\": \"M5 7a4 4 0 1 0 8 0a4 4 0 1 0 -8 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M16 3.13a4 4 0 0 1 0 7.75\", \"key\": \"svg-2\" }], [\"path\", { \"d\": \"M21 21v-2a4 4 0 0 0 -3 -3.85\", \"key\": \"svg-3\" }]];\nconst IconUsers = createReactComponent(\"outline\", \"users\", \"Users\", __iconNode);\n\nexport { __iconNode, IconUsers as default };\n//# sourceMappingURL=IconUsers.mjs.map\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type CSSProperties,\n type ComponentProps,\n type ComponentType,\n type FormEvent,\n type KeyboardEvent,\n type PointerEvent,\n type ReactNode,\n type Ref,\n type RefObject,\n} from \"react\";\nimport {\n IconArrowLeft,\n IconArrowUp,\n IconSearch,\n IconUser,\n IconUsers,\n} from \"@tabler/icons-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport {\n BLUR_PX,\n FADE_SWAP,\n PRESS_SCALE_ROW,\n SPRING_PRESS,\n TRAVEL_LINEAR,\n} from \"../../motion\";\nimport { Avatar } from \"../avatar\";\nimport { Button } from \"../button\";\nimport { Input, type InputProps } from \"../input\";\nimport { ScrollArea } from \"../scroll-area\";\nimport { Skeleton } from \"../skeleton\";\nimport { StatusView, type StatusViewProps } from \"../status-view\";\nimport { cn } from \"../../utils/cn\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\n\n/**\n * Chat — an inbox in one card: the conversations down the left, the open\n * thread on the right with its messages scrolling up from the composer.\n * It composes the smaller parts (`Message` rows of `Bubble`s in a\n * `ScrollArea`, an `Input` for search, `Button`s to send and go back) the\n * way `Sidebar` composes a rail: rows that press, one active, links\n * through the host's `LinkProvider`.\n *\n * Two layouts. `default` seats both panes side by side — the divider\n * between them drags so either pane can grow, each down to a min width.\n * `compact` shows one at a time — the list, then the thread with a way\n * back — for a narrow column or a phone. Opening a conversation pushes\n * the thread in from the right; back pops the list in from the left, a\n * short drift on `TRAVEL_LINEAR` with a `FADE_SWAP` fade. `auto` is\n * compact only while the frame is narrower than 42rem (a container\n * query, so it follows the card, not the viewport). Which pane is up is\n * `pane`, controlled or not; opening a conversation moves to the thread,\n * the header's back button returns.\n *\n * Presentational, like every Pho part: the page fetches, formats times,\n * and decides who is who. The thread stays pinned to its newest message\n * while the reader is at the bottom, and keeps its place when earlier\n * pages arrive above.\n */\n\nexport type ChatLayout = \"default\" | \"compact\" | \"auto\";\nexport type ChatPane = \"list\" | \"thread\";\n/** Push is 1 (thread from the right); pop is −1 (list from the left). */\nexport type ChatPaneDirection = 1 | -1;\n\n/** Same chrome as `BasicPage.Card` and `LogList` — one card surface. */\nconst CHAT_SURFACE = \"rounded-base border border-pho-secondary bg-pho-primary\";\n\n// Below this frame width `auto` is compact: the `@2xl` container variant\n// (42rem) in the class strings below. Those variants are spelled out in\n// full on purpose — Tailwind finds utilities by scanning source text, so\n// a variant built from a variable (`${AUTO_WIDE}` before the colon) never\n// reached a consumer's CSS and `auto` stayed single-pane at every width.\n// chat.test.tsx keeps it that way.\n/** `42rem` in px at the 16px root — `frameWidth` is measured in px. */\nconst AUTO_WIDE_PX = 672;\n/**\n * Compact pane travel — a short drift, the same scale as `BAR_RISE_PX`,\n * not a full-width slide.\n */\nconst PANE_TRAVEL_PX = 24;\n/** Outgoing pane drift — same distance as BasicPage `BACK_LABEL_LEAVE_X`. */\nconst PANE_LEAVE_PX = 8;\n\n/** Search (`p-3` + sm Input) is the pane top-bar height; Header matches it. */\nconst TOP_BAR = \"min-h-[61px]\";\n\n/**\n * Wide layouts start the list at 273 — the measured inbox column, not\n * `w-80`. It will not go below `min-w-64` (256); the thread will not go\n * below `min-w-80` (320).\n */\nconst LIST_WIDTH_PX = 273;\nconst LIST_MIN_PX = 256;\nconst THREAD_MIN_PX = 320;\nconst SPLIT_STEP_PX = 16;\n\nfunction clampListWidth(width: number, rootWidth: number) {\n const next = Math.max(LIST_MIN_PX, width);\n if (rootWidth <= 0) return Number.isFinite(next) ? next : LIST_MIN_PX;\n return Math.min(next, Math.max(LIST_MIN_PX, rootWidth - THREAD_MIN_PX));\n}\n\ninterface ChatContextValue {\n layout: ChatLayout;\n pane: ChatPane;\n setPane: (pane: ChatPane) => void;\n /** Latest list ↔ thread step: 1 push, −1 pop. */\n direction: ChatPaneDirection;\n /** One pane at a time — compact, or `auto` once the frame measures narrow. */\n swap: boolean;\n /** True after the first list ↔ thread step — later remounts still push. */\n swapped: boolean;\n listWidth: number;\n frameWidth: number;\n resizeList: (width: number) => void;\n rootRef: RefObject<HTMLDivElement | null>;\n}\n\nconst ChatContext = createContext<ChatContextValue | null>(null);\n\nfunction useChat(part: string): ChatContextValue {\n const ctx = useContext(ChatContext);\n if (ctx == null) {\n throw new Error(`Chat.${part} must be used inside Chat.Root`);\n }\n return ctx;\n}\n\n// React 18 warns that useLayoutEffect does nothing on the server; fall\n// back to useEffect there so SSR'd docs stay quiet.\nconst useIsoLayoutEffect =\n typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\nfunction paneDirectionFor(pane: ChatPane): ChatPaneDirection {\n return pane === \"thread\" ? 1 : -1;\n}\n\n/**\n * Compact (and `auto` once the frame measures narrower than 42rem) mounts\n * one pane at a time so `AnimatePresence` can push/pop. `frameWidth` 0 is\n * the unmeasured / SSR frame — treat it as wide so both panes render and\n * nothing flashes.\n */\nfunction isPaneSwap(layout: ChatLayout, frameWidth: number) {\n return (\n layout === \"compact\" ||\n (layout === \"auto\" && frameWidth > 0 && frameWidth < AUTO_WIDE_PX)\n );\n}\n\n/**\n * The compact pane swap — incoming travels `PANE_TRAVEL_PX` on\n * `TRAVEL_LINEAR`, fades and breathes `BLUR_PX` on `FADE_SWAP`; outgoing\n * drifts `PANE_LEAVE_PX` the other way. Under reduced motion: opacity\n * only, and instant.\n */\nexport function paneSwapMotion(\n direction: ChatPaneDirection,\n reduceMotion?: boolean | null,\n) {\n if (reduceMotion) {\n return {\n initial: { opacity: 0 },\n animate: { opacity: 1 },\n exit: { opacity: 0 },\n transition: { duration: 0 },\n };\n }\n return {\n initial: {\n x: direction * PANE_TRAVEL_PX,\n opacity: 0,\n filter: `blur(${BLUR_PX}px)`,\n },\n animate: { x: 0, opacity: 1, filter: \"blur(0px)\" },\n exit: {\n x: -direction * PANE_LEAVE_PX,\n opacity: 0,\n filter: `blur(${BLUR_PX}px)`,\n },\n transition: { x: TRAVEL_LINEAR, opacity: FADE_SWAP, filter: FADE_SWAP },\n };\n}\n\nfunction paneSwapVariants(reduceMotion: boolean | null) {\n return {\n enter: (direction: ChatPaneDirection) =>\n paneSwapMotion(direction, reduceMotion).initial,\n rest: (direction: ChatPaneDirection) =>\n paneSwapMotion(direction, reduceMotion).animate,\n leave: (direction: ChatPaneDirection) =>\n paneSwapMotion(direction, reduceMotion).exit,\n };\n}\n\n/**\n * DOM handlers whose React signatures clash with Motion's gesture props.\n * Same omit list as `Button` — swap panes and conversation rows render\n * through `motion.*`.\n */\ntype MotionHandlerConflicts =\n | \"onAnimationStart\"\n | \"onAnimationEnd\"\n | \"onAnimationIteration\"\n | \"onDrag\"\n | \"onDragStart\"\n | \"onDragEnd\"\n | \"onDragEnter\"\n | \"onDragExit\"\n | \"onDragLeave\"\n | \"onDragOver\"\n | \"onDrop\";\n\ntype SwapPaneProps = {\n show: boolean;\n swapped: boolean;\n direction: ChatPaneDirection;\n reduceMotion: boolean | null;\n children?: ReactNode;\n} & (\n | ({ as: \"aside\" } & Omit<\n ComponentProps<\"aside\">,\n \"children\" | MotionHandlerConflicts\n >)\n | ({ as: \"section\" } & Omit<\n ComponentProps<\"section\">,\n \"children\" | MotionHandlerConflicts\n >)\n);\n\ntype SwapMotionProps = {\n custom: ChatPaneDirection;\n variants: ReturnType<typeof paneSwapVariants>;\n initial: \"enter\";\n animate: \"rest\";\n exit: \"leave\";\n transition: ReturnType<typeof paneSwapMotion>[\"transition\"];\n};\n\n/**\n * The compact face — Root's `AnimatePresence` keys list vs thread. `custom`\n * on that presence feeds this step's push/pop into the exiting face.\n */\nfunction SwapPane({\n as,\n show,\n swapped,\n direction,\n reduceMotion,\n children,\n ...props\n}: SwapPaneProps) {\n const swap = paneSwapMotion(direction, reduceMotion);\n const motionProps: SwapMotionProps = {\n custom: direction,\n variants: paneSwapVariants(reduceMotion),\n initial: \"enter\",\n animate: \"rest\",\n exit: \"leave\",\n transition: swap.transition,\n };\n // Skip the first paint only before any pane change — a Thread that\n // remounts (host `key`) on the way in still pushes.\n return (\n <AnimatePresence\n initial={!swapped && show ? false : undefined}\n mode=\"popLayout\"\n custom={direction}\n >\n {show ? (\n as === \"aside\" ? (\n <motion.aside key=\"list\" {...props} {...motionProps}>\n {children}\n </motion.aside>\n ) : (\n <motion.section key=\"thread\" {...props} {...motionProps}>\n {children}\n </motion.section>\n )\n ) : null}\n </AnimatePresence>\n );\n}\n\n/* --------------------------------- root --------------------------------- */\n\nexport interface ChatRootProps extends ComponentProps<\"div\"> {\n /**\n * `default` shows both panes; `compact` one at a time; `auto` is\n * compact while the frame is narrower than 42rem.\n * @default \"default\"\n */\n layout?: ChatLayout;\n /** The pane that is up in a compact layout. Pair with `onPaneChange`. */\n pane?: ChatPane;\n /** Initial pane when uncontrolled. @default \"list\" */\n defaultPane?: ChatPane;\n /** Called with the next pane — a row opened a thread, back was pressed. */\n onPaneChange?: (pane: ChatPane) => void;\n ref?: Ref<HTMLDivElement>;\n}\n\n/**\n * The card. Give it a height (`h-[32rem]`, or `min-h-0 flex-1` in a\n * column that fills the page); the panes scroll inside it.\n */\nfunction Root({\n layout = \"default\",\n pane: paneProp,\n defaultPane = \"list\",\n onPaneChange,\n className,\n style,\n ref,\n ...props\n}: ChatRootProps) {\n const [uncontrolledPane, setUncontrolledPane] = useState(defaultPane);\n const [listWidth, setListWidth] = useState(LIST_WIDTH_PX);\n const [frameWidth, setFrameWidth] = useState(0);\n const rootRef = useRef<HTMLDivElement | null>(null);\n const controlled = paneProp !== undefined;\n const pane = controlled ? paneProp : uncontrolledPane;\n const [direction, setDirection] = useState<ChatPaneDirection>(() =>\n paneDirectionFor(pane),\n );\n const [swapped, setSwapped] = useState(false);\n const prevPaneRef = useRef(pane);\n // Keep this render's direction aligned with `pane` so a controlled\n // update and a `setPane` call both push/pop on the same frame.\n let renderedDirection = direction;\n let renderedSwapped = swapped;\n if (prevPaneRef.current !== pane) {\n renderedDirection = paneDirectionFor(pane);\n renderedSwapped = true;\n prevPaneRef.current = pane;\n if (renderedDirection !== direction) setDirection(renderedDirection);\n if (!swapped) setSwapped(true);\n }\n const setPane = useCallback(\n (next: ChatPane) => {\n setDirection(paneDirectionFor(next));\n if (!controlled) setUncontrolledPane(next);\n onPaneChange?.(next);\n },\n [controlled, onPaneChange],\n );\n const resizeList = useCallback((width: number) => {\n setListWidth(clampListWidth(width, rootRef.current?.clientWidth ?? 0));\n }, []);\n const swap = isPaneSwap(layout, frameWidth);\n useIsoLayoutEffect(() => {\n const root = rootRef.current;\n if (!root || typeof ResizeObserver === \"undefined\") return;\n const tighten = () => {\n const frame = root.clientWidth;\n setFrameWidth(frame);\n setListWidth((current) => clampListWidth(current, frame));\n };\n tighten();\n const observer = new ResizeObserver(tighten);\n observer.observe(root);\n return () => observer.disconnect();\n }, []);\n const value = useMemo(\n () => ({\n layout,\n pane,\n setPane,\n direction: renderedDirection,\n swap,\n swapped: renderedSwapped,\n listWidth,\n frameWidth,\n resizeList,\n rootRef,\n }),\n [\n layout,\n pane,\n setPane,\n renderedDirection,\n swap,\n renderedSwapped,\n listWidth,\n frameWidth,\n resizeList,\n ],\n );\n return (\n <ChatContext.Provider value={value}>\n <div\n ref={(node) => {\n rootRef.current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref) {\n (ref as { current: HTMLDivElement | null }).current = node;\n }\n }}\n data-chat=\"\"\n data-basic-page-card=\"\"\n data-layout={layout}\n data-pane={pane}\n style={\n {\n ...style,\n \"--chat-list-width\": `${listWidth}px`,\n } as CSSProperties\n }\n className={cn(\n CHAT_SURFACE,\n \"@container relative flex min-h-0 min-w-0 overflow-hidden\",\n className,\n )}\n {...props}\n />\n </ChatContext.Provider>\n );\n}\n\n/* --------------------------------- list --------------------------------- */\n\n/** The left pane — search above, conversations below, on the page wash. */\nfunction List({\n className,\n children,\n id: idProp,\n ...props\n}: ComponentProps<\"aside\">) {\n const { layout, pane, direction, swap, swapped } = useChat(\"List\");\n const reduceMotion = useReducedMotion();\n const uid = useId();\n const listId = idProp ?? uid;\n const listClass = cn(\n \"border-pho-secondary bg-pho-page relative z-10 flex min-h-0 shrink-0 flex-col\",\n layout === \"default\" && \"min-w-64 w-[var(--chat-list-width)] border-r\",\n layout === \"compact\" && \"w-full\",\n layout === \"auto\" &&\n cn(\n \"w-full @2xl:min-w-64 @2xl:w-[var(--chat-list-width)] @2xl:border-r\",\n !swap && pane === \"thread\" && \"@max-2xl:hidden\",\n ),\n className,\n );\n const body = (\n <>\n {children}\n {layout !== \"compact\" && <Splitter controlsId={listId} />}\n </>\n );\n const rest = {\n id: listId,\n \"aria-label\": \"Conversations\",\n \"data-chat-list\": \"\",\n className: listClass,\n ...props,\n };\n if (!swap) {\n return <aside {...rest}>{body}</aside>;\n }\n return (\n <SwapPane\n as=\"aside\"\n show={pane === \"list\"}\n swapped={swapped}\n direction={direction}\n reduceMotion={reduceMotion}\n {...rest}\n >\n {body}\n </SwapPane>\n );\n}\n\n/**\n * The drag between the panes — a focusable separator. Hidden in\n * `compact`, and in `auto` while the frame is narrow.\n */\nfunction Splitter({ controlsId }: { controlsId: string }) {\n const { layout, listWidth, frameWidth, resizeList, rootRef } =\n useChat(\"Splitter\");\n const drag = useRef<{ x: number; width: number } | null>(null);\n\n const onPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n if (event.button !== 0) return;\n event.currentTarget.setPointerCapture?.(event.pointerId);\n drag.current = { x: event.clientX, width: listWidth };\n };\n\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n const start = drag.current;\n if (start == null) return;\n const root = rootRef.current;\n const rtl = root != null && getComputedStyle(root).direction === \"rtl\";\n const delta = (event.clientX - start.x) * (rtl ? -1 : 1);\n resizeList(start.width + delta);\n };\n\n const onPointerUp = () => {\n drag.current = null;\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const root = rootRef.current;\n const rtl = root != null && getComputedStyle(root).direction === \"rtl\";\n const shrink = rtl ? \"ArrowRight\" : \"ArrowLeft\";\n const grow = rtl ? \"ArrowLeft\" : \"ArrowRight\";\n const step = event.shiftKey ? SPLIT_STEP_PX * 2 : SPLIT_STEP_PX;\n if (event.key === shrink) {\n event.preventDefault();\n resizeList(listWidth - step);\n } else if (event.key === grow) {\n event.preventDefault();\n resizeList(listWidth + step);\n } else if (event.key === \"Home\") {\n event.preventDefault();\n resizeList(LIST_MIN_PX);\n } else if (event.key === \"End\") {\n event.preventDefault();\n const frame = root?.clientWidth ?? 0;\n if (frame > 0) resizeList(frame - THREAD_MIN_PX);\n }\n };\n\n const valueMax =\n frameWidth > 0\n ? Math.max(LIST_MIN_PX, frameWidth - THREAD_MIN_PX)\n : listWidth;\n\n return (\n <div\n // WAI-ARIA window splitter: a focusable separator with a value. An\n // `hr` can neither take focus nor carry the value attributes.\n // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label=\"Resize conversation list\"\n aria-controls={controlsId}\n aria-valuenow={listWidth}\n aria-valuemin={LIST_MIN_PX}\n aria-valuemax={valueMax}\n aria-valuetext={`${listWidth} pixels`}\n tabIndex={0}\n data-chat-splitter=\"\"\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n onKeyDown={onKeyDown}\n className={cn(\n \"absolute inset-y-0 -right-3 z-10 w-6 cursor-col-resize touch-none select-none\",\n \"outline-pho-brand focus-visible:outline-2 focus-visible:-outline-offset-2\",\n \"after:absolute after:inset-y-0 after:left-1/2 after:w-px after:-translate-x-1/2 after:bg-transparent\",\n \"[@media(hover:hover)]:hover:after:bg-pho-brand focus-visible:after:bg-pho-brand\",\n layout === \"auto\" && \"@max-2xl:hidden\",\n )}\n />\n );\n}\n\nexport interface ChatSearchProps extends Omit<\n InputProps,\n \"size\" | \"icon\" | \"label\" | \"hint\" | \"labelTrailing\"\n> {}\n\n/** The search row pinned over the conversations — an `sm` `Input`. */\nfunction Search({\n className,\n placeholder = \"Search\",\n ...props\n}: ChatSearchProps) {\n return (\n <div data-chat-search=\"\" className={cn(\"p-3\", TOP_BAR, className)}>\n <Input\n size=\"sm\"\n icon={IconSearch}\n placeholder={placeholder}\n aria-label=\"Search conversations\"\n autoComplete=\"off\"\n spellCheck={false}\n {...props}\n />\n </div>\n );\n}\n\n/**\n * The scrolling part of the list. Put a `ConversationList` in it — or a\n * `ConversationsLoading`, an `Empty` — and anything that belongs after\n * the rows (a load-older button).\n */\nfunction Conversations({\n className,\n children,\n ...props\n}: ComponentProps<\"div\">) {\n return (\n <div\n data-chat-conversations=\"\"\n className={cn(\"flex min-h-0 flex-1 flex-col\", className)}\n {...props}\n >\n <ScrollArea.Root className=\"min-h-0 flex-1\">\n <ScrollArea.Viewport>\n <ScrollArea.Content\n // Base UI sets `minWidth: fit-content` on Content; a long\n // title must truncate, not widen the pane.\n style={{ minWidth: 0 }}\n // Same horizontal rail as Sidebar sm (`px-3`): the selected\n // chip sits in the page wash instead of kissing the aside.\n className=\"flex min-h-full flex-col px-3 py-1\"\n >\n {children}\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n </div>\n );\n}\n\n/** The rows. */\nfunction ConversationList({ className, ...props }: ComponentProps<\"ul\">) {\n return (\n <ul\n data-chat-conversation-list=\"\"\n // list-none/m-0/p-0 shield the rows from host prose styles.\n className={cn(\"m-0 flex list-none flex-col gap-0.5 *:m-0\", className)}\n {...props}\n />\n );\n}\n\n/* ------------------------------ conversation ---------------------------- */\n\n/**\n * DOM handlers whose React signatures clash with Motion's gesture props.\n * Same omit list as `Button` — rows render through `motion.*`.\n */\ninterface ConversationBaseProps {\n /** Who — a number, a name, the members of a group. */\n title: ReactNode;\n /** When — the page's relative time (`2d ago`), trailing. */\n time?: ReactNode;\n /** The latest message, one truncated line. */\n preview?: ReactNode;\n /** Replace the default avatar (a person, or people for a `group`). */\n avatar?: ReactNode;\n /** A group conversation — the default avatar shows people. */\n group?: boolean;\n /** The open conversation. */\n active?: boolean;\n className?: string;\n}\n\nexport interface ChatConversationLinkProps\n extends\n ConversationBaseProps,\n Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n keyof ConversationBaseProps | MotionHandlerConflicts\n > {\n /** Destination — rendered through the host's `LinkProvider`. */\n href: string;\n}\n\nexport interface ChatConversationButtonProps\n extends\n ConversationBaseProps,\n Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n keyof ConversationBaseProps | MotionHandlerConflicts\n > {\n href?: undefined;\n}\n\nexport type ChatConversationProps =\n ChatConversationLinkProps | ChatConversationButtonProps;\n\n/** The row at rest, on hover, and while open — one pointer target. */\nconst CONVERSATION_ROW =\n \"outline-pho-brand rounded-base flex w-full cursor-pointer items-center gap-3 px-2 py-2.5 text-left transition-colors focus-visible:outline-2 focus-visible:-outline-offset-1\";\n/**\n * Open row — same chip as `Sidebar.Item` current (`aria-current=page`).\n * Weight lives on the title span, not here: time and preview stay Regular.\n */\nconst CONVERSATION_ROW_ACTIVE =\n \"bg-pho-primary text-pho-primary ring-pho-secondary ring-1 ring-inset *:data-icon:text-pho-primary\";\nconst CONVERSATION_ROW_INACTIVE = \"hover:bg-pho-ghost-hover\";\n\nconst CONVERSATION_PRESS = {\n initial: false as const,\n whileTap: { scale: PRESS_SCALE_ROW },\n transition: SPRING_PRESS,\n};\n\n/**\n * One conversation — a link when `href` is given (through the host's\n * `LinkProvider`), otherwise a button. Opening it in a compact layout\n * brings the thread up.\n */\nfunction Conversation({\n title,\n time,\n preview,\n avatar,\n group,\n active,\n className,\n href,\n onClick,\n ...rest\n}: ChatConversationProps) {\n const { layout, setPane } = useChat(\"Conversation\");\n const Link = useLinkComponent();\n // Same bridge as `Sidebar.Item` — host `LinkProvider` + Motion press.\n const MotionLink = useMemo(\n () =>\n motion.create(Link as unknown as ComponentType<Record<string, unknown>>),\n [Link],\n );\n const rowClass = cn(\n CONVERSATION_ROW,\n active ? CONVERSATION_ROW_ACTIVE : CONVERSATION_ROW_INACTIVE,\n className,\n );\n const open = () => {\n if (layout !== \"default\") setPane(\"thread\");\n };\n const body = (\n <>\n {avatar ?? (\n <Avatar.Root size=\"sm\">\n <Avatar.Fallback>\n {group ? (\n <IconUsers className=\"size-4\" aria-hidden />\n ) : (\n <IconUser className=\"size-4\" aria-hidden />\n )}\n </Avatar.Fallback>\n </Avatar.Root>\n )}\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex items-baseline justify-between gap-2\">\n <span className=\"text-pho-primary min-w-0 truncate text-base font-medium\">\n {title}\n </span>\n {time != null && (\n <span className=\"text-pho-description shrink-0 text-xs font-normal whitespace-nowrap tabular-nums\">\n {time}\n </span>\n )}\n </span>\n {preview != null && (\n <span className=\"text-pho-description mt-0.5 block min-w-0 truncate text-xs font-normal\">\n {preview}\n </span>\n )}\n </span>\n </>\n );\n\n if (href !== undefined) {\n return (\n <li>\n <MotionLink\n href={href}\n aria-current={active ? \"page\" : undefined}\n {...(rest as AnchorHTMLAttributes<HTMLAnchorElement>)}\n onClick={(event: React.MouseEvent<HTMLAnchorElement>) => {\n (onClick as AnchorHTMLAttributes<HTMLAnchorElement>[\"onClick\"])?.(\n event,\n );\n if (!event.defaultPrevented) open();\n }}\n className={rowClass}\n {...CONVERSATION_PRESS}\n >\n {body}\n </MotionLink>\n </li>\n );\n }\n\n return (\n <li>\n <motion.button\n type=\"button\"\n aria-current={active ? \"true\" : undefined}\n {...(rest as Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n MotionHandlerConflicts\n >)}\n onClick={(event) => {\n (onClick as ButtonHTMLAttributes<HTMLButtonElement>[\"onClick\"])?.(\n event,\n );\n if (!event.defaultPrevented) open();\n }}\n className={rowClass}\n {...CONVERSATION_PRESS}\n >\n {body}\n </motion.button>\n </li>\n );\n}\n\n/* -------------------------------- thread -------------------------------- */\n\n/** The right pane — header, messages, and the docked footer, on the card. */\nfunction Thread({ className, children, ...props }: ComponentProps<\"section\">) {\n const { layout, pane, direction, swap, swapped } = useChat(\"Thread\");\n const reduceMotion = useReducedMotion();\n const threadClass = cn(\n \"bg-pho-primary flex min-h-0 flex-1 flex-col\",\n layout === \"default\" && \"min-w-80\",\n layout === \"compact\" && \"min-w-0\",\n layout === \"auto\" && \"min-w-0 @2xl:min-w-80\",\n !swap && layout === \"auto\" && pane === \"list\" && \"@max-2xl:hidden\",\n className,\n );\n if (!swap) {\n return (\n <section\n aria-label=\"Conversation\"\n data-chat-thread=\"\"\n className={threadClass}\n {...props}\n >\n {children}\n </section>\n );\n }\n return (\n <SwapPane\n as=\"section\"\n show={pane === \"thread\"}\n swapped={swapped}\n direction={direction}\n reduceMotion={reduceMotion}\n aria-label=\"Conversation\"\n data-chat-thread=\"\"\n className={threadClass}\n {...props}\n >\n {children}\n </SwapPane>\n );\n}\n\nexport interface ChatHeaderProps extends ComponentProps<\"header\"> {\n /** The other side's avatar — an `Avatar.Root`. */\n avatar?: ReactNode;\n /** Controls at the trailing edge — a details button, a menu. */\n actions?: ReactNode;\n /** The back button's accessible name. @default \"Back to conversations\" */\n backLabel?: string;\n}\n\n/**\n * Who the thread is with. Children are a `Title` and a `Description`.\n * In a compact layout a back button leads the row; `auto` shows it only\n * while the frame is narrow.\n */\nfunction Header({\n avatar,\n actions,\n backLabel = \"Back to conversations\",\n className,\n children,\n ...props\n}: ChatHeaderProps) {\n const { layout, setPane } = useChat(\"Header\");\n return (\n <header\n data-chat-header=\"\"\n className={cn(\n \"flex shrink-0 items-center gap-3 px-4 py-1.5\",\n TOP_BAR,\n className,\n )}\n {...props}\n >\n {layout !== \"default\" && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n shape=\"circle\"\n svgOnly\n aria-label={backLabel}\n data-chat-back=\"\"\n className={cn(\"-ml-1 shrink-0\", layout === \"auto\" && \"@2xl:hidden\")}\n onClick={() => setPane(\"list\")}\n >\n <IconArrowLeft />\n </Button>\n )}\n {avatar}\n <div className=\"flex min-w-0 flex-1 flex-col\">{children}</div>\n {actions != null && (\n <div className=\"flex shrink-0 items-center gap-1\">{actions}</div>\n )}\n </header>\n );\n}\n\n/** The other side's name. Inline extras (a copy button, a badge) sit after it. */\nfunction Title({ className, children, ...props }: ComponentProps<\"h2\">) {\n return (\n <h2\n data-chat-title=\"\"\n className={cn(\n \"text-pho-primary m-0 flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 overflow-visible text-base font-medium\",\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n );\n}\n\n/** One line under the title — from whom, a status. */\nfunction Description({ className, ...props }: ComponentProps<\"p\">) {\n return (\n <p\n data-chat-description=\"\"\n className={cn(\n \"text-pho-description m-0 min-w-0 truncate text-xs\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/* ------------------------------- messages ------------------------------- */\n\n/** Within this many px of the bottom the pane counts as pinned. */\nconst PIN_SLACK_PX = 40;\n\nexport interface ChatMessagesProps extends ComponentProps<\"div\"> {\n /** Earlier pages exist — a button at the top asks for them. */\n hasEarlier?: boolean;\n /** The earlier page is on its way. */\n loadingEarlier?: boolean;\n /** Ask for the page before the first message shown. */\n onLoadEarlier?: () => void;\n /** The button's label. @default \"Load earlier messages\" */\n earlierLabel?: ReactNode;\n}\n\n/**\n * The messages, oldest to newest, on the thread surface. The pane starts at\n * the bottom and stays there as messages arrive unless the reader has\n * scrolled up; an earlier page keeps what they were reading in place.\n * Children are `Message` rows and `Divider`s.\n */\nfunction Messages({\n hasEarlier = false,\n loadingEarlier = false,\n onLoadEarlier,\n earlierLabel = \"Load earlier messages\",\n className,\n children,\n ...props\n}: ChatMessagesProps) {\n const viewportRef = useRef<HTMLDivElement | null>(null);\n const contentRef = useRef<HTMLDivElement | null>(null);\n const pinned = useRef(true);\n const anchor = useRef<{ height: number; top: number } | null>(null);\n\n useIsoLayoutEffect(() => {\n const viewport = viewportRef.current;\n const content = contentRef.current;\n if (!viewport || !content) return;\n const settle = () => {\n const kept = anchor.current;\n if (kept) {\n anchor.current = null;\n viewport.scrollTop = viewport.scrollHeight - kept.height + kept.top;\n return;\n }\n if (pinned.current) viewport.scrollTop = viewport.scrollHeight;\n };\n settle();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(settle);\n observer.observe(content);\n observer.observe(viewport);\n return () => observer.disconnect();\n }, []);\n\n const onScroll = () => {\n const viewport = viewportRef.current;\n if (!viewport) return;\n pinned.current =\n viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight <\n PIN_SLACK_PX;\n };\n\n const loadEarlier = () => {\n const viewport = viewportRef.current;\n if (viewport) {\n anchor.current = {\n height: viewport.scrollHeight,\n top: viewport.scrollTop,\n };\n }\n pinned.current = false;\n onLoadEarlier?.();\n };\n\n return (\n <div\n data-chat-messages=\"\"\n className={cn(\n // Bubbles' focus and selected rings offset against the thread.\n \"flex min-h-0 flex-1 flex-col [--pho-bubble-backdrop:var(--background-color-pho-primary)]\",\n className,\n )}\n {...props}\n >\n <ScrollArea.Root className=\"min-h-0 flex-1\">\n <ScrollArea.Viewport ref={viewportRef} onScroll={onScroll}>\n <ScrollArea.Content\n ref={contentRef}\n style={{ minWidth: 0 }}\n className=\"flex min-h-full flex-col gap-1 p-4\"\n >\n {hasEarlier && (\n <div className=\"flex justify-center\">\n <Button\n variant=\"outlined\"\n size=\"sm\"\n loading={loadingEarlier}\n onClick={loadEarlier}\n >\n {earlierLabel}\n </Button>\n </div>\n )}\n {children}\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n </div>\n );\n}\n\n/** A centered caption in the thread — the day, \"Unread\". */\nfunction Divider({ className, children, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n data-chat-divider=\"\"\n className={cn(\"text-pho-description py-1 text-center text-xs\", className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n\n/* -------------------------------- footer -------------------------------- */\n\n/** The docked bar under the messages — usually a `Composer`. */\nfunction Footer({ className, ...props }: ComponentProps<\"footer\">) {\n return (\n <footer\n data-chat-footer=\"\"\n className={cn(\"shrink-0 px-4 py-3\", className)}\n {...props}\n />\n );\n}\n\n/** The draft box grows with the text up to this, then scrolls. */\nconst COMPOSER_MAX_HEIGHT_PX = 200;\n\nexport interface ChatComposerProps extends Omit<\n ComponentProps<\"form\">,\n \"onSubmit\" | \"prefix\" | \"children\"\n> {\n /** The draft. */\n value: string;\n onValueChange: (value: string) => void;\n /** Enter, or the send button. Not called while `sending` or with nothing to send. */\n onSend: () => void;\n placeholder?: string;\n /** The send is in flight — the button spins, the box waits. */\n sending?: boolean;\n disabled?: boolean;\n /**\n * There is something to send besides text (an attachment). By default\n * the send button wakes when the draft has a non-blank character.\n */\n canSend?: boolean;\n /** Controls at the start of the bottom row — an add-attachment button. */\n prefix?: ReactNode;\n /** A quiet line between `prefix` and the send button — a count, a size. */\n meta?: ReactNode;\n /** The send button's accessible name. @default \"Send\" */\n sendLabel?: string;\n /** Above the text — attachment thumbnails. */\n children?: ReactNode;\n /** The `<textarea>`. */\n textareaRef?: Ref<HTMLTextAreaElement>;\n}\n\n/**\n * The message box: text that grows with the draft, Enter to send and\n * Shift+Enter for a new line, one round send button. Attachments are the\n * page's: put their thumbnails in `children`, the button that adds them\n * in `prefix`, and flip `canSend` when they alone should send.\n */\nfunction Composer({\n value,\n onValueChange,\n onSend,\n placeholder = \"Message\",\n sending = false,\n disabled = false,\n canSend,\n prefix,\n meta,\n sendLabel = \"Send\",\n children,\n textareaRef,\n className,\n ...props\n}: ChatComposerProps) {\n const innerRef = useRef<HTMLTextAreaElement | null>(null);\n const ready = !sending && !disabled && (canSend ?? value.trim().length > 0);\n\n useIsoLayoutEffect(() => {\n const element = innerRef.current;\n if (!element) return;\n element.style.height = \"0px\";\n element.style.height = `${Math.min(element.scrollHeight, COMPOSER_MAX_HEIGHT_PX)}px`;\n }, [value]);\n\n const submit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n if (ready) onSend();\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n if (\n event.key === \"Enter\" &&\n !event.shiftKey &&\n !event.nativeEvent.isComposing\n ) {\n event.preventDefault();\n if (ready) onSend();\n }\n };\n\n return (\n <form\n aria-label=\"Message composer\"\n data-chat-composer=\"\"\n onSubmit={submit}\n className={cn(\n // The field surface, as `Input`: hairline at rest, brand ring while\n // anything inside has focus.\n \"rounded-base bg-pho-primary ring-pho-primary focus-within:ring-pho-brand ring-1 transition-shadow duration-100 ease-linear ring-inset focus-within:ring-2\",\n disabled && \"opacity-50\",\n className,\n )}\n {...props}\n >\n {children}\n <textarea\n ref={(node) => {\n innerRef.current = node;\n if (typeof textareaRef === \"function\") textareaRef(node);\n else if (textareaRef) {\n (textareaRef as { current: HTMLTextAreaElement | null }).current =\n node;\n }\n }}\n value={value}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={onKeyDown}\n rows={1}\n placeholder={placeholder}\n aria-label=\"Message\"\n disabled={disabled}\n // In flight the box holds its text but stays focusable — `disabled`\n // would drop focus mid-send; `ready` already blocks a second send.\n readOnly={sending}\n className=\"text-pho-primary placeholder:text-pho-placeholder m-0 block w-full resize-none bg-transparent px-4 pt-3 pb-1 text-base outline-none disabled:cursor-not-allowed\"\n />\n <div className=\"flex items-center gap-2 px-2 pb-2\">\n {prefix}\n <p className=\"text-pho-description m-0 min-w-0 flex-1 truncate text-xs\">\n {meta}\n </p>\n <Button\n type=\"submit\"\n size=\"sm\"\n shape=\"circle\"\n svgOnly\n aria-label={sendLabel}\n disabled={!ready}\n loading={sending}\n >\n <IconArrowUp />\n </Button>\n </div>\n </form>\n );\n}\n\n/* --------------------------------- states ------------------------------- */\n\nexport interface ChatEmptyProps extends StatusViewProps {}\n\n/**\n * The standing-in view for either pane — no conversations, no thread\n * chosen, nothing said yet. `StatusView` at card size, centered in\n * whatever room the pane has.\n */\nfunction Empty({ className, size = \"sm\", ...props }: ChatEmptyProps) {\n return (\n <div\n data-chat-empty=\"\"\n className={cn(\n \"flex flex-1 flex-col items-center justify-center px-6 py-8\",\n className,\n )}\n >\n <StatusView size={size} {...props} />\n </div>\n );\n}\n\n/** Bones in the shape of conversation rows — avatar, who, when, preview. */\nfunction ConversationsLoading({ rows = 5 }: { rows?: number }) {\n return (\n <div\n aria-hidden\n data-chat-conversations-loading=\"\"\n className=\"flex flex-col gap-0.5\"\n >\n {Array.from({ length: rows }, (_, row) => (\n <div key={row} className=\"flex items-center gap-3 px-2 py-2.5\">\n <Skeleton className=\"size-8 shrink-0 rounded-full\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <Skeleton className=\"h-3.5 w-32\" />\n <Skeleton className=\"h-2.5 w-8\" />\n </div>\n <Skeleton className=\"mt-2 h-2.5 w-44\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\n/** Bones in a thread's shape — theirs left, ours right. */\nfunction MessagesLoading() {\n return (\n <div\n aria-hidden\n data-chat-messages-loading=\"\"\n className=\"flex flex-col gap-3\"\n >\n <Skeleton className=\"rounded-base h-10 w-1/2 self-start\" />\n <Skeleton className=\"rounded-base h-10 w-2/5 self-end\" />\n <Skeleton className=\"rounded-base h-16 w-3/5 self-start\" />\n </div>\n );\n}\n\n/**\n * The composed inbox. Assemble the two panes and fill them:\n *\n * ```tsx\n * <Chat.Root layout=\"auto\" className=\"h-[32rem]\">\n * <Chat.List>\n * <Chat.Search value={query} onChange={…} />\n * <Chat.Conversations>\n * <Chat.ConversationList>\n * <Chat.Conversation title=\"+1 (315) 997-8332\" time=\"2d ago\" preview=\"…\" active />\n * </Chat.ConversationList>\n * </Chat.Conversations>\n * </Chat.List>\n * <Chat.Thread>\n * <Chat.Header avatar={<Avatar.Root size=\"md\">…</Avatar.Root>}>\n * <Chat.Title>+1 (315) 997-8332</Chat.Title>\n * <Chat.Description>From …</Chat.Description>\n * </Chat.Header>\n * <Chat.Messages>\n * <Chat.Divider>September 12</Chat.Divider>\n * <Message.Root>…</Message.Root>\n * </Chat.Messages>\n * <Chat.Footer>\n * <Chat.Composer value={draft} onValueChange={setDraft} onSend={send} />\n * </Chat.Footer>\n * </Chat.Thread>\n * </Chat.Root>\n * ```\n */\nexport const Chat = {\n Root,\n List,\n Search,\n Conversations,\n ConversationList,\n Conversation,\n Thread,\n Header,\n Title,\n Description,\n Messages,\n Divider,\n Footer,\n Composer,\n Empty,\n ConversationsLoading,\n MessagesLoading,\n};\n"],"x_google_ignoreList":[0,1,2,3],"mappings":"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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { n as a } from "./use-press-pulse-IbNstUT0.js";
|
|
3
|
-
var s = "group outline-pho-brand flex flex-1 cursor-pointer items-start gap-2.5 rounded-base p-3 text-base text-pho-secondary ring-1 ring-pho-primary ring-inset transition-[box-shadow,background-color] duration-150 ease-out select-none hover:bg-pho-ghost-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:bg-transparent data-[checked]:ring-2 data-[checked]:ring-pho-brand has-[[data-checked]]:ring-2 has-[[data-checked]]:ring-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2 has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2", o = "flex-col gap-1.5", r = 0.98, t = a, i = {
|
|
4
|
-
type: "spring",
|
|
5
|
-
stiffness: 500,
|
|
6
|
-
damping: 30,
|
|
7
|
-
mass: 0.5
|
|
8
|
-
};
|
|
9
|
-
export {
|
|
10
|
-
i as a,
|
|
11
|
-
o as i,
|
|
12
|
-
r as n,
|
|
13
|
-
t as r,
|
|
14
|
-
s as t
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
//# sourceMappingURL=choice-card-BVNP1NB6.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"choice-card-BVNP1NB6.js","names":[],"sources":["../../src/utils/choice-card.ts"],"sourcesContent":["import type { Transition } from \"motion/react\";\nimport { CONTROL_PRESS_SPRING } from \"./use-press-pulse\";\n\n/**\n * Shared surface for `RadioCard` / `CheckboxCard` — a bordered, selectable\n * tile. Applied to the radio/checkbox root itself so the whole tile is the\n * hit target. Hover fills (`bg-pho-ghost-hover`); selected uses the brand\n * ring. Press feedback lives on this surface (see `usePressPulse`).\n */\nexport const CHOICE_CARD_BASE =\n \"group outline-pho-brand flex flex-1 cursor-pointer items-start gap-2.5 rounded-base p-3 text-base text-pho-secondary ring-1 ring-pho-primary ring-inset transition-[box-shadow,background-color] duration-150 ease-out select-none hover:bg-pho-ghost-hover data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:bg-transparent data-[checked]:ring-2 data-[checked]:ring-pho-brand has-[[data-checked]]:ring-2 has-[[data-checked]]:ring-pho-brand focus-visible:outline-2 focus-visible:outline-offset-2 has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2\";\n\n/** Stacked icon above the copy — tighter than the checkbox/radio row gap. */\nexport const CHOICE_CARD_WITH_ICON = \"flex-col gap-1.5\";\n\n/** Same press as Select's default trigger — field-sized, not Button's whileTap. */\nexport const CHOICE_CARD_PRESS_SCALE = 0.98;\nexport const CHOICE_CARD_PRESS_TRANSITION: Transition = CONTROL_PRESS_SPRING;\n\n/** Selection pop for a radio dot / checkbox glyph — quick and slightly bouncy. */\nexport const CHOICE_INDICATOR_POP_TRANSITION: Transition = {\n type: \"spring\",\n stiffness: 500,\n damping: 30,\n mass: 0.5,\n};\n"],"mappings":";;AASA,IAAa,IACX,klBAGW,IAAwB,oBAGxB,IAA0B,MAC1B,IAA2C,GAG3C,IAA8C;AAAA,EACzD,MAAM;AAAA,EACN,WAAW;AAAA,EACX,SAAS;AAAA,EACT,MAAM;AACR"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-MPvem7yV.js","names":[],"sources":["../../src/components/dialog/dialog.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type ElementType,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n} from \"react\";\nimport { Dialog as BaseDialog } from \"@base-ui/react/dialog\";\nimport { AnimatedHeight } from \"../../utils/animated-height\";\nimport { cn } from \"../../utils/cn\";\nimport { ScrollArea } from \"../scroll-area\";\nimport { Button, type ButtonProps } from \"../button/button\";\nimport { CloseButton } from \"../button/close-button\";\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\n/* ========================== Async pending context ========================== */\n\n/** Imperative actions exposed by Base UI's `actionsRef`. */\ninterface RootActions {\n unmount: () => void;\n close: () => void;\n}\n\ninterface DialogPendingContextValue {\n /** True while a `Dialog.Action` promise is in flight. */\n pending: boolean;\n beginPending: () => void;\n endPending: () => void;\n /** Close the dialog imperatively (used by `Dialog.Action` on resolve). */\n close: () => void;\n}\n\nconst DialogPendingContext = createContext<DialogPendingContextValue | null>(\n null,\n);\n\n/**\n * Whether the surrounding dialog has a `Dialog.Action` promise in flight —\n * use it to disable secondary actions (Cancel etc.) while work is pending.\n * Returns `false` outside a `Dialog.Root`.\n */\nexport function useDialogPending(): boolean {\n return useContext(DialogPendingContext)?.pending ?? false;\n}\n\ntype RootProps = ComponentProps<typeof BaseDialog.Root>;\n\n/**\n * `Dialog.Root` with async awareness: while a `Dialog.Action` promise is\n * pending, every close request (outside press, Escape, `Dialog.Close`) is\n * cancelled so the dialog stays open until the work settles. Props pass\n * through to Base UI's `Dialog.Root` unchanged.\n */\nfunction Root({ onOpenChange, actionsRef, ...props }: RootProps) {\n const [pending, setPending] = useState(false);\n // Guard reads a ref so a resolve → close() in the same tick isn't blocked\n // by a not-yet-flushed state update.\n const pendingRef = useRef(false);\n const internalActionsRef = useRef<RootActions | null>(null);\n\n // Keep a caller-supplied actionsRef working alongside our internal one.\n useEffect(() => {\n if (!actionsRef) return;\n actionsRef.current = internalActionsRef.current;\n return () => {\n actionsRef.current = null;\n };\n }, [actionsRef]);\n\n const handleOpenChange = useCallback<NonNullable<RootProps[\"onOpenChange\"]>>(\n (open, eventDetails) => {\n if (!open && pendingRef.current) {\n eventDetails.cancel();\n return;\n }\n onOpenChange?.(open, eventDetails);\n },\n [onOpenChange],\n );\n\n const contextValue = useMemo<DialogPendingContextValue>(\n () => ({\n pending,\n beginPending: () => {\n pendingRef.current = true;\n setPending(true);\n },\n endPending: () => {\n pendingRef.current = false;\n setPending(false);\n },\n close: () => internalActionsRef.current?.close(),\n }),\n [pending],\n );\n\n return (\n <DialogPendingContext.Provider value={contextValue}>\n <BaseDialog.Root\n actionsRef={internalActionsRef}\n onOpenChange={handleOpenChange}\n {...props}\n />\n </DialogPendingContext.Provider>\n );\n}\n\nconst Trigger = BaseDialog.Trigger;\nconst Portal = BaseDialog.Portal;\nconst Close = BaseDialog.Close;\n\n/* ============================== Dialog.Action ============================== */\n\nexport interface DialogActionProps extends Omit<ButtonProps, \"onClick\"> {\n /**\n * Confirm handler. Return a promise to keep the dialog open while it runs:\n * the button shows `loading`, all dismissal is locked, and the dialog\n * closes when the promise resolves. On rejection the dialog stays open —\n * surface errors inside the handler. A non-promise return closes\n * immediately, like `Dialog.Close`.\n */\n onClick?: (\n event: ReactMouseEvent<HTMLButtonElement>,\n ) => void | Promise<unknown>;\n}\n\nfunction isThenable(value: unknown): value is Promise<unknown> {\n return (\n value != null && typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/**\n * The confirm button of an action row, with native promise support — a\n * `Button` that runs its (possibly async) `onClick` and closes the dialog\n * when the work settles successfully.\n */\nfunction Action({ onClick, loading, disabled, ...props }: DialogActionProps) {\n const pendingContext = useContext(DialogPendingContext);\n const [busy, setBusy] = useState(false);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n function handleClick(event: ReactMouseEvent<HTMLButtonElement>) {\n if (busy || loading) return;\n const result = onClick?.(event);\n if (!isThenable(result)) {\n pendingContext?.close();\n return;\n }\n setBusy(true);\n pendingContext?.beginPending();\n result.then(\n () => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n pendingContext?.close();\n },\n (error: unknown) => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV !== \"production\"\n ) {\n console.error(\"Dialog.Action: async onClick rejected —\", error);\n }\n },\n );\n }\n\n const inert = busy || loading;\n return (\n <Button\n {...props}\n disabled={disabled || inert}\n loading={inert}\n onClick={handleClick}\n />\n );\n}\n\nfunction Backdrop({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Backdrop>) {\n return (\n <BaseDialog.Backdrop\n className={cn(\n \"bg-pho-overlay fixed inset-0 z-50 transition-opacity duration-200 ease-out\",\n \"data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Popup({ className, ...props }: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n // Floating layer: bg-pho-primary + border-pho-secondary hairline, elevation kept.\n \"border-pho-secondary bg-pho-primary shadow-pho-xl fixed top-1/2 left-1/2 z-50 w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg border outline-none\",\n // Global height cap — the inset panel's footprint (inset-4 /\n // sm:inset-8). A flex column so the body region can shrink and\n // scroll while header and actions stay pinned.\n \"flex max-h-[calc(100dvh-2rem)] flex-col sm:max-h-[calc(100dvh-4rem)]\",\n // Opacity + scale only — leave translate centering alone (no transition-all).\n \"transition-[opacity,scale] duration-200 ease-out\",\n \"data-[starting-style]:scale-95 data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:duration-150\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Title({ className, ...props }: StyledProps<typeof BaseDialog.Title>) {\n return (\n <BaseDialog.Title\n className={cn(\n \"text-pho-primary font-display text-display-sm font-medium text-balance\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Description({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Description>) {\n return (\n <BaseDialog.Description\n className={cn(\n \"text-pho-description text-display-xs font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Header icon chrome: secondary ink, a hair of extra air before the title.\n * Panel dialogs use 32px (`size-8`); fullscreen gates step up to 48px\n * (`size-12`) so the glyph reads at viewport scale.\n */\nfunction DialogHeaderIcon({\n children,\n size = \"md\",\n}: {\n children: ReactNode;\n size?: \"md\" | \"lg\";\n}) {\n return (\n <span\n aria-hidden\n className={cn(\n \"text-pho-secondary mb-1\",\n size === \"lg\" ? \"[&>svg]:size-12\" : \"[&>svg]:size-8\",\n )}\n >\n {children}\n </span>\n );\n}\n\ninterface ContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /**\n * Decorative icon above the title — typically a Tabler outline icon.\n * Rendered aria-hidden in secondary ink at 32px (`[&>svg]:size-8`). Pass a\n * styled node to override the ink; the size is owned by the slot.\n */\n icon?: ReactNode;\n /** Heading rendered in the panel header. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Consequence bullets rendered as a list at the top of the body — one item\n * per outcome (what is deleted, what survives, who loses access). Use on\n * destructive confirms where the one-line description undersells the\n * impact; keep each item to a single short sentence. Wrap the load-bearing\n * figure in `<strong>` (\"<strong>3 members</strong> lose access\") — the\n * list styles it (secondary ink, medium weight); no classes needed.\n */\n consequences?: ReactNode[];\n /**\n * Final cautionary line under `consequences` — error ink at description\n * size (e.g. \"It cannot be undone. Please be certain.\"). Reserve it for\n * irreversible actions; keep it short.\n */\n warning?: ReactNode;\n /**\n * Footer action row (Cancel / Confirm, etc.). Iron rule: when `actions` is\n * set, the header close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Header close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Convenience panel: renders the portal, backdrop, and styled popup with an\n * optional header (title/description + close) and optional action row. For\n * full control, compose the parts directly (`Dialog.Portal` /\n * `Dialog.Backdrop` / `Dialog.Popup`).\n */\nfunction Content({\n icon,\n title,\n description,\n consequences,\n warning,\n actions,\n showClose = true,\n children,\n className,\n ...props\n}: ContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a header X.\n const showCloseButton = actions == null && showClose;\n const hasHeader = Boolean(icon || title || description || showCloseButton);\n const hasConsequences = consequences != null && consequences.length > 0;\n // The scrollable middle region — actions stay pinned below it.\n const hasScrollBody = hasConsequences || warning != null || children != null;\n\n return (\n <Portal>\n <Backdrop />\n <Popup className={className} {...props}>\n {hasHeader && (\n <div className=\"flex shrink-0 flex-col gap-2 px-6 pt-6\">\n {icon && <DialogHeaderIcon>{icon}</DialogHeaderIcon>}\n {(title || showCloseButton) && (\n // Title row height = title only. Close is out of flow, centered\n // on the row, and may paint outside it (no clip, no stretch).\n <div className=\"relative\">\n {title ? (\n <Title className={showCloseButton ? \"pr-12\" : undefined}>\n {title}\n </Title>\n ) : (\n <div className=\"h-[1.625rem]\" aria-hidden=\"true\" />\n )}\n {showCloseButton && (\n <Close\n render={\n <CloseButton className=\"absolute top-1/2 right-0 z-10 -translate-y-1/2\" />\n }\n />\n )}\n </div>\n )}\n {description && <Description>{description}</Description>}\n </div>\n )}\n {hasScrollBody && (\n <ScrollArea.Root className=\"min-h-0 flex-1\">\n <ScrollArea.Viewport>\n <ScrollArea.Content className=\"flex flex-col gap-5 px-6 py-5\">\n {hasConsequences && (\n <ul className=\"text-pho-description text-md [&_strong]:text-pho-secondary space-y-1 [&_strong]:font-medium\">\n {consequences.map((item, index) => (\n // Hand-drawn marker: a 4px dot on the first line's center —\n // quieter than the browser disc, ink tracks the text.\n <li\n key={index}\n className=\"relative pl-4 before:absolute before:top-2.5 before:left-1 before:size-1 before:rounded-full before:bg-current\"\n >\n {item}\n </li>\n ))}\n </ul>\n )}\n {warning != null && (\n <p className=\"text-pho-error text-display-xs font-medium\">\n {warning}\n </p>\n )}\n {children}\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n )}\n {actions != null && (\n <div\n className={cn(\n \"flex shrink-0 items-center justify-end gap-2 px-6 pb-5\",\n !hasScrollBody && \"pt-5\",\n )}\n >\n {actions}\n </div>\n )}\n </Popup>\n </Portal>\n );\n}\n\n/* =========================== Dialog.InsetContent =========================== */\n\n/**\n * Near-fullscreen popup — the viewport minus a breathing ring, floating over\n * a backdrop (the page stays visible through the gap, so it dims like any\n * floating layer). Still a card: border, elevation, rounded corners; the\n * scale gesture stays but shrinks to 98% — at this size 95% reads like a jump.\n */\nfunction InsetPopup({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n \"border-pho-secondary bg-pho-primary shadow-pho-xl fixed inset-4 z-50 flex flex-col overflow-hidden rounded-lg border outline-none sm:inset-8\",\n \"transition-[opacity,scale] duration-200 ease-out\",\n \"data-[starting-style]:scale-[0.98] data-[starting-style]:opacity-0\",\n \"data-[ending-style]:scale-[0.98] data-[ending-style]:opacity-0 data-[ending-style]:duration-150\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface InsetContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /** Decorative icon above the title — same treatment as `Content`. */\n icon?: ReactNode;\n /** Heading rendered in the panel header. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Bottom action row. Iron rule as `Content`: when `actions` is set, the\n * header close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Header close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Convenience near-fullscreen panel: header pinned on top, body filling and\n * scrolling on its own, optional action row pinned at the bottom. Sits\n * between `Content` (a focused card) and `FullscreenContent` (a page\n * takeover): use it for roomy working surfaces — pickers, editors, previews —\n * that still want the page peeking through an edge.\n */\nfunction InsetContent({\n icon,\n title,\n description,\n actions,\n showClose = true,\n children,\n className,\n ...props\n}: InsetContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a header X.\n const showCloseButton = actions == null && showClose;\n const hasHeader = Boolean(icon || title || description || showCloseButton);\n\n return (\n <Portal>\n <Backdrop />\n <InsetPopup className={className} {...props}>\n {hasHeader && (\n <div className=\"flex shrink-0 flex-col gap-2 px-6 pt-6\">\n {icon && <DialogHeaderIcon>{icon}</DialogHeaderIcon>}\n {(title || showCloseButton) && (\n <div className=\"relative\">\n {title ? (\n <Title className={showCloseButton ? \"pr-12\" : undefined}>\n {title}\n </Title>\n ) : (\n <div className=\"h-[1.625rem]\" aria-hidden=\"true\" />\n )}\n {showCloseButton && (\n <Close\n render={\n <CloseButton className=\"absolute top-1/2 right-0 z-10 -translate-y-1/2\" />\n }\n />\n )}\n </div>\n )}\n {description && <Description>{description}</Description>}\n </div>\n )}\n <ScrollArea.Root className=\"min-h-0 flex-1\">\n <ScrollArea.Viewport>\n <ScrollArea.Content className=\"px-6 py-5\">\n {children}\n </ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n </ScrollArea.Root>\n {actions != null && (\n <div className=\"flex shrink-0 items-center justify-end gap-2 px-6 pb-5\">\n {actions}\n </div>\n )}\n </InsetPopup>\n </Portal>\n );\n}\n\n/* ========================= Dialog.FullscreenContent ======================== */\n\n/**\n * Full-viewport popup — a page-surface takeover instead of a floating card.\n * No backdrop: the popup itself is the layer. Fade only; scale is a floating-\n * card gesture and reads wrong at viewport size.\n */\nfunction FullscreenPopup({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n \"bg-pho-page fixed inset-0 z-50 overflow-y-auto outline-none\",\n \"transition-opacity duration-200 ease-out\",\n \"data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface FullscreenContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /**\n * Decorative icon above the title — same chrome as `Content`, but 48px\n * (`size-12`) for viewport-scale gates.\n */\n icon?: ReactNode;\n /** Heading of the takeover. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Action row under the body. Iron rule as `Content`: when `actions` is set,\n * the corner close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Corner close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n /**\n * Classes on the viewport-centering frame (the `min-h-full` flex host).\n * Use to drop the default optical `pb-20` when the stack grows (e.g. a\n * captcha) so true center stays put: `frameClassName=\"pb-6\"`.\n */\n frameClassName?: string;\n children?: ReactNode;\n}\n\n/**\n * Convenience full-screen panel: the whole viewport becomes the dialog, with\n * a centered column at the standalone-flow width (28rem — the same measure as\n * onboarding / invite cards). Column height follows its content through\n * `AnimatedHeight` (same spring as the Card shell), so step swaps — phone →\n * OTP → captcha — glide instead of jumping. Use for gates the visitor must\n * deal with before the page behind makes sense (e.g. binding a phone number);\n * prefer `Content` for everything conversational.\n */\nfunction FullscreenContent({\n icon,\n title,\n description,\n actions,\n showClose = true,\n frameClassName,\n children,\n className,\n ...props\n}: FullscreenContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a corner X.\n const showCloseButton = actions == null && showClose;\n\n return (\n <Portal>\n <FullscreenPopup className={className} {...props}>\n {showCloseButton && (\n <Close\n render={<CloseButton className=\"fixed top-4 right-4 z-10\" />}\n />\n )}\n {/* Default `pb-20` optically lifts the column above true center. */}\n <div\n className={cn(\n \"flex min-h-full items-center justify-center px-6 pt-6 pb-20\",\n frameClassName,\n )}\n >\n {/* Width stays on the outer host; AnimatedHeight measures the\n header + body stack and springs its own height on content\n changes. The action row sits below it, outside the clip: while\n the body grows the container is shorter than its content for a\n few frames, and a row inside it would be cut off at the bottom\n (a pressed \"Send code\" turning grey right as a captcha mounts).\n Outside, the row rides the spring instead. */}\n <div className=\"w-full max-w-md\">\n <AnimatedHeight className=\"flex flex-col gap-5\">\n {(icon || title || description) && (\n <div className=\"flex flex-col gap-2\">\n {icon && (\n <DialogHeaderIcon size=\"lg\">{icon}</DialogHeaderIcon>\n )}\n {title && <Title>{title}</Title>}\n {description && <Description>{description}</Description>}\n </div>\n )}\n {children}\n </AnimatedHeight>\n {actions != null && (\n <div className=\"mt-5 flex items-center justify-end gap-2\">\n {actions}\n </div>\n )}\n </div>\n </div>\n </FullscreenPopup>\n </Portal>\n );\n}\n\n/**\n * Modal dialog built on Base UI `Dialog`. Controlled or uncontrolled via\n * `Dialog.Root` (`open` / `onOpenChange` / `defaultOpen`). `Dialog.Action`\n * adds native promise support: an async confirm keeps the dialog open and\n * undismissable until the work resolves.\n */\nexport const Dialog = {\n Root,\n Trigger,\n Portal,\n Backdrop,\n Popup,\n InsetPopup,\n FullscreenPopup,\n Title,\n Description,\n Close,\n Action,\n Content,\n InsetContent,\n FullscreenContent,\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filter-bar-B-oYYBsU.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconPlus.mjs","../../src/components/filter-bar/filter-bar.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\": \"M12 5l0 14\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M5 12l14 0\", \"key\": \"svg-1\" }]];\nconst IconPlus = createReactComponent(\"outline\", \"plus\", \"Plus\", __iconNode);\n\nexport { __iconNode, IconPlus as default };\n//# sourceMappingURL=IconPlus.mjs.map\n","import {\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n type Ref,\n type RefObject,\n} from \"react\";\nimport { IconCheck, IconPlus, IconSearch, IconX } from \"@tabler/icons-react\";\nimport { Button } from \"../button\";\nimport { Command } from \"../command\";\nimport { InputGroup } from \"../input-group\";\nimport { Popover } from \"../popover\";\nimport { cn } from \"../../utils/cn\";\n\n/**\n * Filter Bar — the row that pins above a log list: a search field for an\n * id, then one chip per filter. A chip with nothing chosen reads\n * `+ Status`; with a value it reads `Status: Failed` and carries its own\n * clear. Each chip opens a small popover: a keyboard-first list of\n * options (with a search field past eight of them), or presets and a\n * from / to pair for a date range.\n *\n * Design notes:\n * - Fully controlled. The page owns `filters` and `search` and hands\n * them back changed; the bar keeps no state but which popover is open.\n * That keeps the query in one place (the URL, a store) and lets the\n * list refetch from it.\n * - Chips are real buttons (the trigger, and the clear beside it), so\n * the bar is one tab stop per control and Escape closes a popover\n * back onto its chip.\n * - No scroll container of its own: chips wrap. `sticky` pins it to the\n * top of the nearest scroll pane on the surface it sits on.\n */\n\nexport interface FilterOption {\n value: string;\n label: string;\n /**\n * Rich option row (a badge, mono path). Search and the set chip still\n * use `label` and `value` strings.\n */\n title?: ReactNode;\n}\n\ninterface FilterDefinitionBase {\n /** The key in `filters` this chip reads and writes. */\n key: string;\n /** The chip's word — \"Status\", \"Event type\". Sentence case. */\n label: string;\n}\n\nexport interface SelectFilterDefinition extends FilterDefinitionBase {\n type?: \"select\";\n options: readonly FilterOption[];\n /** Several values at once (`string[]`); one at a time by default. */\n multiple?: boolean;\n /**\n * A search field above the options. On by default past eight options,\n * off below; say so to override.\n */\n searchable?: boolean;\n /** The search field's placeholder. @default \"Search\" */\n searchPlaceholder?: string;\n}\n\n/** A relative preset for a date-range filter — \"Last 7 days\" is 168 hours. */\nexport interface DateRangePreset {\n label: string;\n hours: number;\n}\n\nexport interface DateRangeFilterDefinition extends FilterDefinitionBase {\n type: \"date-range\";\n /** The relative presets listed above the from / to pair. */\n presets?: readonly DateRangePreset[];\n}\n\nexport type FilterDefinition =\n SelectFilterDefinition | DateRangeFilterDefinition;\n\n/**\n * A date-range value. A preset stores an absolute ISO timestamp in `from`\n * (computed when chosen) and its label in `preset`; the from / to pair\n * stores plain `YYYY-MM-DD` dates. Either side may be open (`null`).\n */\nexport interface DateRangeValue {\n from: string | null;\n to: string | null;\n preset?: string;\n}\n\nexport type FilterValue = string | string[] | DateRangeValue;\n\n/** The page's filter state — one entry per definition key that is set. */\nexport type FilterValues = Record<string, FilterValue | undefined>;\n\n/** The relative presets a date-range chip lists when given none. */\nexport const FILTER_DATE_PRESETS: readonly DateRangePreset[] = [\n { label: \"Last hour\", hours: 1 },\n { label: \"Last 24 hours\", hours: 24 },\n { label: \"Last 7 days\", hours: 24 * 7 },\n { label: \"Last 30 days\", hours: 24 * 30 },\n];\n\n/** Past this many options a select chip shows a search field. */\nconst SEARCHABLE_PAST = 8;\n\n/** Whether a filter value counts as set — an empty string or list does not. */\nexport function isFilterSet(value: FilterValue | undefined): boolean {\n if (value == null) return false;\n if (typeof value === \"string\") return value !== \"\";\n if (Array.isArray(value)) return value.length > 0;\n return value.from != null || value.to != null;\n}\n\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction formatDay(value: string): string {\n // A plain date is a calendar day: format it in UTC so the day survives\n // every viewer timezone. A timestamp is a moment: format it locally.\n const dateOnly = DATE_ONLY.test(value);\n const date = new Date(dateOnly ? `${value}T00:00:00Z` : value);\n if (Number.isNaN(date.getTime())) return value;\n return new Intl.DateTimeFormat(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n ...(dateOnly ? { timeZone: \"UTC\" } : {}),\n }).format(date);\n}\n\n/** The words a set chip shows after its label. */\nexport function formatFilterValue(\n definition: FilterDefinition,\n value: FilterValue | undefined,\n): string {\n if (!isFilterSet(value) || value == null) return \"\";\n if (definition.type === \"date-range\") {\n const range = value as DateRangeValue;\n if (range.preset) return range.preset;\n if (range.from && range.to) {\n return `${formatDay(range.from)} to ${formatDay(range.to)}`;\n }\n if (range.from) return `From ${formatDay(range.from)}`;\n if (range.to) return `Until ${formatDay(range.to)}`;\n return \"\";\n }\n const labelOf = (item: string) =>\n definition.options.find((option) => option.value === item)?.label ?? item;\n if (Array.isArray(value)) return value.map(labelOf).join(\", \");\n return typeof value === \"string\" ? labelOf(value) : \"\";\n}\n\n/* --------------------------------- chips -------------------------------- */\n\nconst CHIP_TRIGGER =\n \"outline-pho-brand flex h-8 min-w-0 cursor-pointer items-center gap-1.5 rounded-full text-base transition-[color,background-color] duration-100 ease-linear focus-visible:outline-2 focus-visible:-outline-offset-2 [&>svg]:size-4 [&>svg]:shrink-0\";\n\nfunction FilterChip({\n definition,\n value,\n onChange,\n}: {\n definition: FilterDefinition;\n value: FilterValue | undefined;\n onChange: (next: FilterValue | undefined) => void;\n}) {\n const [open, setOpen] = useState(false);\n const focusRef = useRef<HTMLElement | null>(null);\n const set = isFilterSet(value);\n const display = formatFilterValue(definition, value);\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <span\n data-filter-chip={definition.key}\n data-set={set || undefined}\n className={cn(\n \"ring-pho-primary inline-flex max-w-full shrink-0 items-stretch rounded-full ring-1 ring-inset\",\n set ? \"bg-pho-secondary\" : \"bg-transparent\",\n )}\n >\n <Popover.Trigger\n aria-label={set ? undefined : `${definition.label} filter`}\n className={cn(\n CHIP_TRIGGER,\n \"hover:bg-pho-ghost-hover\",\n set ? \"pr-1.5 pl-3\" : \"pr-3 pl-2.5\",\n set ? \"rounded-r-none\" : \"\",\n )}\n >\n {set ? null : <IconPlus aria-hidden />}\n {set ? (\n <span className=\"flex min-w-0 items-baseline gap-1\">\n <span className=\"text-pho-description shrink-0\">\n {definition.label}:\n </span>\n <span className=\"text-pho-primary max-w-56 truncate font-medium\">\n {display}\n </span>\n </span>\n ) : (\n <span className=\"text-pho-secondary\">{definition.label}</span>\n )}\n </Popover.Trigger>\n {set ? (\n <button\n type=\"button\"\n aria-label={`Clear ${definition.label.toLowerCase()} filter`}\n onClick={() => onChange(undefined)}\n className={cn(\n CHIP_TRIGGER,\n \"text-pho-secondary hover:bg-pho-ghost-hover hover:text-pho-secondary-hover rounded-l-none pr-2.5 pl-1 [&>svg]:size-3.5\",\n )}\n >\n <IconX aria-hidden />\n </button>\n ) : null}\n </span>\n <Popover.Portal>\n <Popover.Positioner align=\"start\" sideOffset={6}>\n <Popover.Popup\n aria-label={`${definition.label} filter`}\n initialFocus={focusRef}\n className={cn(\n \"w-64 p-0\",\n definition.type === \"date-range\" && \"w-72\",\n )}\n >\n {definition.type === \"date-range\" ? (\n <DateRangePanel\n definition={definition}\n value={value as DateRangeValue | undefined}\n focusRef={focusRef}\n onChange={(next) => {\n onChange(next);\n if (next?.preset) setOpen(false);\n }}\n />\n ) : (\n <OptionsPanel\n definition={definition}\n value={value as string | string[] | undefined}\n focusRef={focusRef}\n onChange={(next) => {\n onChange(next);\n if (!definition.multiple) setOpen(false);\n }}\n />\n )}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\nfunction OptionsPanel({\n definition,\n value,\n focusRef,\n onChange,\n}: {\n definition: SelectFilterDefinition;\n value: string | string[] | undefined;\n focusRef: RefObject<HTMLElement | null>;\n onChange: (next: string | string[] | undefined) => void;\n}) {\n const [query, setQuery] = useState(\"\");\n const searchable =\n definition.searchable ?? definition.options.length > SEARCHABLE_PAST;\n const chosen = new Set(\n value == null ? [] : Array.isArray(value) ? value : [value],\n );\n const needle = query.trim().toLowerCase();\n const options = needle\n ? definition.options.filter(\n (option) =>\n option.label.toLowerCase().includes(needle) ||\n option.value.toLowerCase().includes(needle),\n )\n : definition.options;\n const pick = (option: FilterOption) => {\n if (definition.multiple) {\n const next = new Set(chosen);\n if (next.has(option.value)) next.delete(option.value);\n else next.add(option.value);\n // Keep the definition's order, so the chip reads the same way\n // whatever order the values were chosen in.\n const ordered = definition.options\n .map((item) => item.value)\n .filter((item) => next.has(item));\n onChange(ordered.length > 0 ? ordered : undefined);\n return;\n }\n onChange(chosen.has(option.value) ? undefined : option.value);\n };\n return (\n <Command.Root\n label={`${definition.label} options`}\n // Without a search field the list itself takes focus, so the arrow\n // keys work from the first frame.\n ref={(node: HTMLDivElement | null) => {\n if (!searchable) focusRef.current = node;\n }}\n className=\"rounded-base\"\n >\n {searchable ? (\n <Command.InputGroup>\n <IconSearch\n aria-hidden\n className=\"text-pho-description pointer-events-none absolute left-3 size-4\"\n />\n <Command.Input\n ref={(node: HTMLInputElement | null) => {\n focusRef.current = node;\n }}\n value={query}\n onValueChange={setQuery}\n placeholder={definition.searchPlaceholder ?? \"Search\"}\n aria-label={`Search ${definition.label.toLowerCase()} options`}\n className=\"py-2 pr-3 pl-9 text-base\"\n />\n </Command.InputGroup>\n ) : null}\n <Command.List>\n <Command.Empty>Nothing matches.</Command.Empty>\n {options.map((option) => (\n <Command.Item\n key={option.value}\n value={option.value}\n size=\"sm\"\n title={option.title ?? option.label}\n aria-checked={chosen.has(option.value)}\n icon={chosen.has(option.value) ? <IconCheck aria-hidden /> : null}\n onSelect={() => pick(option)}\n />\n ))}\n </Command.List>\n </Command.Root>\n );\n}\n\nconst DATE_INPUT =\n \"bg-pho-primary ring-pho-primary text-pho-primary focus-visible:ring-pho-brand w-full min-w-0 rounded-sm px-2 py-1 text-base ring-1 transition-shadow duration-100 ease-linear outline-none ring-inset focus-visible:ring-2\";\n\nfunction DateRangePanel({\n definition,\n value,\n focusRef,\n onChange,\n}: {\n definition: DateRangeFilterDefinition;\n value: DateRangeValue | undefined;\n focusRef: RefObject<HTMLElement | null>;\n onChange: (next: DateRangeValue | undefined) => void;\n}) {\n const presets = definition.presets ?? FILTER_DATE_PRESETS;\n // A preset's `from` is a timestamp; the day field shows its date.\n const day = (side: string | null | undefined) =>\n side == null ? \"\" : DATE_ONLY.test(side) ? side : side.slice(0, 10);\n const setSide = (side: \"from\" | \"to\", next: string) => {\n // Editing either day leaves a preset behind: the pair is the value now,\n // and a preset's timestamp becomes the day it fell on.\n const range: DateRangeValue = {\n from: day(value?.from) || null,\n to: day(value?.to) || null,\n [side]: next || null,\n };\n onChange(range.from == null && range.to == null ? undefined : range);\n };\n return (\n <div className=\"flex flex-col\">\n <Command.Root\n label={`${definition.label} presets`}\n ref={(node: HTMLDivElement | null) => {\n focusRef.current = node;\n }}\n className=\"rounded-t-[inherit]\"\n >\n <Command.List>\n {presets.map((preset) => (\n <Command.Item\n key={preset.label}\n value={preset.label}\n size=\"sm\"\n title={preset.label}\n aria-checked={value?.preset === preset.label}\n icon={\n value?.preset === preset.label ? (\n <IconCheck aria-hidden />\n ) : null\n }\n onSelect={() =>\n onChange({\n from: new Date(\n Date.now() - preset.hours * 60 * 60 * 1000,\n ).toISOString(),\n to: null,\n preset: preset.label,\n })\n }\n />\n ))}\n </Command.List>\n </Command.Root>\n {/* The day fields stand outside the command list: its arrow-key\n handling would otherwise swallow the native date stepping. */}\n <div className=\"border-pho-secondary grid grid-cols-2 gap-2 border-t p-2\">\n <label className=\"text-pho-description flex min-w-0 flex-col gap-1 text-xs\">\n From\n <input\n type=\"date\"\n value={day(value?.from)}\n max={day(value?.to) || undefined}\n onChange={(event) => setSide(\"from\", event.target.value)}\n className={DATE_INPUT}\n />\n </label>\n <label className=\"text-pho-description flex min-w-0 flex-col gap-1 text-xs\">\n To\n <input\n type=\"date\"\n value={day(value?.to)}\n min={day(value?.from) || undefined}\n onChange={(event) => setSide(\"to\", event.target.value)}\n className={DATE_INPUT}\n />\n </label>\n </div>\n </div>\n );\n}\n\n/* ---------------------------------- bar --------------------------------- */\n\nexport interface FilterBarProps extends Omit<\n ComponentProps<\"div\">,\n \"children\"\n> {\n /** One chip per definition, in this order. */\n definitions: readonly FilterDefinition[];\n /** The values, keyed by definition key. Absent or empty means unset. */\n filters: FilterValues;\n /** The whole map, changed — set, cleared, or cleared all. */\n onFiltersChange: (next: FilterValues) => void;\n /** The search field's text. The field renders only with `onSearchChange`. */\n search?: string;\n onSearchChange?: (value: string) => void;\n /** A teaching phrase — \"Find an event by id\". @default \"Search\" */\n searchPlaceholder?: string;\n /** The field's accessible name when the placeholder is too short to be one. */\n searchLabel?: string;\n /**\n * Pin the bar to the top of the nearest scroll pane. It paints the\n * surface it sits on (`--pho-surface`) so rows scroll under it.\n */\n sticky?: boolean;\n /** Controls after the chips — a range picker, an export button. */\n children?: ReactNode;\n ref?: Ref<HTMLDivElement>;\n}\n\nexport function FilterBar({\n definitions,\n filters,\n onFiltersChange,\n search,\n onSearchChange,\n searchPlaceholder = \"Search\",\n searchLabel,\n sticky,\n className,\n children,\n ...props\n}: FilterBarProps) {\n const setCount = definitions.filter((definition) =>\n isFilterSet(filters[definition.key]),\n ).length;\n const change = (key: string, next: FilterValue | undefined) => {\n const rest = { ...filters };\n if (next === undefined) delete rest[key];\n else rest[key] = next;\n onFiltersChange(rest);\n };\n return (\n <div\n data-filter-bar=\"\"\n className={cn(\n \"flex min-w-0 flex-wrap items-center gap-2\",\n sticky &&\n \"sticky top-0 z-10 bg-[var(--pho-surface,var(--background-color-pho-page))] py-3\",\n className,\n )}\n {...props}\n >\n {onSearchChange != null ? (\n <InputGroup.Root size=\"sm\" className=\"w-64 max-w-full\">\n <InputGroup.Addon>\n <IconSearch />\n </InputGroup.Addon>\n <InputGroup.Input\n type=\"search\"\n value={search ?? \"\"}\n onChange={(event) => onSearchChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.key !== \"Escape\") return;\n event.preventDefault();\n onSearchChange(\"\");\n }}\n placeholder={searchPlaceholder}\n aria-label={searchLabel ?? searchPlaceholder}\n />\n </InputGroup.Root>\n ) : null}\n {definitions.map((definition) => (\n <FilterChip\n key={definition.key}\n definition={definition}\n value={filters[definition.key]}\n onChange={(next) => change(definition.key, next)}\n />\n ))}\n {setCount > 1 ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => {\n const rest = { ...filters };\n for (const definition of definitions) delete rest[definition.key];\n onFiltersChange(rest);\n }}\n >\n Clear filters\n </Button>\n ) : null}\n {children}\n </div>\n );\n}\n\nFilterBar.displayName = \"FilterBar\";\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { t as s } from "./cn-ChIgwEl3.js";
|
|
3
|
-
import { t as n } from "./IconSearch-BKAHkLyX.js";
|
|
4
|
-
import { jsx as a, jsxs as l } from "react/jsx-runtime";
|
|
5
|
-
var p = "rounded-base border border-pho-secondary bg-pho-primary", m = "text-pho-description h-10 text-left align-middle font-normal whitespace-nowrap", b = "divide-pho-secondary border-pho-secondary divide-y border-t", x = {
|
|
6
|
-
sm: "text-xs",
|
|
7
|
-
base: "text-base",
|
|
8
|
-
lg: "text-md"
|
|
9
|
-
};
|
|
10
|
-
function u({ value: r, onChange: t, className: i, ...e }) {
|
|
11
|
-
return /* @__PURE__ */ l("label", {
|
|
12
|
-
className: s("flex min-w-40 flex-1 items-center gap-2", i),
|
|
13
|
-
children: [/* @__PURE__ */ a(n, {
|
|
14
|
-
"aria-hidden": !0,
|
|
15
|
-
className: "text-pho-description size-4 shrink-0"
|
|
16
|
-
}), /* @__PURE__ */ a("input", {
|
|
17
|
-
type: "search",
|
|
18
|
-
value: r,
|
|
19
|
-
onChange: (o) => t(o.target.value),
|
|
20
|
-
className: "text-pho-primary placeholder:text-pho-description outline-pho-brand w-full min-w-0 rounded-sm bg-transparent text-base focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
21
|
-
...e,
|
|
22
|
-
"aria-label": e["aria-label"] ?? (e["aria-labelledby"] ? void 0 : "Search")
|
|
23
|
-
})]
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
export {
|
|
27
|
-
x as a,
|
|
28
|
-
p as i,
|
|
29
|
-
b as n,
|
|
30
|
-
m as r,
|
|
31
|
-
u as t
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
//# sourceMappingURL=ghost-search-CNVs9k1o.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ghost-search-CNVs9k1o.js","names":[],"sources":["../../src/components/data-table/chrome.ts","../../src/utils/ghost-search.tsx"],"sourcesContent":["/**\n * The table chrome `DataTable` and `Trace.Logs` share, kept apart from\n * `data-table.tsx` so a consumer of the classes alone (the trace's log\n * list) does not carry the table engine into its chunk.\n *\n * - The frame is `BasicPage.Card`'s box minus its dividers; rows draw\n * their own.\n * - A header cell is description ink at the row's size, regular weight,\n * 40px tall on every size: a label row, not a banner. Its padding is the\n * cell's own (`px-5` in a table, the row's in a grid), so it stays out.\n * - The body's top border is the line under the header; the rows divide\n * themselves.\n */\n\n/** Same chrome as `BasicPage.Card`, minus its dividers — rows draw their own. */\nexport const DATA_TABLE_SURFACE =\n \"rounded-base border border-pho-secondary bg-pho-primary\";\n\n/** A header cell: ink, height, weight. Pad it where it sits. */\nexport const DATA_TABLE_HEADER_CELL =\n \"text-pho-description h-10 text-left align-middle font-normal whitespace-nowrap\";\n\n/** The body: the line under the header, and one between every two rows. */\nexport const DATA_TABLE_BODY =\n \"divide-pho-secondary border-pho-secondary divide-y border-t\";\n\nexport type DataTableSize = \"sm\" | \"base\" | \"lg\";\n\n/**\n * The type each size sets on the table, so cells and header move together:\n * 13px dense, the body's 14px, 16px for rows that carry two lines.\n */\nexport const DATA_TABLE_TEXT: Record<DataTableSize, string> = {\n sm: \"text-xs\",\n base: \"text-base\",\n lg: \"text-md\",\n};\n","import type { ComponentProps } from \"react\";\nimport { IconSearch } from \"@tabler/icons-react\";\nimport { cn } from \"./cn\";\n\nexport interface GhostSearchProps extends Omit<\n ComponentProps<\"input\">,\n \"value\" | \"onChange\" | \"type\" | \"children\"\n> {\n value: string;\n onChange: (value: string) => void;\n}\n\n/**\n * A search box with no box: the glyph and the text on the surface's own\n * line, the way a toolbar band inside a card carries it (a `DataTable`'s\n * search, a `Trace.Waterfall`'s). Quiet ink, no ring until focus.\n */\nexport function GhostSearch({\n value,\n onChange,\n className,\n ...props\n}: GhostSearchProps) {\n return (\n <label className={cn(\"flex min-w-40 flex-1 items-center gap-2\", className)}>\n <IconSearch\n aria-hidden\n className=\"text-pho-description size-4 shrink-0\"\n />\n <input\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n className=\"text-pho-primary placeholder:text-pho-description outline-pho-brand w-full min-w-0 rounded-sm bg-transparent text-base focus-visible:outline-2 focus-visible:outline-offset-2\"\n {...props}\n aria-label={\n props[\"aria-label\"] ??\n (props[\"aria-labelledby\"] ? undefined : \"Search\")\n }\n />\n </label>\n );\n}\n"],"mappings":";;;;AAeA,IAAa,IACX,2DAGW,IACX,kFAGW,IACX,+DAQW,IAAiD;AAAA,EAC5D,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,IAAI;AACN;ACnBA,SAAgB,EAAY,EAC1B,OAAA,GACA,UAAA,GACA,WAAA,GACA,GAAG,EAAA,GACgB;AACnB,SACE,gBAAA,EAAC,SAAD;AAAA,IAAO,WAAW,EAAG,2CAA2C,CAAS;AAAA,IAAzE,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,MACE,eAAA;AAAA,MACA,WAAU;AAAA,IACX,CAAA,GACD,gBAAA,EAAC,SAAD;AAAA,MACE,MAAK;AAAA,MACE,OAAA;AAAA,MACP,UAAA,CAAW,MAAU,EAAS,EAAM,OAAO,KAAK;AAAA,MAChD,WAAU;AAAA,MACV,GAAI;AAAA,MACJ,cACE,EAAM,YAAA,MACL,EAAM,iBAAA,IAAqB,SAAY;AAAA,IAE3C,CAAA,CACI;AAAA;AAEX"}
|