@photon-ai/pho-ui 2.16.0 → 2.17.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/IconArrowsMinimize-BfPUGuCB.js +75 -0
- package/dist/chunks/IconArrowsMinimize-BfPUGuCB.js.map +1 -0
- package/dist/chunks/IconChevronUp-CrpWSgIl.js +11 -0
- package/dist/chunks/IconChevronUp-CrpWSgIl.js.map +1 -0
- package/dist/chunks/{bar-chart-BJfr3eyd.js → bar-chart-DIALC2_z.js} +2 -2
- package/dist/chunks/bar-chart-DIALC2_z.js.map +1 -0
- package/dist/chunks/basic-page-CogcwGx3.js +1749 -0
- package/dist/chunks/basic-page-CogcwGx3.js.map +1 -0
- package/dist/chunks/card-DhDwtSi9.js +56 -0
- package/dist/chunks/card-DhDwtSi9.js.map +1 -0
- package/dist/chunks/code-block-BuDIo8Q0.js +197 -0
- package/dist/chunks/code-block-BuDIo8Q0.js.map +1 -0
- package/dist/chunks/collapsible-if7ncPbI.js +28 -0
- package/dist/chunks/collapsible-if7ncPbI.js.map +1 -0
- package/dist/chunks/{command-Ck8IAgV7.js → command-CTYrSz9a.js} +2 -2
- package/dist/chunks/{command-Ck8IAgV7.js.map → command-CTYrSz9a.js.map} +1 -1
- package/dist/chunks/data-table-DcwCgXJU.js +293 -0
- package/dist/chunks/data-table-DcwCgXJU.js.map +1 -0
- package/dist/chunks/date-range-picker-DwFDUNRL.js +88 -0
- package/dist/chunks/date-range-picker-DwFDUNRL.js.map +1 -0
- package/dist/chunks/{dialog-BxKACOj5.js → dialog-BwfUFn6B.js} +2 -2
- package/dist/chunks/{dialog-BxKACOj5.js.map → dialog-BwfUFn6B.js.map} +1 -1
- package/dist/chunks/{filter-bar-Cjjq38xo.js → filter-bar-BsvdXwzc.js} +2 -2
- package/dist/chunks/{filter-bar-Cjjq38xo.js.map → filter-bar-BsvdXwzc.js.map} +1 -1
- package/dist/chunks/ghost-search-BvBFa9su.js +25 -0
- package/dist/chunks/ghost-search-BvBFa9su.js.map +1 -0
- package/dist/chunks/{line-chart-CUR3AxrR.js → line-chart-VuMYKzW3.js} +2 -2
- package/dist/chunks/{line-chart-CUR3AxrR.js.map → line-chart-VuMYKzW3.js.map} +1 -1
- package/dist/chunks/{log-list-0AXnjFrk.js → log-list-BERiO4UJ.js} +2 -2
- package/dist/chunks/{log-list-0AXnjFrk.js.map → log-list-BERiO4UJ.js.map} +1 -1
- package/dist/chunks/scroll-area-Zik8t1Mk.js +168 -0
- package/dist/chunks/scroll-area-Zik8t1Mk.js.map +1 -0
- package/dist/chunks/sidebar-DRPe5CAh.js +306 -0
- package/dist/chunks/sidebar-DRPe5CAh.js.map +1 -0
- package/dist/chunks/{toast-iSf6NuAS.js → toast-72Wwlzg9.js} +2 -2
- package/dist/chunks/{toast-iSf6NuAS.js.map → toast-72Wwlzg9.js.map} +1 -1
- package/dist/chunks/trace-Ba1RMBfk.js +1645 -0
- package/dist/chunks/trace-Ba1RMBfk.js.map +1 -0
- package/dist/chunks/use-measure-C-i54AC6.js +629 -0
- package/dist/chunks/use-measure-C-i54AC6.js.map +1 -0
- package/dist/components/bar-chart.js +1 -1
- package/dist/components/card.js +1 -1
- package/dist/components/code-block.js +1 -1
- package/dist/components/collapsible.js +2 -25
- package/dist/components/command.js +1 -1
- package/dist/components/data-table.js +9 -8
- package/dist/components/date-range-picker.js +10 -0
- package/dist/components/dialog.js +1 -1
- package/dist/components/filter-bar.js +1 -1
- package/dist/components/line-chart.js +1 -1
- package/dist/components/log-list.js +1 -1
- package/dist/components/scroll-area.js +1 -1
- package/dist/components/toast.js +1 -1
- package/dist/components/trace.js +41 -6
- package/dist/index.js +166 -121
- package/dist/primitives.js +2 -2
- package/dist/sections/basic-page.js +5 -5
- package/dist/sections/sidebar.js +9 -6
- package/dist/src/components/card/card.d.ts +5 -1
- package/dist/src/components/chart/scale.d.ts +6 -1
- package/dist/src/components/code-block/code-block.d.ts +24 -5
- package/dist/src/components/code-block/index.d.ts +1 -1
- package/dist/src/components/data-table/data-table.d.ts +54 -13
- package/dist/src/components/date-range-picker/date-range-picker.d.ts +31 -0
- package/dist/src/components/date-range-picker/index.d.ts +1 -0
- package/dist/src/components/scroll-area/scroll-area.d.ts +9 -1
- package/dist/src/components/trace/decorations.d.ts +32 -0
- package/dist/src/components/trace/index.d.ts +5 -2
- package/dist/src/components/trace/layout.d.ts +57 -29
- package/dist/src/components/trace/span-primitive.d.ts +168 -0
- package/dist/src/components/trace/span-tree.d.ts +148 -0
- package/dist/src/components/trace/trace.d.ts +98 -16
- package/dist/src/index.d.ts +1 -0
- package/dist/src/sections/basic-page/basic-page.d.ts +95 -7
- package/dist/src/sections/basic-page/index.d.ts +1 -1
- package/dist/src/sections/sidebar/index.d.ts +1 -1
- package/dist/src/sections/sidebar/sidebar.d.ts +72 -0
- package/dist/src/utils/ghost-search.d.ts +11 -0
- package/package.json +5 -1
- package/dist/chunks/bar-chart-BJfr3eyd.js.map +0 -1
- package/dist/chunks/basic-page-CMJuM5iA.js +0 -1650
- package/dist/chunks/basic-page-CMJuM5iA.js.map +0 -1
- package/dist/chunks/card-DSW3Uhag.js +0 -56
- package/dist/chunks/card-DSW3Uhag.js.map +0 -1
- package/dist/chunks/code-block-CdozzaHM.js +0 -139
- package/dist/chunks/code-block-CdozzaHM.js.map +0 -1
- package/dist/chunks/data-table-CHLJfGkS.js +0 -279
- package/dist/chunks/data-table-CHLJfGkS.js.map +0 -1
- package/dist/chunks/scroll-area-BO-9PMM7.js +0 -167
- package/dist/chunks/scroll-area-BO-9PMM7.js.map +0 -1
- package/dist/chunks/sidebar-DVzZsCts.js +0 -223
- package/dist/chunks/sidebar-DVzZsCts.js.map +0 -1
- package/dist/chunks/trace-CbH0IohX.js +0 -314
- package/dist/chunks/trace-CbH0IohX.js.map +0 -1
- package/dist/chunks/use-measure-CMVgLouO.js +0 -616
- package/dist/chunks/use-measure-CMVgLouO.js.map +0 -1
- package/dist/components/collapsible.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-list-0AXnjFrk.js","names":[],"sources":["../../src/components/log-list/log-list.tsx"],"sourcesContent":["import {\n useEffect,\n useId,\n useRef,\n type ComponentProps,\n type MouseEvent,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { Badge, type BadgeColor, type BadgeSize } from \"../badge\";\nimport { Button } from \"../button\";\nimport { Skeleton } from \"../skeleton\";\nimport { Spinner } from \"../spinner\";\nimport { StatusView } from \"../status-view\";\nimport { Tooltip } from \"../tooltip\";\nimport { cn } from \"../../utils/cn\";\nimport { useCopy } from \"../../utils/use-copy\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\n\n/**\n * Log List — rows of requests, deliveries, or messages, newest first,\n * each one line: a mono id you can copy, a status, the method, what\n * happened, and how long ago. Reach for it where a `DataTable` would be\n * columns of the same few fields: a log reads left to right as one line,\n * and the page filters it from a `FilterBar` pinned above.\n *\n * Design notes:\n * - The surface is `BasicPage.Card`'s: hairline border, `base` radius,\n * hairline rules between rows. It sits in a `Stack` as any card does.\n * - The row is one link (or one button). It stretches over the row from\n * the label, the way a `DataTable` row's does, so the whole row is one\n * pointer target and one tab stop; the copy control sits above it.\n * - The id truncates in the middle, keeping the prefix that says what it\n * is and the tail that tells it apart. The full id is a tooltip away,\n * and one click copies it.\n * - `LoadMore` is the sentinel at the end: it asks for the next page as\n * it scrolls into view, and offers a button for keyboards and for\n * browsers without an observer.\n */\n\n/** Same chrome as `BasicPage.Card`. */\nconst LOG_LIST_SURFACE =\n \"rounded-base border border-pho-secondary bg-pho-primary divide-y divide-pho-secondary\";\n\n/** Middle truncation: the prefix and this many after it, then the tail. */\nconst ID_HEAD = 12;\nconst ID_TAIL = 5;\n\n/**\n * Keep the start and the end of an id and fold the middle into an\n * ellipsis — `pho_req_01m04axjqrfzxv4xjet40a84gb` reads\n * `pho_req_01m0…a84gb`. Ids that fit are returned whole.\n */\nexport function truncateMiddle(\n value: string,\n head = ID_HEAD,\n tail = ID_TAIL,\n): string {\n if (value.length <= head + tail + 1) return value;\n return `${value.slice(0, head)}…${value.slice(-tail)}`;\n}\n\n/* -------------------------------- status -------------------------------- */\n\nconst SUCCESS_WORDS = new Set([\n \"success\",\n \"succeeded\",\n \"successful\",\n \"delivered\",\n \"ok\",\n \"sent\",\n \"received\",\n \"completed\",\n \"complete\",\n \"done\",\n \"active\",\n]);\nconst ERROR_WORDS = new Set([\n \"failed\",\n \"failure\",\n \"error\",\n \"errored\",\n \"rejected\",\n \"undelivered\",\n \"timeout\",\n \"timed_out\",\n \"timed out\",\n \"canceled\",\n \"cancelled\",\n]);\nconst WARNING_WORDS = new Set([\n \"pending\",\n \"queued\",\n \"retrying\",\n \"processing\",\n \"sending\",\n \"in_progress\",\n \"in progress\",\n \"scheduled\",\n \"waiting\",\n]);\n\n/**\n * The `Badge` color for a log status: an HTTP status code (2xx success,\n * 3xx gray, 4xx warning, 5xx error) or a word (`delivered` / `failed` /\n * `pending`). Anything else is gray.\n */\nexport function logStatusColor(status: number | string): BadgeColor {\n if (typeof status === \"number\") {\n if (status < 300) return \"success\";\n if (status < 400) return \"gray\";\n if (status < 500) return \"warning\";\n return \"error\";\n }\n const word = status.trim().toLowerCase();\n if (/^\\d{3}$/.test(word)) return logStatusColor(Number(word));\n if (SUCCESS_WORDS.has(word)) return \"success\";\n if (ERROR_WORDS.has(word)) return \"error\";\n if (WARNING_WORDS.has(word)) return \"warning\";\n return \"gray\";\n}\n\n/** A status word as a label: `timed_out` reads `Timed out`. */\nexport function logStatusLabel(status: number | string): string {\n if (typeof status === \"number\") return String(status);\n const word = status.trim().replace(/_/g, \" \");\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\nexport interface LogStatusProps extends Omit<\n ComponentProps<\"span\">,\n \"children\" | \"color\"\n> {\n /** An HTTP status code or a status word. */\n value: number | string;\n /** Override the derived word. */\n label?: ReactNode;\n /** Badge size. @default \"sm\" */\n size?: BadgeSize;\n}\n\n/** The status slot — a low-contrast `Badge` colored by `logStatusColor`. */\nfunction Status({\n value,\n label,\n size = \"sm\",\n className,\n ...props\n}: LogStatusProps) {\n return (\n <Badge\n color={logStatusColor(value)}\n contrast=\"low\"\n size={size}\n className={cn(\"tabular-nums\", className)}\n {...props}\n >\n {label ?? logStatusLabel(value)}\n </Badge>\n );\n}\n\n/** The method slot — `POST`, `GET` as a quiet mono chip. */\nfunction Method({\n className,\n ...props\n}: ComponentProps<\"span\"> & { ref?: Ref<HTMLSpanElement> }) {\n return (\n <span\n className={cn(\n \"bg-pho-secondary text-pho-secondary inline-flex h-5 min-w-12 shrink-0 items-center justify-center rounded-sm px-1.5 font-mono text-xs font-medium whitespace-nowrap\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/* ---------------------------------- id ---------------------------------- */\n\n/**\n * The id cell: a mono button that copies the full id, with a tooltip\n * holding the whole of it. The cell is a fixed width in characters so\n * ids line up down the list.\n */\nfunction IdCell({ id, cellId }: { id: string; cellId: string }) {\n const { copied, copy } = useCopy();\n return (\n <Tooltip.Root>\n <Tooltip.Trigger\n id={cellId}\n aria-label={copied ? `${id} copied` : `Copy ${id}`}\n data-copied={copied || undefined}\n onClick={() => void copy(id)}\n className={cn(\n \"text-pho-secondary outline-pho-brand hover:text-pho-primary relative z-10 -mx-1 w-[calc(18ch+0.5rem)] shrink-0 cursor-pointer truncate rounded-sm px-1 py-0.5 text-left font-mono text-xs transition-colors duration-100 ease-linear focus-visible:outline-2\",\n \"data-[copied]:text-pho-success\",\n )}\n >\n {copied ? \"Copied\" : truncateMiddle(id)}\n </Tooltip.Trigger>\n <output className=\"sr-only\" aria-live=\"polite\">\n {copied ? \"Copied\" : \"\"}\n </output>\n <Tooltip.Portal>\n <Tooltip.Positioner>\n <Tooltip.Popup className=\"font-mono\">{id}</Tooltip.Popup>\n </Tooltip.Positioner>\n </Tooltip.Portal>\n </Tooltip.Root>\n );\n}\n\n/* ---------------------------------- row --------------------------------- */\n\nexport interface LogListRowProps extends Omit<\n ComponentProps<\"div\">,\n \"children\" | \"title\" | \"onClick\" | \"id\"\n> {\n /** The record's id — mono, middle-truncated, copied on click. */\n id?: string;\n /** The status slot — usually `LogList.Status`. */\n status?: ReactNode;\n /** The method — `POST`, `GET`; rendered in `LogList.Method`. */\n method?: string;\n /** What happened — the route, the event type, the message. */\n label: ReactNode;\n /** The label in mono — for a route or an event type. */\n code?: boolean;\n /**\n * The line under the label, with real content: who received what from\n * whom, the destination that answered. A sentence, with its period.\n */\n description?: ReactNode;\n /** Trailing: how long it took — \"59 ms\". */\n duration?: ReactNode;\n /** Trailing: when — \"2 min ago\". */\n time?: ReactNode;\n /** Trailing content before the duration and time. */\n children?: ReactNode;\n /** The row is a link to its page, through the host's `LinkProvider`. */\n href?: string;\n /** The row is a button. */\n onClick?: (event: MouseEvent<HTMLElement>) => void;\n /**\n * Replace the row's link element — a router's `Link`, the way Base UI\n * components take `render`. The row's classes and handlers merge in.\n */\n render?: useRender.RenderProp;\n /** The row whose page is open beside the list — it keeps the wash. */\n current?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\nfunction Row({\n id,\n status,\n method,\n label,\n code,\n description,\n duration,\n time,\n children,\n href,\n onClick,\n render,\n current,\n className,\n ...props\n}: LogListRowProps) {\n const Link = useLinkComponent();\n const base = useId();\n const interactive = href != null || onClick != null || render != null;\n const cellIds = {\n id: `${base}-id`,\n status: `${base}-status`,\n method: `${base}-method`,\n meta: `${base}-meta`,\n };\n const hasMeta = children != null || duration != null || time != null;\n const describedBy = [\n id != null && cellIds.id,\n status != null && cellIds.status,\n method != null && cellIds.method,\n hasMeta && cellIds.meta,\n ]\n .filter(Boolean)\n .join(\" \");\n const primary = useRender({\n render: render ?? (href != null ? <Link href={href} /> : undefined),\n defaultTagName: href != null ? \"a\" : onClick != null ? \"button\" : \"span\",\n props: {\n className: cn(\n \"text-pho-primary block min-w-0 max-w-full truncate text-left text-base font-medium outline-none\",\n code && \"font-mono text-xs\",\n // The one link, stretched over the row; the ring is the row's.\n interactive &&\n \"cursor-pointer after:absolute after:inset-0 after:content-['']\",\n ),\n onClick,\n type:\n render == null && href == null && onClick != null\n ? \"button\"\n : undefined,\n \"aria-current\": current ? \"page\" : undefined,\n \"aria-describedby\": describedBy || undefined,\n \"data-log-primary\": \"\",\n children: label,\n },\n });\n return (\n <div\n data-log-row=\"\"\n data-current={current || undefined}\n className={cn(\n \"relative flex min-h-12 min-w-0 items-center gap-3 px-5 py-2.5\",\n interactive &&\n \"hover:bg-pho-primary-hover outline-pho-brand transition-colors has-[[data-log-primary]:focus-visible]:outline-2 has-[[data-log-primary]:focus-visible]:-outline-offset-2\",\n current && \"bg-pho-primary-hover\",\n // The 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 {...props}\n >\n {id != null ? <IdCell id={id} cellId={cellIds.id} /> : null}\n {status != null ? (\n <span id={cellIds.status} className=\"flex shrink-0 items-center\">\n {status}\n </span>\n ) : null}\n {method != null ? <Method id={cellIds.method}>{method}</Method> : null}\n <div data-log-primary-cell=\"\" className=\"min-w-0 flex-1\">\n {primary}\n {description != null ? (\n <p className=\"text-pho-description truncate text-xs\">{description}</p>\n ) : null}\n </div>\n {hasMeta ? (\n <div\n id={cellIds.meta}\n className=\"text-pho-description ml-auto flex shrink-0 items-center gap-3 text-xs whitespace-nowrap tabular-nums\"\n >\n {children}\n {duration != null ? <span>{duration}</span> : null}\n {time != null ? <span>{time}</span> : null}\n </div>\n ) : null}\n </div>\n );\n}\n\n/* -------------------------------- states -------------------------------- */\n\nexport interface LogListEmptyProps extends Omit<\n ComponentProps<\"div\">,\n \"title\" | \"children\"\n> {\n /** One short line naming the state. @default \"Nothing here yet.\" */\n title?: ReactNode;\n /** What fills it, or why it is empty. */\n description?: ReactNode;\n /** An action, when there is one. */\n children?: ReactNode;\n}\n\n/** The list with no rows — `StatusView` at card size. */\nfunction Empty({\n title = \"Nothing here yet.\",\n description,\n children,\n className,\n ...props\n}: LogListEmptyProps) {\n return (\n <div className={cn(\"flex justify-center\", className)} {...props}>\n <StatusView\n size=\"sm\"\n title={title}\n description={description}\n actions={children}\n />\n </div>\n );\n}\n\n/** Bones in the rows' place while the first page is on its way. */\nfunction Loading({ rows = 5 }: { rows?: number }) {\n return (\n <>\n {Array.from({ length: rows }, (_, index) => (\n <div\n key={index}\n aria-hidden\n className=\"flex min-h-12 items-center gap-3 px-5 py-2.5\"\n >\n <Skeleton className=\"h-3.5 w-32\" />\n <Skeleton className=\"h-5 w-12 rounded-full\" />\n <Skeleton className=\"h-3.5 w-48\" />\n <Skeleton className=\"ml-auto h-3.5 w-16\" />\n </div>\n ))}\n </>\n );\n}\n\nexport interface LogListLoadMoreProps extends Omit<\n ComponentProps<\"div\">,\n \"children\"\n> {\n /** Asked for as the sentinel scrolls into view, and on the button. */\n onLoadMore: () => void;\n /** The next page is on its way — the sentinel shows a spinner and waits. */\n loading?: boolean;\n /** Nothing left to load — renders nothing. @default true */\n hasMore?: boolean;\n /** How far ahead of the viewport to ask. @default \"200px\" */\n rootMargin?: string;\n /** The button's words. @default \"Load more\" */\n label?: ReactNode;\n}\n\n/**\n * The sentinel at the end of the list. An `IntersectionObserver` asks for\n * the next page as it comes into view (`rootMargin` ahead of it); while\n * `loading` it shows a spinner and asks for nothing. The button is the\n * same request for keyboards and for a browser without the observer.\n * SSR-safe: the observer is created in an effect.\n */\nfunction LoadMore({\n onLoadMore,\n loading,\n hasMore = true,\n rootMargin = \"200px\",\n label = \"Load more\",\n className,\n ...props\n}: LogListLoadMoreProps) {\n const ref = useRef<HTMLDivElement | null>(null);\n const latest = useRef(onLoadMore);\n latest.current = onLoadMore;\n useEffect(() => {\n const el = ref.current;\n if (!hasMore || loading || el == null) return;\n if (typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) latest.current();\n },\n { rootMargin },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [hasMore, loading, rootMargin]);\n if (!hasMore) return null;\n return (\n <div\n ref={ref}\n data-log-load-more=\"\"\n aria-busy={loading || undefined}\n className={cn(\n \"flex min-h-12 items-center justify-center px-5 py-2\",\n className,\n )}\n {...props}\n >\n {loading ? (\n <Spinner aria-label=\"Loading more\" className=\"text-pho-secondary\" />\n ) : (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => onLoadMore()}>\n {label}\n </Button>\n )}\n </div>\n );\n}\n\n/* ---------------------------------- root -------------------------------- */\n\nexport interface LogListRootProps extends ComponentProps<\"div\"> {\n ref?: Ref<HTMLDivElement>;\n}\n\n/** The card the rows stack in. Mark it `aria-busy` while bones show. */\nfunction Root({ className, ...props }: LogListRootProps) {\n return (\n <div\n data-log-list=\"\"\n className={cn(LOG_LIST_SURFACE, \"min-w-0\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Log List — a card of one-line log rows.\n *\n * ```tsx\n * <LogList.Root>\n * <LogList.Row\n * id=\"pho_req_01m04axjqrfzxv4xjet40a84gb\"\n * status={<LogList.Status value={200} />}\n * method=\"POST\"\n * code\n * label=\"/v1/messages\"\n * description=\"+1 332 259 3374 received a message from +1 332 222 1111.\"\n * duration=\"59 ms\"\n * time=\"2 min ago\"\n * href=\"/requests/pho_req_01m04axjqrfzxv4xjet40a84gb\"\n * />\n * <LogList.LoadMore onLoadMore={fetchNextPage} loading={isFetching} hasMore={hasNextPage} />\n * </LogList.Root>\n * ```\n */\nexport const LogList = {\n Root,\n Row,\n Status,\n Method,\n Empty,\n Loading,\n LoadMore,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"log-list-BERiO4UJ.js","names":[],"sources":["../../src/components/log-list/log-list.tsx"],"sourcesContent":["import {\n useEffect,\n useId,\n useRef,\n type ComponentProps,\n type MouseEvent,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { Badge, type BadgeColor, type BadgeSize } from \"../badge\";\nimport { Button } from \"../button\";\nimport { Skeleton } from \"../skeleton\";\nimport { Spinner } from \"../spinner\";\nimport { StatusView } from \"../status-view\";\nimport { Tooltip } from \"../tooltip\";\nimport { cn } from \"../../utils/cn\";\nimport { useCopy } from \"../../utils/use-copy\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\n\n/**\n * Log List — rows of requests, deliveries, or messages, newest first,\n * each one line: a mono id you can copy, a status, the method, what\n * happened, and how long ago. Reach for it where a `DataTable` would be\n * columns of the same few fields: a log reads left to right as one line,\n * and the page filters it from a `FilterBar` pinned above.\n *\n * Design notes:\n * - The surface is `BasicPage.Card`'s: hairline border, `base` radius,\n * hairline rules between rows. It sits in a `Stack` as any card does.\n * - The row is one link (or one button). It stretches over the row from\n * the label, the way a `DataTable` row's does, so the whole row is one\n * pointer target and one tab stop; the copy control sits above it.\n * - The id truncates in the middle, keeping the prefix that says what it\n * is and the tail that tells it apart. The full id is a tooltip away,\n * and one click copies it.\n * - `LoadMore` is the sentinel at the end: it asks for the next page as\n * it scrolls into view, and offers a button for keyboards and for\n * browsers without an observer.\n */\n\n/** Same chrome as `BasicPage.Card`. */\nconst LOG_LIST_SURFACE =\n \"rounded-base border border-pho-secondary bg-pho-primary divide-y divide-pho-secondary\";\n\n/** Middle truncation: the prefix and this many after it, then the tail. */\nconst ID_HEAD = 12;\nconst ID_TAIL = 5;\n\n/**\n * Keep the start and the end of an id and fold the middle into an\n * ellipsis — `pho_req_01m04axjqrfzxv4xjet40a84gb` reads\n * `pho_req_01m0…a84gb`. Ids that fit are returned whole.\n */\nexport function truncateMiddle(\n value: string,\n head = ID_HEAD,\n tail = ID_TAIL,\n): string {\n if (value.length <= head + tail + 1) return value;\n return `${value.slice(0, head)}…${value.slice(-tail)}`;\n}\n\n/* -------------------------------- status -------------------------------- */\n\nconst SUCCESS_WORDS = new Set([\n \"success\",\n \"succeeded\",\n \"successful\",\n \"delivered\",\n \"ok\",\n \"sent\",\n \"received\",\n \"completed\",\n \"complete\",\n \"done\",\n \"active\",\n]);\nconst ERROR_WORDS = new Set([\n \"failed\",\n \"failure\",\n \"error\",\n \"errored\",\n \"rejected\",\n \"undelivered\",\n \"timeout\",\n \"timed_out\",\n \"timed out\",\n \"canceled\",\n \"cancelled\",\n]);\nconst WARNING_WORDS = new Set([\n \"pending\",\n \"queued\",\n \"retrying\",\n \"processing\",\n \"sending\",\n \"in_progress\",\n \"in progress\",\n \"scheduled\",\n \"waiting\",\n]);\n\n/**\n * The `Badge` color for a log status: an HTTP status code (2xx success,\n * 3xx gray, 4xx warning, 5xx error) or a word (`delivered` / `failed` /\n * `pending`). Anything else is gray.\n */\nexport function logStatusColor(status: number | string): BadgeColor {\n if (typeof status === \"number\") {\n if (status < 300) return \"success\";\n if (status < 400) return \"gray\";\n if (status < 500) return \"warning\";\n return \"error\";\n }\n const word = status.trim().toLowerCase();\n if (/^\\d{3}$/.test(word)) return logStatusColor(Number(word));\n if (SUCCESS_WORDS.has(word)) return \"success\";\n if (ERROR_WORDS.has(word)) return \"error\";\n if (WARNING_WORDS.has(word)) return \"warning\";\n return \"gray\";\n}\n\n/** A status word as a label: `timed_out` reads `Timed out`. */\nexport function logStatusLabel(status: number | string): string {\n if (typeof status === \"number\") return String(status);\n const word = status.trim().replace(/_/g, \" \");\n return word.charAt(0).toUpperCase() + word.slice(1);\n}\n\nexport interface LogStatusProps extends Omit<\n ComponentProps<\"span\">,\n \"children\" | \"color\"\n> {\n /** An HTTP status code or a status word. */\n value: number | string;\n /** Override the derived word. */\n label?: ReactNode;\n /** Badge size. @default \"sm\" */\n size?: BadgeSize;\n}\n\n/** The status slot — a low-contrast `Badge` colored by `logStatusColor`. */\nfunction Status({\n value,\n label,\n size = \"sm\",\n className,\n ...props\n}: LogStatusProps) {\n return (\n <Badge\n color={logStatusColor(value)}\n contrast=\"low\"\n size={size}\n className={cn(\"tabular-nums\", className)}\n {...props}\n >\n {label ?? logStatusLabel(value)}\n </Badge>\n );\n}\n\n/** The method slot — `POST`, `GET` as a quiet mono chip. */\nfunction Method({\n className,\n ...props\n}: ComponentProps<\"span\"> & { ref?: Ref<HTMLSpanElement> }) {\n return (\n <span\n className={cn(\n \"bg-pho-secondary text-pho-secondary inline-flex h-5 min-w-12 shrink-0 items-center justify-center rounded-sm px-1.5 font-mono text-xs font-medium whitespace-nowrap\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/* ---------------------------------- id ---------------------------------- */\n\n/**\n * The id cell: a mono button that copies the full id, with a tooltip\n * holding the whole of it. The cell is a fixed width in characters so\n * ids line up down the list.\n */\nfunction IdCell({ id, cellId }: { id: string; cellId: string }) {\n const { copied, copy } = useCopy();\n return (\n <Tooltip.Root>\n <Tooltip.Trigger\n id={cellId}\n aria-label={copied ? `${id} copied` : `Copy ${id}`}\n data-copied={copied || undefined}\n onClick={() => void copy(id)}\n className={cn(\n \"text-pho-secondary outline-pho-brand hover:text-pho-primary relative z-10 -mx-1 w-[calc(18ch+0.5rem)] shrink-0 cursor-pointer truncate rounded-sm px-1 py-0.5 text-left font-mono text-xs transition-colors duration-100 ease-linear focus-visible:outline-2\",\n \"data-[copied]:text-pho-success\",\n )}\n >\n {copied ? \"Copied\" : truncateMiddle(id)}\n </Tooltip.Trigger>\n <output className=\"sr-only\" aria-live=\"polite\">\n {copied ? \"Copied\" : \"\"}\n </output>\n <Tooltip.Portal>\n <Tooltip.Positioner>\n <Tooltip.Popup className=\"font-mono\">{id}</Tooltip.Popup>\n </Tooltip.Positioner>\n </Tooltip.Portal>\n </Tooltip.Root>\n );\n}\n\n/* ---------------------------------- row --------------------------------- */\n\nexport interface LogListRowProps extends Omit<\n ComponentProps<\"div\">,\n \"children\" | \"title\" | \"onClick\" | \"id\"\n> {\n /** The record's id — mono, middle-truncated, copied on click. */\n id?: string;\n /** The status slot — usually `LogList.Status`. */\n status?: ReactNode;\n /** The method — `POST`, `GET`; rendered in `LogList.Method`. */\n method?: string;\n /** What happened — the route, the event type, the message. */\n label: ReactNode;\n /** The label in mono — for a route or an event type. */\n code?: boolean;\n /**\n * The line under the label, with real content: who received what from\n * whom, the destination that answered. A sentence, with its period.\n */\n description?: ReactNode;\n /** Trailing: how long it took — \"59 ms\". */\n duration?: ReactNode;\n /** Trailing: when — \"2 min ago\". */\n time?: ReactNode;\n /** Trailing content before the duration and time. */\n children?: ReactNode;\n /** The row is a link to its page, through the host's `LinkProvider`. */\n href?: string;\n /** The row is a button. */\n onClick?: (event: MouseEvent<HTMLElement>) => void;\n /**\n * Replace the row's link element — a router's `Link`, the way Base UI\n * components take `render`. The row's classes and handlers merge in.\n */\n render?: useRender.RenderProp;\n /** The row whose page is open beside the list — it keeps the wash. */\n current?: boolean;\n ref?: Ref<HTMLDivElement>;\n}\n\nfunction Row({\n id,\n status,\n method,\n label,\n code,\n description,\n duration,\n time,\n children,\n href,\n onClick,\n render,\n current,\n className,\n ...props\n}: LogListRowProps) {\n const Link = useLinkComponent();\n const base = useId();\n const interactive = href != null || onClick != null || render != null;\n const cellIds = {\n id: `${base}-id`,\n status: `${base}-status`,\n method: `${base}-method`,\n meta: `${base}-meta`,\n };\n const hasMeta = children != null || duration != null || time != null;\n const describedBy = [\n id != null && cellIds.id,\n status != null && cellIds.status,\n method != null && cellIds.method,\n hasMeta && cellIds.meta,\n ]\n .filter(Boolean)\n .join(\" \");\n const primary = useRender({\n render: render ?? (href != null ? <Link href={href} /> : undefined),\n defaultTagName: href != null ? \"a\" : onClick != null ? \"button\" : \"span\",\n props: {\n className: cn(\n \"text-pho-primary block min-w-0 max-w-full truncate text-left text-base font-medium outline-none\",\n code && \"font-mono text-xs\",\n // The one link, stretched over the row; the ring is the row's.\n interactive &&\n \"cursor-pointer after:absolute after:inset-0 after:content-['']\",\n ),\n onClick,\n type:\n render == null && href == null && onClick != null\n ? \"button\"\n : undefined,\n \"aria-current\": current ? \"page\" : undefined,\n \"aria-describedby\": describedBy || undefined,\n \"data-log-primary\": \"\",\n children: label,\n },\n });\n return (\n <div\n data-log-row=\"\"\n data-current={current || undefined}\n className={cn(\n \"relative flex min-h-12 min-w-0 items-center gap-3 px-5 py-2.5\",\n interactive &&\n \"hover:bg-pho-primary-hover outline-pho-brand transition-colors has-[[data-log-primary]:focus-visible]:outline-2 has-[[data-log-primary]:focus-visible]:-outline-offset-2\",\n current && \"bg-pho-primary-hover\",\n // The 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 {...props}\n >\n {id != null ? <IdCell id={id} cellId={cellIds.id} /> : null}\n {status != null ? (\n <span id={cellIds.status} className=\"flex shrink-0 items-center\">\n {status}\n </span>\n ) : null}\n {method != null ? <Method id={cellIds.method}>{method}</Method> : null}\n <div data-log-primary-cell=\"\" className=\"min-w-0 flex-1\">\n {primary}\n {description != null ? (\n <p className=\"text-pho-description truncate text-xs\">{description}</p>\n ) : null}\n </div>\n {hasMeta ? (\n <div\n id={cellIds.meta}\n className=\"text-pho-description ml-auto flex shrink-0 items-center gap-3 text-xs whitespace-nowrap tabular-nums\"\n >\n {children}\n {duration != null ? <span>{duration}</span> : null}\n {time != null ? <span>{time}</span> : null}\n </div>\n ) : null}\n </div>\n );\n}\n\n/* -------------------------------- states -------------------------------- */\n\nexport interface LogListEmptyProps extends Omit<\n ComponentProps<\"div\">,\n \"title\" | \"children\"\n> {\n /** One short line naming the state. @default \"Nothing here yet.\" */\n title?: ReactNode;\n /** What fills it, or why it is empty. */\n description?: ReactNode;\n /** An action, when there is one. */\n children?: ReactNode;\n}\n\n/** The list with no rows — `StatusView` at card size. */\nfunction Empty({\n title = \"Nothing here yet.\",\n description,\n children,\n className,\n ...props\n}: LogListEmptyProps) {\n return (\n <div className={cn(\"flex justify-center\", className)} {...props}>\n <StatusView\n size=\"sm\"\n title={title}\n description={description}\n actions={children}\n />\n </div>\n );\n}\n\n/** Bones in the rows' place while the first page is on its way. */\nfunction Loading({ rows = 5 }: { rows?: number }) {\n return (\n <>\n {Array.from({ length: rows }, (_, index) => (\n <div\n key={index}\n aria-hidden\n className=\"flex min-h-12 items-center gap-3 px-5 py-2.5\"\n >\n <Skeleton className=\"h-3.5 w-32\" />\n <Skeleton className=\"h-5 w-12 rounded-full\" />\n <Skeleton className=\"h-3.5 w-48\" />\n <Skeleton className=\"ml-auto h-3.5 w-16\" />\n </div>\n ))}\n </>\n );\n}\n\nexport interface LogListLoadMoreProps extends Omit<\n ComponentProps<\"div\">,\n \"children\"\n> {\n /** Asked for as the sentinel scrolls into view, and on the button. */\n onLoadMore: () => void;\n /** The next page is on its way — the sentinel shows a spinner and waits. */\n loading?: boolean;\n /** Nothing left to load — renders nothing. @default true */\n hasMore?: boolean;\n /** How far ahead of the viewport to ask. @default \"200px\" */\n rootMargin?: string;\n /** The button's words. @default \"Load more\" */\n label?: ReactNode;\n}\n\n/**\n * The sentinel at the end of the list. An `IntersectionObserver` asks for\n * the next page as it comes into view (`rootMargin` ahead of it); while\n * `loading` it shows a spinner and asks for nothing. The button is the\n * same request for keyboards and for a browser without the observer.\n * SSR-safe: the observer is created in an effect.\n */\nfunction LoadMore({\n onLoadMore,\n loading,\n hasMore = true,\n rootMargin = \"200px\",\n label = \"Load more\",\n className,\n ...props\n}: LogListLoadMoreProps) {\n const ref = useRef<HTMLDivElement | null>(null);\n const latest = useRef(onLoadMore);\n latest.current = onLoadMore;\n useEffect(() => {\n const el = ref.current;\n if (!hasMore || loading || el == null) return;\n if (typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) latest.current();\n },\n { rootMargin },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [hasMore, loading, rootMargin]);\n if (!hasMore) return null;\n return (\n <div\n ref={ref}\n data-log-load-more=\"\"\n aria-busy={loading || undefined}\n className={cn(\n \"flex min-h-12 items-center justify-center px-5 py-2\",\n className,\n )}\n {...props}\n >\n {loading ? (\n <Spinner aria-label=\"Loading more\" className=\"text-pho-secondary\" />\n ) : (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => onLoadMore()}>\n {label}\n </Button>\n )}\n </div>\n );\n}\n\n/* ---------------------------------- root -------------------------------- */\n\nexport interface LogListRootProps extends ComponentProps<\"div\"> {\n ref?: Ref<HTMLDivElement>;\n}\n\n/** The card the rows stack in. Mark it `aria-busy` while bones show. */\nfunction Root({ className, ...props }: LogListRootProps) {\n return (\n <div\n data-log-list=\"\"\n className={cn(LOG_LIST_SURFACE, \"min-w-0\", className)}\n {...props}\n />\n );\n}\n\n/**\n * Log List — a card of one-line log rows.\n *\n * ```tsx\n * <LogList.Root>\n * <LogList.Row\n * id=\"pho_req_01m04axjqrfzxv4xjet40a84gb\"\n * status={<LogList.Status value={200} />}\n * method=\"POST\"\n * code\n * label=\"/v1/messages\"\n * description=\"+1 332 259 3374 received a message from +1 332 222 1111.\"\n * duration=\"59 ms\"\n * time=\"2 min ago\"\n * href=\"/requests/pho_req_01m04axjqrfzxv4xjet40a84gb\"\n * />\n * <LogList.LoadMore onLoadMore={fetchNextPage} loading={isFetching} hasMore={hasNextPage} />\n * </LogList.Root>\n * ```\n */\nexport const LogList = {\n Root,\n Row,\n Status,\n Method,\n Empty,\n Loading,\n LoadMore,\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as d } from "./cn-ChIgwEl3.js";
|
|
3
|
+
import "../motion.js";
|
|
4
|
+
import { createContext as A, useContext as k, useLayoutEffect as C, useRef as b } from "react";
|
|
5
|
+
import { Fragment as L, jsx as i, jsxs as v } from "react/jsx-runtime";
|
|
6
|
+
import { motion as $ } from "motion/react";
|
|
7
|
+
import { ScrollArea as c } from "@base-ui/react/scroll-area";
|
|
8
|
+
var N = "pointer-events-none absolute inset-x-0 z-10 h-8", _ = 8, F = 1;
|
|
9
|
+
function P(t, e) {
|
|
10
|
+
const n = 100 / (t + 1);
|
|
11
|
+
return Array.from({ length: t }, (o, r) => ({
|
|
12
|
+
blurPx: r / (t - 1) * e,
|
|
13
|
+
window: [
|
|
14
|
+
r * n,
|
|
15
|
+
(r + 1) * n,
|
|
16
|
+
(r + 2) * n,
|
|
17
|
+
(r + 3) * n
|
|
18
|
+
]
|
|
19
|
+
})).filter((o) => o.blurPx > 0);
|
|
20
|
+
}
|
|
21
|
+
var T = P(_, F);
|
|
22
|
+
function U(t, e) {
|
|
23
|
+
const n = t === "top" ? "to top" : "to bottom", [o, r, l, s] = e;
|
|
24
|
+
return `linear-gradient(${n}, transparent ${o}%, black ${r}%, black ${l}%, transparent ${s}%)`;
|
|
25
|
+
}
|
|
26
|
+
var z = "var(--pho-surface, var(--background-color-pho-primary))";
|
|
27
|
+
function B(t, e) {
|
|
28
|
+
return `linear-gradient(${t === "top" ? "to top" : "to bottom"}, color-mix(in oklab, ${e} 20%, transparent) 0%, ${e} 100%)`;
|
|
29
|
+
}
|
|
30
|
+
function y(t, e) {
|
|
31
|
+
if (t)
|
|
32
|
+
for (const n of t.children) {
|
|
33
|
+
const o = n;
|
|
34
|
+
if (o.dataset.scrollFade === "wash") {
|
|
35
|
+
o.style.opacity = String(e);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const r = `blur(${Number(o.dataset.blurPx) * e}px)`;
|
|
39
|
+
o.style.backdropFilter = r, o.style.setProperty("-webkit-backdrop-filter", r);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function x({ edge: t, edgeRef: e, surface: n = z, className: o }) {
|
|
43
|
+
return /* @__PURE__ */ v("div", {
|
|
44
|
+
ref: e,
|
|
45
|
+
"aria-hidden": !0,
|
|
46
|
+
"data-edge": t,
|
|
47
|
+
className: d(N, o ?? (t === "top" ? "top-0" : "bottom-0")),
|
|
48
|
+
children: [T.map(({ blurPx: r, window: l }, s) => {
|
|
49
|
+
const a = U(t, l);
|
|
50
|
+
return /* @__PURE__ */ i("div", {
|
|
51
|
+
"data-blur-px": r,
|
|
52
|
+
className: "absolute inset-0",
|
|
53
|
+
style: {
|
|
54
|
+
maskImage: a,
|
|
55
|
+
WebkitMaskImage: a
|
|
56
|
+
}
|
|
57
|
+
}, s);
|
|
58
|
+
}), /* @__PURE__ */ i("div", {
|
|
59
|
+
"data-scroll-fade": "wash",
|
|
60
|
+
className: "absolute inset-0 opacity-0",
|
|
61
|
+
style: { background: B(t, n) }
|
|
62
|
+
})]
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
var R = A(null);
|
|
66
|
+
function H() {
|
|
67
|
+
const t = k(R);
|
|
68
|
+
if (t == null) throw new Error("ScrollArea parts must be used inside ScrollArea.Root");
|
|
69
|
+
return t;
|
|
70
|
+
}
|
|
71
|
+
function E(t) {
|
|
72
|
+
return t <= 0 ? 0 : t >= 1 ? 1 : t;
|
|
73
|
+
}
|
|
74
|
+
function M(t, e) {
|
|
75
|
+
typeof t == "function" ? t(e) : t && (t.current = e);
|
|
76
|
+
}
|
|
77
|
+
function O({ inset: t, insetTop: e, insetBottom: n, style: o, ref: r, ...l }) {
|
|
78
|
+
return /* @__PURE__ */ i(c.Content, {
|
|
79
|
+
ref: r,
|
|
80
|
+
style: {
|
|
81
|
+
paddingTop: e ?? t,
|
|
82
|
+
paddingBottom: n ?? t,
|
|
83
|
+
...o
|
|
84
|
+
},
|
|
85
|
+
...l
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
var X = c.Corner;
|
|
89
|
+
function j({ className: t, children: e, fade: n = !0, ...o }) {
|
|
90
|
+
const r = b(null), l = b(null);
|
|
91
|
+
return /* @__PURE__ */ i(c.Root, {
|
|
92
|
+
className: d("relative overflow-hidden", t),
|
|
93
|
+
...o,
|
|
94
|
+
children: /* @__PURE__ */ v(R.Provider, {
|
|
95
|
+
value: {
|
|
96
|
+
topEl: r,
|
|
97
|
+
bottomEl: l,
|
|
98
|
+
fade: n
|
|
99
|
+
},
|
|
100
|
+
children: [e, n ? /* @__PURE__ */ v(L, { children: [/* @__PURE__ */ i(x, {
|
|
101
|
+
edge: "top",
|
|
102
|
+
edgeRef: r
|
|
103
|
+
}), /* @__PURE__ */ i(x, {
|
|
104
|
+
edge: "bottom",
|
|
105
|
+
edgeRef: l
|
|
106
|
+
})] }) : null]
|
|
107
|
+
})
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function D({ className: t, ref: e, ...n }) {
|
|
111
|
+
const { topEl: o, bottomEl: r, fade: l } = H(), s = b(null);
|
|
112
|
+
return C(() => {
|
|
113
|
+
const a = s.current;
|
|
114
|
+
if (!a || !l) return;
|
|
115
|
+
const m = () => {
|
|
116
|
+
const g = o.current?.offsetHeight || r.current?.offsetHeight || 32, p = a.scrollHeight - a.clientHeight, w = p <= 0 ? 0 : E(a.scrollTop / g), S = p <= 0 ? 0 : E((p - a.scrollTop) / g);
|
|
117
|
+
y(o.current, w), y(r.current, S);
|
|
118
|
+
};
|
|
119
|
+
let u = 0;
|
|
120
|
+
const h = () => {
|
|
121
|
+
u || (u = requestAnimationFrame(() => {
|
|
122
|
+
u = 0, m();
|
|
123
|
+
}));
|
|
124
|
+
};
|
|
125
|
+
m(), a.addEventListener("scroll", h, { passive: !0 });
|
|
126
|
+
let f = null;
|
|
127
|
+
return typeof ResizeObserver < "u" && (f = new ResizeObserver(m), f.observe(a), a.firstElementChild && f.observe(a.firstElementChild)), () => {
|
|
128
|
+
a.removeEventListener("scroll", h), u && cancelAnimationFrame(u), f?.disconnect();
|
|
129
|
+
};
|
|
130
|
+
}, [
|
|
131
|
+
o,
|
|
132
|
+
r,
|
|
133
|
+
l
|
|
134
|
+
]), /* @__PURE__ */ i(c.Viewport, {
|
|
135
|
+
render: /* @__PURE__ */ i($.div, { layoutScroll: !0 }),
|
|
136
|
+
className: d("outline-pho-brand h-full min-h-0 w-full overscroll-contain rounded-[inherit] focus-visible:outline-2 focus-visible:-outline-offset-1", t),
|
|
137
|
+
...n,
|
|
138
|
+
ref: (a) => {
|
|
139
|
+
s.current = a, M(e, a);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function G({ className: t, ...e }) {
|
|
144
|
+
return /* @__PURE__ */ i(c.Scrollbar, {
|
|
145
|
+
className: d("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),
|
|
146
|
+
...e
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function I({ className: t, ...e }) {
|
|
150
|
+
return /* @__PURE__ */ i(c.Thumb, {
|
|
151
|
+
className: d("flex-1 rounded-full bg-[var(--border-color-pho-primary)]", t),
|
|
152
|
+
...e
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
var Z = {
|
|
156
|
+
Root: j,
|
|
157
|
+
Viewport: D,
|
|
158
|
+
Content: O,
|
|
159
|
+
Scrollbar: G,
|
|
160
|
+
Thumb: I,
|
|
161
|
+
Corner: X
|
|
162
|
+
};
|
|
163
|
+
export {
|
|
164
|
+
F as n,
|
|
165
|
+
Z as t
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
//# sourceMappingURL=scroll-area-Zik8t1Mk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-area-Zik8t1Mk.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 { BLUR_PX } from \"../../motion\";\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;\n\n/**\n * The system's one blur strength. The edge fade peaks here, and a motion\n * that softens (a scope swap, a bar title) borrows the same value, so\n * every soft focus in the product is the same soft focus.\n */\nexport const BLUR_MAX_PX = BLUR_PX;\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\n// The wash fades into the block it sits on: every `bg-pho-*` surface\n// registers itself as `--pho-surface` (see the stylesheet), so the nearest\n// surface ancestor's background carries down here — live across themes.\n// The primary surface is the fallback for hosts outside any pho surface.\nconst DEFAULT_SURFACE =\n \"var(--pho-surface, var(--background-color-pho-primary))\";\n\nfunction washGradient(edge: \"top\" | \"bottom\", surface: string) {\n const to = edge === \"top\" ? \"to top\" : \"to bottom\";\n return `linear-gradient(${to}, color-mix(in oklab, ${surface} 20%, transparent) 0%, ${surface} 100%)`;\n}\n\nexport function paintEdge(node: HTMLDivElement | null, progress: number) {\n if (!node) return;\n for (const child of node.children) {\n const el = child as HTMLElement;\n if (el.dataset.scrollFade === \"wash\") {\n el.style.opacity = String(progress);\n continue;\n }\n const blur = `blur(${Number(el.dataset.blurPx) * progress}px)`;\n el.style.backdropFilter = blur;\n el.style.setProperty(\"-webkit-backdrop-filter\", blur);\n }\n}\n\nexport function Edge({\n edge,\n edgeRef,\n surface = DEFAULT_SURFACE,\n className,\n}: {\n edge: \"top\" | \"bottom\";\n edgeRef: Ref<HTMLDivElement>;\n /** The surface the wash fades into — the card by default, or a page. */\n surface?: string;\n /** Position override — the strip sits at the named edge unless placed. */\n className?: string;\n}) {\n return (\n <div\n ref={edgeRef}\n aria-hidden\n data-edge={edge}\n className={cn(\n EDGE_CLASS,\n className ?? (edge === \"top\" ? \"top-0\" : \"bottom-0\"),\n )}\n >\n {BLUR_LAYERS.map(({ blurPx, window }, index) => {\n const mask = edgeMask(edge, window);\n return (\n <div\n key={index}\n data-blur-px={blurPx}\n className=\"absolute inset-0\"\n style={{\n maskImage: mask,\n WebkitMaskImage: mask,\n }}\n />\n );\n })}\n <div\n data-scroll-fade=\"wash\"\n className=\"absolute inset-0 opacity-0\"\n style={{ background: washGradient(edge, surface) }}\n />\n </div>\n );\n}\n","import {\n createContext,\n useContext,\n useLayoutEffect,\n useRef,\n type ComponentProps,\n type ElementType,\n type Ref,\n type RefObject,\n} from \"react\";\nimport { ScrollArea as BaseScrollArea } from \"@base-ui/react/scroll-area\";\nimport { motion } from \"motion/react\";\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 fade: boolean;\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\n/**\n * The scrolled content. `inset` is a resting inset in the scroll axis —\n * like a scroll view's safe-area padding: the content stands clear of the\n * edges at rest but scrolls past them to the true edge, and the scrollbar\n * and edge fade stay on `Root`'s edges. `insetTop` / `insetBottom` set the\n * ends separately (they win over `inset`).\n */\nfunction Content({\n inset,\n insetTop,\n insetBottom,\n style,\n ref,\n ...props\n}: ComponentProps<typeof BaseScrollArea.Content> & {\n inset?: number | string;\n insetTop?: number | string;\n insetBottom?: number | string;\n ref?: Ref<HTMLDivElement>;\n}) {\n return (\n <BaseScrollArea.Content\n ref={ref}\n style={{\n paddingTop: insetTop ?? inset,\n paddingBottom: insetBottom ?? inset,\n ...style,\n }}\n {...props}\n />\n );\n}\n\nconst Corner = BaseScrollArea.Corner;\n\nfunction Root({\n className,\n children,\n fade = true,\n ...props\n}: StyledProps<typeof BaseScrollArea.Root> & {\n /**\n * Progressive edge fade (blur + wash). Leave on except for code\n * surfaces — CodeBlock is the only caller that turns it off, so\n * glyphs hard-clip at the border.\n * @default true\n */\n fade?: boolean;\n}) {\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, fade }}>\n {children}\n {fade ? (\n <>\n <Edge edge=\"top\" edgeRef={topEl} />\n <Edge edge=\"bottom\" edgeRef={bottomEl} />\n </>\n ) : null}\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, fade } = useScrollAreaContext();\n const viewportRef = useRef<HTMLElement | null>(null);\n\n useLayoutEffect(() => {\n const viewport = viewportRef.current;\n if (!viewport || !fade) 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, fade]);\n\n return (\n <BaseScrollArea.Viewport\n // A motion element with layoutScroll: any layout-animated content\n // inside (a shared-element morph, a FLIP row) projects against the\n // viewport's scroll offset instead of reading a scroll as a layout\n // change.\n render={<motion.div layoutScroll />}\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":";;;;;;;AAKA,IAAa,IAAa,mDAGpB,IAAmB,GAOZ,IAAA;AAEb,SAAS,EAAgB,GAAe,GAAe;AACrD,QAAM,IAAU,OAAO,IAAQ;AAC/B,SAAO,MAAM,KAAK,EAAE,QAAQ,EAAM,GAAA,CAAI,GAAG,OAAO;AAAA,IAC9C,QAAS,KAAK,IAAQ,KAAM;AAAA,IAC5B,QAAQ;AAAA,MACN,IAAI;AAAA,OACH,IAAI,KAAK;AAAA,OACT,IAAI,KAAK;AAAA,OACT,IAAI,KAAK;AAAA,IACZ;AAAA,EACF,EAAE,EAAE,OAAA,CAAQ,MAAU,EAAM,SAAS,CAAC;AACxC;AAEA,IAAM,IAAc,EAAgB,GAAkB,CAAW;AAEjE,SAAS,EAAS,GAAwB,GAA2B;AACnE,QAAM,IAAS,MAAS,QAAQ,WAAW,aACrC,CAAC,GAAG,GAAG,GAAG,CAAA,IAAK;AACrB,SAAO,mBAAmB,CAAA,iBAAuB,CAAA,YAAa,CAAA,YAAa,CAAA,kBAAmB,CAAA;AAChG;AAMA,IAAM,IACJ;AAEF,SAAS,EAAa,GAAwB,GAAiB;AAE7D,SAAO,mBADI,MAAS,QAAQ,WAAW,WAAA,yBACc,CAAA,0BAAiC,CAAA;AACxF;AAEA,SAAgB,EAAU,GAA6B,GAAkB;AACvE,MAAK;AACL,eAAW,KAAS,EAAK,UAAU;AACjC,YAAM,IAAK;AACX,UAAI,EAAG,QAAQ,eAAe,QAAQ;AACpC,QAAA,EAAG,MAAM,UAAU,OAAO,CAAQ;AAClC;AAAA,MACF;AACA,YAAM,IAAO,QAAQ,OAAO,EAAG,QAAQ,MAAM,IAAI,CAAA;AACjD,MAAA,EAAG,MAAM,iBAAiB,GAC1B,EAAG,MAAM,YAAY,2BAA2B,CAAI;AAAA,IACtD;AACF;AAEA,SAAgB,EAAK,EACnB,MAAA,GACA,SAAA,GACA,SAAA,IAAU,GACV,WAAA,EAAA,GAQC;AACD,SACE,gBAAA,EAAC,OAAD;AAAA,IACE,KAAK;AAAA,IACL,eAAA;AAAA,IACA,aAAW;AAAA,IACX,WAAW,EACT,GACA,MAAc,MAAS,QAAQ,UAAU,WAC3C;AAAA,IAPF,UAAA,CASG,EAAY,IAAA,CAAK,EAAE,QAAA,GAAQ,QAAA,EAAA,GAAU,MAAU;AAC9C,YAAM,IAAO,EAAS,GAAM,CAAM;AAClC,aACE,gBAAA,EAAC,OAAD;AAAA,QAEE,gBAAc;AAAA,QACd,WAAU;AAAA,QACV,OAAO;AAAA,UACL,WAAW;AAAA,UACX,iBAAiB;AAAA,QACnB;AAAA,MACD,GAPM,CAON;AAAA,IAEL,CAAC,GACD,gBAAA,EAAC,OAAD;AAAA,MACE,oBAAiB;AAAA,MACjB,WAAU;AAAA,MACV,OAAO,EAAE,YAAY,EAAa,GAAM,CAAO,EAAE;AAAA,IAClD,CAAA,CACE;AAAA;AAET;ACrFA,IAAM,IAAoB,EAIhB,IAAI;AAEd,SAAS,IAAuB;AAC9B,QAAM,IAAM,EAAW,CAAiB;AACxC,MAAI,KAAO,KACT,OAAM,IAAI,MAAM,sDAAsD;AAExE,SAAO;AACT;AAEA,SAAS,EAAQ,GAAW;AAC1B,SAAI,KAAK,IAAU,IACf,KAAK,IAAU,IACZ;AACT;AAEA,SAAS,EAAa,GAAyB,GAAgB;AAC7D,EAAI,OAAO,KAAQ,aACjB,EAAI,CAAI,IACC,MAET,EAA+B,UAAU;AAE7C;AASA,SAAS,EAAQ,EACf,OAAA,GACA,UAAA,GACA,aAAA,GACA,OAAA,GACA,KAAA,GACA,GAAG,EAAA,GAMF;AACD,SACE,gBAAA,EAAC,EAAe,SAAhB;AAAA,IACO,KAAA;AAAA,IACL,OAAO;AAAA,MACL,YAAY,KAAY;AAAA,MACxB,eAAe,KAAe;AAAA,MAC9B,GAAG;AAAA,IACL;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,IAAM,IAAS,EAAe;AAE9B,SAAS,EAAK,EACZ,WAAA,GACA,UAAA,GACA,MAAA,IAAO,IACP,GAAG,EAAA,GASF;AACD,QAAM,IAAQ,EAA8B,IAAI,GAC1C,IAAW,EAA8B,IAAI;AAEnD,SACE,gBAAA,EAAC,EAAe,MAAhB;AAAA,IACE,WAAW,EAAG,4BAA4B,CAAS;AAAA,IACnD,GAAI;AAAA,IAEJ,UAAA,gBAAA,EAAC,EAAkB,UAAnB;AAAA,MAA4B,OAAO;AAAA,QAAE,OAAA;AAAA,QAAO,UAAA;AAAA,QAAU,MAAA;AAAA,MAAK;AAAA,MAA3D,UAAA,CACG,GACA,IACC,gBAAA,EAAA,GAAA,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAK;AAAA,QAAM,SAAS;AAAA,MAAQ,CAAA,GAClC,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAK;AAAA,QAAS,SAAS;AAAA,MAAW,CAAA,CACxC,EAAA,CAAA,IACA,IACsB;AAAA;EACT,CAAA;AAEzB;AAEA,SAAS,EAAS,EAChB,WAAA,GACA,KAAA,GACA,GAAG,EAAA,GAC2C;AAC9C,QAAM,EAAE,OAAA,GAAO,UAAA,GAAU,MAAA,EAAA,IAAS,EAAqB,GACjD,IAAc,EAA2B,IAAI;AAEnD,SAAA,EAAA,MAAsB;AACpB,UAAM,IAAW,EAAY;AAC7B,QAAI,CAAC,KAAY,CAAC,EAAM;AAExB,UAAM,IAAA,MAAc;AAClB,YAAM,IACJ,EAAM,SAAS,gBACf,EAAS,SAAS,gBAAA,IAEd,IAAY,EAAS,eAAe,EAAS,cAC7C,IAAM,KAAa,IAAI,IAAI,EAAQ,EAAS,YAAY,CAAM,GAC9D,IACJ,KAAa,IAAI,IAAI,GAAS,IAAY,EAAS,aAAa,CAAM;AACxE,MAAA,EAAU,EAAM,SAAS,CAAG,GAC5B,EAAU,EAAS,SAAS,CAAM;AAAA,IACpC;AAEA,QAAI,IAAQ;AACZ,UAAM,IAAA,MAAiB;AACrB,MAAI,MACJ,IAAQ,sBAAA,MAA4B;AAClC,QAAA,IAAQ,GACR,EAAM;AAAA,MACR,CAAC;AAAA,IACH;AAEA,IAAA,EAAM,GACN,EAAS,iBAAiB,UAAU,GAAU,EAAE,SAAS,GAAK,CAAC;AAC/D,QAAI,IAAkC;AACtC,WAAI,OAAO,iBAAmB,QAC5B,IAAW,IAAI,eAAe,CAAK,GACnC,EAAS,QAAQ,CAAQ,GACrB,EAAS,qBACX,EAAS,QAAQ,EAAS,iBAAiB,IAG/C,MAAa;AACX,MAAA,EAAS,oBAAoB,UAAU,CAAQ,GAC3C,KAAO,qBAAqB,CAAK,GACrC,GAAU,WAAW;AAAA,IACvB;AAAA,EACF,GAAG;AAAA,IAAC;AAAA,IAAO;AAAA,IAAU;AAAA,EAAI,CAAC,GAGxB,gBAAA,EAAC,EAAe,UAAhB;AAAA,IAKE,QAAQ,gBAAA,EAAC,EAAO,KAAR,EAAY,cAAA,GAAc,CAAA;AAAA,IAClC,WAAW,EACT,wIACA,CACF;AAAA,IACA,GAAI;AAAA,IACJ,KAAA,CAAM,MAAS;AACb,MAAA,EAAY,UAAU,GACtB,EAAU,GAAK,CAAI;AAAA,IACrB;AAAA,EACD,CAAA;AAEL;AAEA,SAAS,EAAU,EACjB,WAAA,GACA,GAAG,EAAA,GAC4C;AAC/C,SACE,gBAAA,EAAC,EAAe,WAAhB;AAAA,IACE,WAAW,EACT,0FACA,yIACA,gHACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,SAAS,EAAM,EACb,WAAA,GACA,GAAG,EAAA,GACwC;AAC3C,SACE,gBAAA,EAAC,EAAe,OAAhB;AAAA,IACE,WAAW,EACT,4DACA,CACF;AAAA,IACA,GAAI;AAAA,EACL,CAAA;AAEL;AASA,IAAa,IAAa;AAAA,EACxB,MAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AACF"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as n } from "./cn-ChIgwEl3.js";
|
|
3
|
+
import { t as ee } from "./is-react-component-DSnjtBmo.js";
|
|
4
|
+
import { n as te } from "./link-provider-DXzDQ08N.js";
|
|
5
|
+
import { SPRING_PRESS as re } from "../motion.js";
|
|
6
|
+
import { a as ae, u as ne } from "./button-CdqS_t5a.js";
|
|
7
|
+
import { t as oe } from "./createReactComponent-BqCmnqfX.js";
|
|
8
|
+
import { t as se } from "./IconArrowUpRight-DGgKzQwV.js";
|
|
9
|
+
import { t as ie } from "./IconChevronRight-CzoJnYNI.js";
|
|
10
|
+
import { n as _ } from "./avatar-BkmGDIqf.js";
|
|
11
|
+
import { t as le } from "./IconSearch-BKAHkLyX.js";
|
|
12
|
+
import { t as h } from "./scroll-area-Zik8t1Mk.js";
|
|
13
|
+
import { t as L } from "./collapsible-if7ncPbI.js";
|
|
14
|
+
import { t as ce } from "./kbd-DNI10uy7.js";
|
|
15
|
+
import { createContext as P, isValidElement as ue, useCallback as z, useContext as G, useEffect as T, useId as pe, useLayoutEffect as me, useMemo as K, useRef as w, useState as C } from "react";
|
|
16
|
+
import { Fragment as de, jsx as t, jsxs as c } from "react/jsx-runtime";
|
|
17
|
+
import { motion as g } from "motion/react";
|
|
18
|
+
import { Collapsible as fe } from "@base-ui/react/collapsible";
|
|
19
|
+
var he = [
|
|
20
|
+
["path", {
|
|
21
|
+
d: "M4 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",
|
|
22
|
+
key: "svg-0"
|
|
23
|
+
}],
|
|
24
|
+
["path", {
|
|
25
|
+
d: "M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",
|
|
26
|
+
key: "svg-1"
|
|
27
|
+
}],
|
|
28
|
+
["path", {
|
|
29
|
+
d: "M18 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0",
|
|
30
|
+
key: "svg-2"
|
|
31
|
+
}]
|
|
32
|
+
], xe = oe("outline", "dots", "Dots", he), I = {
|
|
33
|
+
initial: !1,
|
|
34
|
+
whileTap: { scale: 0.97 },
|
|
35
|
+
transition: re
|
|
36
|
+
}, H = "border-pho-secondary bg-pho-page sticky top-0 flex h-dvh w-64 shrink-0 flex-col border-r", j = {
|
|
37
|
+
base: "px-4 pt-5 pb-4",
|
|
38
|
+
sm: "px-3 pt-4 pb-3"
|
|
39
|
+
}, Qe = n(H, j.base), ve = {
|
|
40
|
+
base: "mb-6 px-2",
|
|
41
|
+
sm: "mb-3 px-0"
|
|
42
|
+
}, q = "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", be = "bg-pho-primary text-pho-primary ring-pho-secondary font-medium ring-1 ring-inset *:data-icon:text-pho-primary", $ = n("text-pho-secondary *:data-icon:text-pho-secondary", "hover:bg-pho-primary hover:text-pho-primary hover:*:data-icon:text-pho-primary"), We = "text-pho-primary *:data-icon:text-pho-primary", ge = "ml-auto size-4 shrink-0 transition-transform duration-150 ease-out", V = {
|
|
43
|
+
withIcon: "pl-6",
|
|
44
|
+
withoutIcon: "pl-4"
|
|
45
|
+
}, J = P("base"), Q = P(null), W = typeof window > "u" ? T : me;
|
|
46
|
+
function Ie({ className: r, inset: e = "base", ...a }) {
|
|
47
|
+
return /* @__PURE__ */ t(J.Provider, {
|
|
48
|
+
value: e,
|
|
49
|
+
children: /* @__PURE__ */ t("aside", {
|
|
50
|
+
className: n(H, j[e], r),
|
|
51
|
+
...a,
|
|
52
|
+
"data-inset": e
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function Ne({ className: r, ...e }) {
|
|
57
|
+
const a = G(J);
|
|
58
|
+
return /* @__PURE__ */ t("div", {
|
|
59
|
+
className: n("flex items-center gap-2.5 [&:has(+nav)]:mb-0", ve[a], r),
|
|
60
|
+
...e
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function ye({ label: r = "Search", kbd: e = "⌘K", className: a, ...s }) {
|
|
64
|
+
return /* @__PURE__ */ t(ae, {
|
|
65
|
+
variant: "outlined",
|
|
66
|
+
shape: "square",
|
|
67
|
+
size: "md",
|
|
68
|
+
"aria-keyshortcuts": e === "⌘K" ? "Meta+K Control+K" : void 0,
|
|
69
|
+
prefix: /* @__PURE__ */ t(le, { "aria-hidden": !0 }),
|
|
70
|
+
suffix: /* @__PURE__ */ t(ce, {
|
|
71
|
+
keys: e,
|
|
72
|
+
className: "pointer-events-none"
|
|
73
|
+
}),
|
|
74
|
+
className: n("hover:ring-pho-secondary min-h-9 w-full justify-start gap-2 rounded-sm px-2 py-1.5 has-[[data-icon=prefix]]:pl-2 has-[[data-icon=suffix]]:pr-2 [&>[data-text]]:min-w-0 [&>[data-text]]:flex-1 [&>[data-text]]:truncate [&>[data-text]]:px-0 [&>[data-text]]:text-left", a),
|
|
75
|
+
...s,
|
|
76
|
+
children: r
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function Re({ scroll: r = !0, inset: e, insetTop: a = e ?? 24, insetBottom: s = e ?? 16, className: i, style: l, children: u, ...p }) {
|
|
80
|
+
return r ? /* @__PURE__ */ t("nav", {
|
|
81
|
+
className: n("flex min-h-0 flex-1 flex-col", i),
|
|
82
|
+
style: l,
|
|
83
|
+
...p,
|
|
84
|
+
children: /* @__PURE__ */ c(h.Root, {
|
|
85
|
+
className: "min-h-0 flex-1",
|
|
86
|
+
children: [/* @__PURE__ */ t(h.Viewport, { children: /* @__PURE__ */ t(h.Content, {
|
|
87
|
+
inset: e,
|
|
88
|
+
insetTop: a,
|
|
89
|
+
insetBottom: s,
|
|
90
|
+
className: "flex flex-col gap-6",
|
|
91
|
+
children: u
|
|
92
|
+
}) }), /* @__PURE__ */ t(h.Scrollbar, { children: /* @__PURE__ */ t(h.Thumb, {}) })]
|
|
93
|
+
})
|
|
94
|
+
}) : /* @__PURE__ */ t("nav", {
|
|
95
|
+
className: n("flex flex-col gap-6", i),
|
|
96
|
+
style: {
|
|
97
|
+
paddingTop: a ?? e,
|
|
98
|
+
paddingBottom: s ?? e,
|
|
99
|
+
...l
|
|
100
|
+
},
|
|
101
|
+
...p,
|
|
102
|
+
children: u
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function Se({ className: r, ...e }) {
|
|
106
|
+
return /* @__PURE__ */ t("div", {
|
|
107
|
+
className: r,
|
|
108
|
+
...e
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function Ee({ className: r, ...e }) {
|
|
112
|
+
return /* @__PURE__ */ t("div", {
|
|
113
|
+
className: n("text-pho-description mb-2 px-2 text-xs font-normal", r),
|
|
114
|
+
...e
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function X({ className: r, columns: e, ...a }) {
|
|
118
|
+
return /* @__PURE__ */ t("ul", {
|
|
119
|
+
className: n("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),
|
|
120
|
+
...a
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function Ae({ className: r, ...e }) {
|
|
124
|
+
return /* @__PURE__ */ t("div", {
|
|
125
|
+
className: n("mt-4 flex flex-col gap-0.5 [nav~&]:mt-0", r),
|
|
126
|
+
...e
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function b(r) {
|
|
130
|
+
if (r == null || r === !1) return null;
|
|
131
|
+
let e = null;
|
|
132
|
+
return ee(r) ? e = /* @__PURE__ */ t(r, {}) : ue(r) && (e = r), e == null ? null : /* @__PURE__ */ t("span", {
|
|
133
|
+
"data-icon": !0,
|
|
134
|
+
className: "pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-4 [&>svg]:shrink-0",
|
|
135
|
+
children: e
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function _e({ icon: r, active: e, className: a, children: s, href: i, external: l, ...u }) {
|
|
139
|
+
const p = te(), N = K(() => g.create(p), [p]), m = G(Q), f = pe();
|
|
140
|
+
W(() => {
|
|
141
|
+
if (m)
|
|
142
|
+
return m.reportActive(f, !!e), () => m.reportActive(f, !1);
|
|
143
|
+
}, [
|
|
144
|
+
m,
|
|
145
|
+
f,
|
|
146
|
+
e
|
|
147
|
+
]);
|
|
148
|
+
const x = n(q, e ? be : $, a), d = /* @__PURE__ */ t("span", {
|
|
149
|
+
className: "min-w-0 flex-1 truncate",
|
|
150
|
+
children: s
|
|
151
|
+
});
|
|
152
|
+
return i !== void 0 ? /* @__PURE__ */ t("li", { children: /* @__PURE__ */ c(N, {
|
|
153
|
+
href: i,
|
|
154
|
+
"aria-current": e ? "page" : void 0,
|
|
155
|
+
...l && {
|
|
156
|
+
target: "_blank",
|
|
157
|
+
rel: "noopener noreferrer"
|
|
158
|
+
},
|
|
159
|
+
...u,
|
|
160
|
+
className: x,
|
|
161
|
+
...I,
|
|
162
|
+
children: [
|
|
163
|
+
b(r),
|
|
164
|
+
d,
|
|
165
|
+
l && /* @__PURE__ */ c(de, { children: [b(/* @__PURE__ */ t(se, { "aria-hidden": !0 })), /* @__PURE__ */ t("span", {
|
|
166
|
+
className: "sr-only",
|
|
167
|
+
children: "(opens in a new tab)"
|
|
168
|
+
})] })
|
|
169
|
+
]
|
|
170
|
+
}) }) : /* @__PURE__ */ t("li", { children: /* @__PURE__ */ c(g.button, {
|
|
171
|
+
type: "button",
|
|
172
|
+
"aria-current": e ? "page" : void 0,
|
|
173
|
+
...u,
|
|
174
|
+
className: x,
|
|
175
|
+
...I,
|
|
176
|
+
children: [b(r), d]
|
|
177
|
+
}) });
|
|
178
|
+
}
|
|
179
|
+
function we({ label: r, icon: e, open: a, defaultOpen: s = !1, onOpenChange: i, openWhenChildActive: l = !0, active: u, className: p, children: N, ...m }) {
|
|
180
|
+
const [f, x] = C(s), d = a !== void 0, y = d ? a : f, R = z((o) => {
|
|
181
|
+
d || x(o), i?.(o);
|
|
182
|
+
}, [d, i]), [B, Y] = C(() => /* @__PURE__ */ new Set()), O = z((o, F) => {
|
|
183
|
+
Y((E) => {
|
|
184
|
+
if (E.has(o) === F) return E;
|
|
185
|
+
const A = new Set(E);
|
|
186
|
+
return F ? A.add(o) : A.delete(o), A;
|
|
187
|
+
});
|
|
188
|
+
}, []), Z = K(() => ({ reportActive: O }), [O]), v = u ?? B.size > 0, D = w(!1);
|
|
189
|
+
T(() => {
|
|
190
|
+
const o = requestAnimationFrame(() => {
|
|
191
|
+
D.current = !0;
|
|
192
|
+
});
|
|
193
|
+
return () => cancelAnimationFrame(o);
|
|
194
|
+
}, []);
|
|
195
|
+
const [S, k] = C(!1), M = w(y);
|
|
196
|
+
M.current = y;
|
|
197
|
+
const U = w(R);
|
|
198
|
+
return U.current = R, W(() => {
|
|
199
|
+
!l || !v || M.current || (D.current || k(!0), U.current(!0));
|
|
200
|
+
}, [
|
|
201
|
+
B,
|
|
202
|
+
v,
|
|
203
|
+
l
|
|
204
|
+
]), T(() => {
|
|
205
|
+
if (!S) return;
|
|
206
|
+
const o = requestAnimationFrame(() => k(!1));
|
|
207
|
+
return () => cancelAnimationFrame(o);
|
|
208
|
+
}, [S]), /* @__PURE__ */ c(L.Root, {
|
|
209
|
+
open: y,
|
|
210
|
+
onOpenChange: (o) => R(o),
|
|
211
|
+
render: /* @__PURE__ */ t("li", {}),
|
|
212
|
+
children: [/* @__PURE__ */ c(fe.Trigger, {
|
|
213
|
+
render: /* @__PURE__ */ t(g.button, { ...I }),
|
|
214
|
+
className: n(q, $, v && "text-pho-primary *:data-icon:text-pho-primary", "data-[panel-open]:*:data-chevron:rotate-90", p),
|
|
215
|
+
"data-child-active": v || void 0,
|
|
216
|
+
...m,
|
|
217
|
+
children: [
|
|
218
|
+
b(e),
|
|
219
|
+
/* @__PURE__ */ t("span", {
|
|
220
|
+
className: "min-w-0 flex-1 truncate",
|
|
221
|
+
children: r
|
|
222
|
+
}),
|
|
223
|
+
/* @__PURE__ */ t(ie, {
|
|
224
|
+
"aria-hidden": !0,
|
|
225
|
+
"data-chevron": !0,
|
|
226
|
+
className: ge
|
|
227
|
+
})
|
|
228
|
+
]
|
|
229
|
+
}), /* @__PURE__ */ t(L.Panel, {
|
|
230
|
+
keepMounted: !0,
|
|
231
|
+
style: S ? { transitionDuration: "0s" } : void 0,
|
|
232
|
+
children: /* @__PURE__ */ t(Q.Provider, {
|
|
233
|
+
value: Z,
|
|
234
|
+
children: /* @__PURE__ */ t("div", {
|
|
235
|
+
"data-submenu-list": !0,
|
|
236
|
+
className: n("pt-0.5", e ? V.withIcon : V.withoutIcon),
|
|
237
|
+
children: /* @__PURE__ */ t(X, { children: N })
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
})]
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
var Ce = "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";
|
|
244
|
+
function Te(r) {
|
|
245
|
+
const e = r.split(/\s+/).filter(Boolean);
|
|
246
|
+
return ((e[0]?.[0] ?? r[0] ?? "?") + (e.length >= 2 ? e[e.length - 1]?.[0] ?? "" : "")).toUpperCase();
|
|
247
|
+
}
|
|
248
|
+
function Be({ name: r, avatarSrc: e, initials: a, className: s, ...i }) {
|
|
249
|
+
return /* @__PURE__ */ c(g.button, {
|
|
250
|
+
type: "button",
|
|
251
|
+
className: n(Ce, s),
|
|
252
|
+
...i,
|
|
253
|
+
...I,
|
|
254
|
+
children: [
|
|
255
|
+
/* @__PURE__ */ c(_.Root, {
|
|
256
|
+
size: "xs",
|
|
257
|
+
children: [e && /* @__PURE__ */ t(_.Image, {
|
|
258
|
+
src: e,
|
|
259
|
+
alt: ""
|
|
260
|
+
}), /* @__PURE__ */ t(_.Fallback, { children: a ?? Te(r) })]
|
|
261
|
+
}),
|
|
262
|
+
/* @__PURE__ */ t("span", {
|
|
263
|
+
className: "text-pho-primary min-w-0 flex-1 truncate text-base",
|
|
264
|
+
children: r
|
|
265
|
+
}),
|
|
266
|
+
/* @__PURE__ */ t("span", {
|
|
267
|
+
"aria-hidden": !0,
|
|
268
|
+
className: ne({
|
|
269
|
+
variant: "outlined",
|
|
270
|
+
size: "sm",
|
|
271
|
+
shape: "circle",
|
|
272
|
+
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"
|
|
273
|
+
}),
|
|
274
|
+
children: /* @__PURE__ */ t(xe, { className: "size-4" })
|
|
275
|
+
})
|
|
276
|
+
]
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
var Xe = {
|
|
280
|
+
Root: Ie,
|
|
281
|
+
Header: Ne,
|
|
282
|
+
Search: ye,
|
|
283
|
+
Nav: Re,
|
|
284
|
+
Group: Se,
|
|
285
|
+
GroupLabel: Ee,
|
|
286
|
+
List: X,
|
|
287
|
+
Item: _e,
|
|
288
|
+
Submenu: we,
|
|
289
|
+
Footer: Ae,
|
|
290
|
+
AccountRow: Be
|
|
291
|
+
};
|
|
292
|
+
export {
|
|
293
|
+
H as a,
|
|
294
|
+
ge as c,
|
|
295
|
+
Xe as d,
|
|
296
|
+
$ as i,
|
|
297
|
+
V as l,
|
|
298
|
+
q as n,
|
|
299
|
+
Qe as o,
|
|
300
|
+
be as r,
|
|
301
|
+
j as s,
|
|
302
|
+
ve as t,
|
|
303
|
+
We as u
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
//# sourceMappingURL=sidebar-DRPe5CAh.js.map
|