@photon-ai/pho-ui 4.5.1 → 4.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/chunks/{basic-page-dQ86NSIy.js → basic-page-C0DvO_Vt.js} +492 -489
  2. package/dist/chunks/basic-page-C0DvO_Vt.js.map +1 -0
  3. package/dist/chunks/{button-CgUS0j3D.js → button-C9VqBBIr.js} +9 -9
  4. package/dist/chunks/button-C9VqBBIr.js.map +1 -0
  5. package/dist/chunks/{chat-BXjycPi9.js → chat-B0WIgEyM.js} +2 -2
  6. package/dist/chunks/{chat-BXjycPi9.js.map → chat-B0WIgEyM.js.map} +1 -1
  7. package/dist/chunks/{code-block-BGgbp-6Q.js → code-block-BuFfh0zH.js} +2 -2
  8. package/dist/chunks/{code-block-BGgbp-6Q.js.map → code-block-BuFfh0zH.js.map} +1 -1
  9. package/dist/chunks/{command-BfCCRaoc.js → command-iYvU6Mhf.js} +2 -2
  10. package/dist/chunks/{command-BfCCRaoc.js.map → command-iYvU6Mhf.js.map} +1 -1
  11. package/dist/chunks/{dialog-DeM4axJ6.js → dialog-MPvem7yV.js} +2 -2
  12. package/dist/chunks/{dialog-DeM4axJ6.js.map → dialog-MPvem7yV.js.map} +1 -1
  13. package/dist/chunks/{error-VvHnteyf.js → error-D5SzZ0ev.js} +2 -2
  14. package/dist/chunks/{error-VvHnteyf.js.map → error-D5SzZ0ev.js.map} +1 -1
  15. package/dist/chunks/{filter-bar-BcpeTKCC.js → filter-bar-B-oYYBsU.js} +3 -3
  16. package/dist/chunks/{filter-bar-BcpeTKCC.js.map → filter-bar-B-oYYBsU.js.map} +1 -1
  17. package/dist/chunks/{log-list-Didt-MV4.js → log-list-tNuCFGlP.js} +2 -2
  18. package/dist/chunks/{log-list-Didt-MV4.js.map → log-list-tNuCFGlP.js.map} +1 -1
  19. package/dist/chunks/{sidebar-BmloUwJQ.js → sidebar-BP39w1iA.js} +3 -3
  20. package/dist/chunks/sidebar-BP39w1iA.js.map +1 -0
  21. package/dist/chunks/{toast-DUvjSZF7.js → toast-BACxYsv6.js} +2 -2
  22. package/dist/chunks/{toast-DUvjSZF7.js.map → toast-BACxYsv6.js.map} +1 -1
  23. package/dist/components/button.js +1 -1
  24. package/dist/components/chat.js +1 -1
  25. package/dist/components/code-block.js +1 -1
  26. package/dist/components/command.js +1 -1
  27. package/dist/components/dialog.js +1 -1
  28. package/dist/components/error.js +1 -1
  29. package/dist/components/filter-bar.js +1 -1
  30. package/dist/components/log-list.js +1 -1
  31. package/dist/components/toast.js +1 -1
  32. package/dist/index.js +38 -38
  33. package/dist/sections/basic-page.js +1 -1
  34. package/dist/sections/sidebar.js +1 -1
  35. package/dist/src/components/button/button.d.ts +7 -7
  36. package/dist/src/sections/basic-page/basic-page.d.ts +2 -0
  37. package/dist/src/sections/basic-page/index.d.ts +1 -0
  38. package/package.json +1 -1
  39. package/dist/chunks/basic-page-dQ86NSIy.js.map +0 -1
  40. package/dist/chunks/button-CgUS0j3D.js.map +0 -1
  41. package/dist/chunks/sidebar-BmloUwJQ.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"code-block-BGgbp-6Q.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconTextWrap.mjs","../../src/components/code-block/tokenize-json.ts","../../src/components/code-block/code-block.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\": \"M4 6l16 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M4 18l5 0\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M4 12h13a3 3 0 0 1 0 6h-4l2 -2m0 4l-2 -2\", \"key\": \"svg-2\" }]];\nconst IconTextWrap = createReactComponent(\"outline\", \"text-wrap\", \"TextWrap\", __iconNode);\n\nexport { __iconNode, IconTextWrap as default };\n//# sourceMappingURL=IconTextWrap.mjs.map\n","/**\n * A tokenizer for JSON, and nothing else: keys, strings, numbers, the\n * three keywords, and punctuation. Runs one line at a time (a JSON\n * string never spans lines) so a panel can show its first N lines and\n * stop. Text that isn't JSON comes back as it is, in plain tokens.\n */\n\nexport type JsonTokenType =\n \"key\" | \"string\" | \"number\" | \"keyword\" | \"punctuation\" | \"plain\";\n\nexport interface JsonToken {\n type: JsonTokenType;\n text: string;\n}\n\n// One pass, left to right: a string (a key when a colon follows), a\n// number, a keyword, a bracket or a comma. Anything between is plain.\nconst TOKEN =\n /(\"(?:[^\"\\\\]|\\\\.)*\")(\\s*:)?|(-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)|\\b(true|false|null)\\b|([{}[\\]:,])/g;\n\nexport function tokenizeJson(line: string): JsonToken[] {\n const tokens: JsonToken[] = [];\n let last = 0;\n TOKEN.lastIndex = 0;\n for (let match = TOKEN.exec(line); match != null; match = TOKEN.exec(line)) {\n if (match.index > last) {\n tokens.push({ type: \"plain\", text: line.slice(last, match.index) });\n }\n const [, string, colon, number, keyword, punctuation] = match;\n if (string != null) {\n tokens.push({ type: colon != null ? \"key\" : \"string\", text: string });\n if (colon != null) tokens.push({ type: \"punctuation\", text: colon });\n } else if (number != null) {\n tokens.push({ type: \"number\", text: number });\n } else if (keyword != null) {\n tokens.push({ type: \"keyword\", text: keyword });\n } else if (punctuation != null) {\n tokens.push({ type: \"punctuation\", text: punctuation });\n }\n last = match.index + match[0].length;\n }\n if (last < line.length) {\n tokens.push({ type: \"plain\", text: line.slice(last) });\n }\n return tokens;\n}\n","import {\n useMemo,\n useState,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport {\n IconArrowsMaximize,\n IconArrowsMinimize,\n IconChevronDown,\n IconChevronUp,\n IconTextWrap,\n} from \"@tabler/icons-react\";\nimport { Button } from \"../button\";\nimport { CopyButton } from \"../copy-button\";\nimport { ScrollArea } from \"../scroll-area\";\nimport { Toggle } from \"../toggle\";\nimport { Tooltip } from \"../tooltip\";\nimport { cn } from \"../../utils/cn\";\nimport { tokenizeJson, type JsonTokenType } from \"./tokenize-json\";\n\n/**\n * Code Block — a read-only panel for a request body, a response, an\n * event's JSON. Mono text on the code surface, a title row with expand,\n * wrap, and copy controls. Past `maxLines` the body either scrolls\n * inside that height (`overflow=\"scroll\"`, the default) or folds with a\n * footer button (`overflow=\"expand\"`).\n *\n * Design notes:\n * - Wide lines scroll sideways inside the panel; the page never does.\n * Wrapping is a toggle (`wrap` / `defaultWrap`), off by default so a\n * body reads the way it was sent.\n * - `language=\"json\"` colors keys, strings, numbers, and keywords with a\n * built-in tokenizer — no highlighter library at runtime — on the\n * `--color-pho-code-*` tokens, which carry light and dark.\n * - A body that isn't a string (an object) is pretty-printed as JSON.\n */\n\nexport type CodeBlockLanguage = \"json\" | \"text\";\n\nexport type CodeBlockOverflow = \"scroll\" | \"expand\";\n\nconst TOKEN_CLASS: Record<JsonTokenType, string | undefined> = {\n key: \"text-pho-code-key\",\n string: \"text-pho-code-string\",\n number: \"text-pho-code-number\",\n keyword: \"text-pho-code-keyword\",\n punctuation: \"text-pho-code-punctuation\",\n plain: undefined,\n};\n\n/** The panel's chrome — the card hairline around the code surface. */\nconst CODE_BLOCK_SURFACE =\n \"rounded-base border border-pho-secondary bg-pho-code-bg text-pho-code-fg\";\n\n/** One code line is `leading-5` / `min-h-5`; the pre pads `py-3`. */\nconst LINE_H = \"1.25rem\";\nconst PAD_Y = \"0.75rem\";\n\nexport interface CodeBlockProps extends Omit<\n ComponentProps<\"div\">,\n \"title\" | \"children\"\n> {\n /** The text. An object is pretty-printed as JSON (two-space indent). */\n code?: string | object | null;\n /** `json` colors the text; `text` leaves it plain. @default \"text\" */\n language?: CodeBlockLanguage;\n /** The title row's words — \"Request body\", \"Response\". */\n title?: ReactNode;\n /** Past this many lines the panel folds or clips. @default 30 */\n maxLines?: number;\n /**\n * How a long body is shown past `maxLines`. `scroll` clips to that\n * height and scrolls inside, with an expand toggle in the title row.\n * `expand` folds and shows a footer button.\n * @default \"scroll\"\n */\n overflow?: CodeBlockOverflow;\n /** Wrap long lines (controlled). */\n wrap?: boolean;\n /** Wrap long lines at first (uncontrolled). @default false */\n defaultWrap?: boolean;\n onWrapChange?: (wrap: boolean) => void;\n /** The expand toggle in the title row when `overflow` is `scroll`. @default true */\n expandToggle?: boolean;\n /** The wrap toggle in the title row. @default true */\n wrapToggle?: boolean;\n /**\n * A gutter of line numbers. Off by default; turn on for a long\n * payload (about twenty lines or more).\n * @default false\n */\n lineNumbers?: boolean;\n /** The copy control in the title row. @default true */\n copy?: boolean;\n /** What the panel says with no code. @default \"Nothing to show.\" */\n empty?: ReactNode;\n /** More controls in the title row, before the built-in ones. */\n actions?: ReactNode;\n ref?: Ref<HTMLDivElement>;\n}\n\nfunction toText(code: CodeBlockProps[\"code\"]): string {\n if (code == null) return \"\";\n if (typeof code === \"string\") return code;\n try {\n return JSON.stringify(code, null, 2) ?? \"\";\n } catch {\n return String(code);\n }\n}\n\nfunction HeaderToggle({\n label,\n pressed,\n onPressedChange,\n children,\n}: {\n label: string;\n pressed: boolean;\n onPressedChange: (next: boolean) => void;\n children: ReactNode;\n}) {\n return (\n <Tooltip.Root>\n <Tooltip.Trigger\n render={\n <Toggle\n size=\"sm\"\n pressed={pressed}\n onPressedChange={onPressedChange}\n aria-label={label}\n className=\"rounded-sm\"\n >\n {children}\n </Toggle>\n }\n />\n <Tooltip.Portal>\n <Tooltip.Positioner>\n <Tooltip.Popup>{label}</Tooltip.Popup>\n </Tooltip.Positioner>\n </Tooltip.Portal>\n </Tooltip.Root>\n );\n}\n\nfunction CodeLines({\n lines,\n language,\n lineNumbers,\n digits,\n wrap,\n}: {\n lines: string[];\n language: CodeBlockLanguage;\n lineNumbers: boolean;\n digits: number;\n wrap: boolean;\n}) {\n return (\n <code>\n {lines.map((line, index) => (\n <span\n key={index}\n data-line=\"\"\n className={cn(\n \"min-h-5\",\n lineNumbers ? \"flex items-start\" : \"block\",\n lineNumbers && !wrap && \"min-w-max\",\n )}\n >\n {lineNumbers ? (\n <span\n data-line-number=\"\"\n aria-hidden\n className=\"text-pho-placeholder bg-pho-code-bg sticky left-0 z-[1] box-content shrink-0 pr-3 pl-3 text-right font-mono text-xs leading-5 tabular-nums select-none\"\n style={{ width: `${digits}ch` }}\n >\n {index + 1}\n </span>\n ) : null}\n <span className={lineNumbers ? \"min-w-0 flex-1\" : undefined}>\n {language === \"json\"\n ? tokenizeJson(line).map((token, at) =>\n token.type === \"plain\" ? (\n token.text\n ) : (\n <span key={at} className={TOKEN_CLASS[token.type]}>\n {token.text}\n </span>\n ),\n )\n : line}\n </span>\n </span>\n ))}\n </code>\n );\n}\n\nexport function CodeBlock({\n code,\n language = \"text\",\n title,\n maxLines = 30,\n overflow = \"scroll\",\n wrap: wrapProp,\n defaultWrap = false,\n onWrapChange,\n expandToggle = true,\n wrapToggle = true,\n lineNumbers = false,\n copy = true,\n empty = \"Nothing to show.\",\n actions,\n className,\n ...props\n}: CodeBlockProps) {\n const text = useMemo(() => toText(code), [code]);\n const lines = useMemo(() => text.split(\"\\n\"), [text]);\n const [ownWrap, setOwnWrap] = useState(defaultWrap);\n const wrap = wrapProp ?? ownWrap;\n const setWrap = (next: boolean) => {\n if (wrapProp == null) setOwnWrap(next);\n onWrapChange?.(next);\n };\n const [expanded, setExpanded] = useState(false);\n const folds = lines.length > maxLines;\n const scrolling = overflow === \"scroll\" && folds && !expanded;\n const shown =\n overflow === \"expand\" && folds && !expanded\n ? lines.slice(0, maxLines)\n : lines;\n const isEmpty = text === \"\";\n const showExpandToggle =\n overflow === \"scroll\" && expandToggle && folds && !isEmpty;\n const showWrapToggle = wrapToggle && !isEmpty;\n const showCopy = copy && !isEmpty;\n const hasHeader =\n title != null ||\n actions != null ||\n showExpandToggle ||\n showWrapToggle ||\n showCopy;\n const copyLabel = typeof title === \"string\" ? title.toLowerCase() : \"code\";\n const scrollLabel = typeof title === \"string\" ? title : \"Code\";\n const expandLabel = expanded\n ? `Collapse to ${maxLines} lines`\n : `Show all ${lines.length} lines`;\n const lineNoDigits = String(Math.max(lines.length, 1)).length;\n const body = (\n <pre\n className={cn(\n \"m-0 min-w-0 py-3 font-mono text-xs leading-5\",\n lineNumbers ? \"pr-3 pl-0\" : \"px-3\",\n wrap\n ? \"[overflow-wrap:anywhere] whitespace-pre-wrap\"\n : scrolling\n ? \"w-max min-w-full whitespace-pre\"\n : \"max-w-full overflow-x-auto whitespace-pre\",\n )}\n >\n <CodeLines\n lines={shown}\n language={language}\n lineNumbers={lineNumbers}\n digits={lineNoDigits}\n wrap={wrap}\n />\n </pre>\n );\n return (\n <div\n data-code-block=\"\"\n data-language={language}\n data-overflow={overflow}\n className={cn(\n CODE_BLOCK_SURFACE,\n \"flex w-full min-w-0 flex-col overflow-hidden\",\n className,\n )}\n {...props}\n >\n {hasHeader ? (\n <div className=\"border-pho-secondary flex min-h-10 items-center gap-2 border-b py-1 pr-1.5 pl-3\">\n <div className=\"text-pho-secondary min-w-0 flex-1 truncate text-xs font-medium\">\n {title}\n </div>\n {actions}\n <Tooltip.Provider>\n {showExpandToggle ? (\n <HeaderToggle\n label={expandLabel}\n pressed={expanded}\n onPressedChange={setExpanded}\n >\n {expanded ? (\n <IconArrowsMinimize aria-hidden />\n ) : (\n <IconArrowsMaximize aria-hidden />\n )}\n </HeaderToggle>\n ) : null}\n {showWrapToggle ? (\n <HeaderToggle\n label=\"Wrap long lines\"\n pressed={wrap}\n onPressedChange={setWrap}\n >\n <IconTextWrap aria-hidden />\n </HeaderToggle>\n ) : null}\n </Tooltip.Provider>\n {showCopy ? (\n <CopyButton value={text} label={copyLabel} size=\"md\" />\n ) : null}\n </div>\n ) : null}\n {isEmpty ? (\n <p className=\"text-pho-description m-0 px-3 py-3 text-base\">{empty}</p>\n ) : scrolling ? (\n <section className=\"min-w-0\">\n <ScrollArea.Root\n fade={false}\n data-code-scroll=\"\"\n className=\"min-w-0 rounded-b-[inherit]\"\n style={{ height: `calc(${maxLines} * ${LINE_H} + ${PAD_Y} * 2)` }}\n >\n <ScrollArea.Viewport tabIndex={0} aria-label={scrollLabel}>\n <ScrollArea.Content>{body}</ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n {wrap ? null : (\n <ScrollArea.Scrollbar orientation=\"horizontal\">\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n )}\n </ScrollArea.Root>\n </section>\n ) : (\n body\n )}\n {overflow === \"expand\" && folds ? (\n <div className=\"border-pho-secondary flex items-center border-t px-1.5 py-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-expanded={expanded}\n prefix={expanded ? IconChevronUp : IconChevronDown}\n onClick={() => setExpanded((prev) => !prev)}\n >\n {expanded ? \"Show less\" : `Show all ${lines.length} lines`}\n </Button>\n </div>\n ) : null}\n </div>\n );\n}\n\nCodeBlock.displayName = \"CodeBlock\";\n"],"x_google_ignoreList":[0],"mappings":"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"}
1
+ {"version":3,"file":"code-block-BuFfh0zH.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconTextWrap.mjs","../../src/components/code-block/tokenize-json.ts","../../src/components/code-block/code-block.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\": \"M4 6l16 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M4 18l5 0\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M4 12h13a3 3 0 0 1 0 6h-4l2 -2m0 4l-2 -2\", \"key\": \"svg-2\" }]];\nconst IconTextWrap = createReactComponent(\"outline\", \"text-wrap\", \"TextWrap\", __iconNode);\n\nexport { __iconNode, IconTextWrap as default };\n//# sourceMappingURL=IconTextWrap.mjs.map\n","/**\n * A tokenizer for JSON, and nothing else: keys, strings, numbers, the\n * three keywords, and punctuation. Runs one line at a time (a JSON\n * string never spans lines) so a panel can show its first N lines and\n * stop. Text that isn't JSON comes back as it is, in plain tokens.\n */\n\nexport type JsonTokenType =\n \"key\" | \"string\" | \"number\" | \"keyword\" | \"punctuation\" | \"plain\";\n\nexport interface JsonToken {\n type: JsonTokenType;\n text: string;\n}\n\n// One pass, left to right: a string (a key when a colon follows), a\n// number, a keyword, a bracket or a comma. Anything between is plain.\nconst TOKEN =\n /(\"(?:[^\"\\\\]|\\\\.)*\")(\\s*:)?|(-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)|\\b(true|false|null)\\b|([{}[\\]:,])/g;\n\nexport function tokenizeJson(line: string): JsonToken[] {\n const tokens: JsonToken[] = [];\n let last = 0;\n TOKEN.lastIndex = 0;\n for (let match = TOKEN.exec(line); match != null; match = TOKEN.exec(line)) {\n if (match.index > last) {\n tokens.push({ type: \"plain\", text: line.slice(last, match.index) });\n }\n const [, string, colon, number, keyword, punctuation] = match;\n if (string != null) {\n tokens.push({ type: colon != null ? \"key\" : \"string\", text: string });\n if (colon != null) tokens.push({ type: \"punctuation\", text: colon });\n } else if (number != null) {\n tokens.push({ type: \"number\", text: number });\n } else if (keyword != null) {\n tokens.push({ type: \"keyword\", text: keyword });\n } else if (punctuation != null) {\n tokens.push({ type: \"punctuation\", text: punctuation });\n }\n last = match.index + match[0].length;\n }\n if (last < line.length) {\n tokens.push({ type: \"plain\", text: line.slice(last) });\n }\n return tokens;\n}\n","import {\n useMemo,\n useState,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport {\n IconArrowsMaximize,\n IconArrowsMinimize,\n IconChevronDown,\n IconChevronUp,\n IconTextWrap,\n} from \"@tabler/icons-react\";\nimport { Button } from \"../button\";\nimport { CopyButton } from \"../copy-button\";\nimport { ScrollArea } from \"../scroll-area\";\nimport { Toggle } from \"../toggle\";\nimport { Tooltip } from \"../tooltip\";\nimport { cn } from \"../../utils/cn\";\nimport { tokenizeJson, type JsonTokenType } from \"./tokenize-json\";\n\n/**\n * Code Block — a read-only panel for a request body, a response, an\n * event's JSON. Mono text on the code surface, a title row with expand,\n * wrap, and copy controls. Past `maxLines` the body either scrolls\n * inside that height (`overflow=\"scroll\"`, the default) or folds with a\n * footer button (`overflow=\"expand\"`).\n *\n * Design notes:\n * - Wide lines scroll sideways inside the panel; the page never does.\n * Wrapping is a toggle (`wrap` / `defaultWrap`), off by default so a\n * body reads the way it was sent.\n * - `language=\"json\"` colors keys, strings, numbers, and keywords with a\n * built-in tokenizer — no highlighter library at runtime — on the\n * `--color-pho-code-*` tokens, which carry light and dark.\n * - A body that isn't a string (an object) is pretty-printed as JSON.\n */\n\nexport type CodeBlockLanguage = \"json\" | \"text\";\n\nexport type CodeBlockOverflow = \"scroll\" | \"expand\";\n\nconst TOKEN_CLASS: Record<JsonTokenType, string | undefined> = {\n key: \"text-pho-code-key\",\n string: \"text-pho-code-string\",\n number: \"text-pho-code-number\",\n keyword: \"text-pho-code-keyword\",\n punctuation: \"text-pho-code-punctuation\",\n plain: undefined,\n};\n\n/** The panel's chrome — the card hairline around the code surface. */\nconst CODE_BLOCK_SURFACE =\n \"rounded-base border border-pho-secondary bg-pho-code-bg text-pho-code-fg\";\n\n/** One code line is `leading-5` / `min-h-5`; the pre pads `py-3`. */\nconst LINE_H = \"1.25rem\";\nconst PAD_Y = \"0.75rem\";\n\nexport interface CodeBlockProps extends Omit<\n ComponentProps<\"div\">,\n \"title\" | \"children\"\n> {\n /** The text. An object is pretty-printed as JSON (two-space indent). */\n code?: string | object | null;\n /** `json` colors the text; `text` leaves it plain. @default \"text\" */\n language?: CodeBlockLanguage;\n /** The title row's words — \"Request body\", \"Response\". */\n title?: ReactNode;\n /** Past this many lines the panel folds or clips. @default 30 */\n maxLines?: number;\n /**\n * How a long body is shown past `maxLines`. `scroll` clips to that\n * height and scrolls inside, with an expand toggle in the title row.\n * `expand` folds and shows a footer button.\n * @default \"scroll\"\n */\n overflow?: CodeBlockOverflow;\n /** Wrap long lines (controlled). */\n wrap?: boolean;\n /** Wrap long lines at first (uncontrolled). @default false */\n defaultWrap?: boolean;\n onWrapChange?: (wrap: boolean) => void;\n /** The expand toggle in the title row when `overflow` is `scroll`. @default true */\n expandToggle?: boolean;\n /** The wrap toggle in the title row. @default true */\n wrapToggle?: boolean;\n /**\n * A gutter of line numbers. Off by default; turn on for a long\n * payload (about twenty lines or more).\n * @default false\n */\n lineNumbers?: boolean;\n /** The copy control in the title row. @default true */\n copy?: boolean;\n /** What the panel says with no code. @default \"Nothing to show.\" */\n empty?: ReactNode;\n /** More controls in the title row, before the built-in ones. */\n actions?: ReactNode;\n ref?: Ref<HTMLDivElement>;\n}\n\nfunction toText(code: CodeBlockProps[\"code\"]): string {\n if (code == null) return \"\";\n if (typeof code === \"string\") return code;\n try {\n return JSON.stringify(code, null, 2) ?? \"\";\n } catch {\n return String(code);\n }\n}\n\nfunction HeaderToggle({\n label,\n pressed,\n onPressedChange,\n children,\n}: {\n label: string;\n pressed: boolean;\n onPressedChange: (next: boolean) => void;\n children: ReactNode;\n}) {\n return (\n <Tooltip.Root>\n <Tooltip.Trigger\n render={\n <Toggle\n size=\"sm\"\n pressed={pressed}\n onPressedChange={onPressedChange}\n aria-label={label}\n className=\"rounded-sm\"\n >\n {children}\n </Toggle>\n }\n />\n <Tooltip.Portal>\n <Tooltip.Positioner>\n <Tooltip.Popup>{label}</Tooltip.Popup>\n </Tooltip.Positioner>\n </Tooltip.Portal>\n </Tooltip.Root>\n );\n}\n\nfunction CodeLines({\n lines,\n language,\n lineNumbers,\n digits,\n wrap,\n}: {\n lines: string[];\n language: CodeBlockLanguage;\n lineNumbers: boolean;\n digits: number;\n wrap: boolean;\n}) {\n return (\n <code>\n {lines.map((line, index) => (\n <span\n key={index}\n data-line=\"\"\n className={cn(\n \"min-h-5\",\n lineNumbers ? \"flex items-start\" : \"block\",\n lineNumbers && !wrap && \"min-w-max\",\n )}\n >\n {lineNumbers ? (\n <span\n data-line-number=\"\"\n aria-hidden\n className=\"text-pho-placeholder bg-pho-code-bg sticky left-0 z-[1] box-content shrink-0 pr-3 pl-3 text-right font-mono text-xs leading-5 tabular-nums select-none\"\n style={{ width: `${digits}ch` }}\n >\n {index + 1}\n </span>\n ) : null}\n <span className={lineNumbers ? \"min-w-0 flex-1\" : undefined}>\n {language === \"json\"\n ? tokenizeJson(line).map((token, at) =>\n token.type === \"plain\" ? (\n token.text\n ) : (\n <span key={at} className={TOKEN_CLASS[token.type]}>\n {token.text}\n </span>\n ),\n )\n : line}\n </span>\n </span>\n ))}\n </code>\n );\n}\n\nexport function CodeBlock({\n code,\n language = \"text\",\n title,\n maxLines = 30,\n overflow = \"scroll\",\n wrap: wrapProp,\n defaultWrap = false,\n onWrapChange,\n expandToggle = true,\n wrapToggle = true,\n lineNumbers = false,\n copy = true,\n empty = \"Nothing to show.\",\n actions,\n className,\n ...props\n}: CodeBlockProps) {\n const text = useMemo(() => toText(code), [code]);\n const lines = useMemo(() => text.split(\"\\n\"), [text]);\n const [ownWrap, setOwnWrap] = useState(defaultWrap);\n const wrap = wrapProp ?? ownWrap;\n const setWrap = (next: boolean) => {\n if (wrapProp == null) setOwnWrap(next);\n onWrapChange?.(next);\n };\n const [expanded, setExpanded] = useState(false);\n const folds = lines.length > maxLines;\n const scrolling = overflow === \"scroll\" && folds && !expanded;\n const shown =\n overflow === \"expand\" && folds && !expanded\n ? lines.slice(0, maxLines)\n : lines;\n const isEmpty = text === \"\";\n const showExpandToggle =\n overflow === \"scroll\" && expandToggle && folds && !isEmpty;\n const showWrapToggle = wrapToggle && !isEmpty;\n const showCopy = copy && !isEmpty;\n const hasHeader =\n title != null ||\n actions != null ||\n showExpandToggle ||\n showWrapToggle ||\n showCopy;\n const copyLabel = typeof title === \"string\" ? title.toLowerCase() : \"code\";\n const scrollLabel = typeof title === \"string\" ? title : \"Code\";\n const expandLabel = expanded\n ? `Collapse to ${maxLines} lines`\n : `Show all ${lines.length} lines`;\n const lineNoDigits = String(Math.max(lines.length, 1)).length;\n const body = (\n <pre\n className={cn(\n \"m-0 min-w-0 py-3 font-mono text-xs leading-5\",\n lineNumbers ? \"pr-3 pl-0\" : \"px-3\",\n wrap\n ? \"[overflow-wrap:anywhere] whitespace-pre-wrap\"\n : scrolling\n ? \"w-max min-w-full whitespace-pre\"\n : \"max-w-full overflow-x-auto whitespace-pre\",\n )}\n >\n <CodeLines\n lines={shown}\n language={language}\n lineNumbers={lineNumbers}\n digits={lineNoDigits}\n wrap={wrap}\n />\n </pre>\n );\n return (\n <div\n data-code-block=\"\"\n data-language={language}\n data-overflow={overflow}\n className={cn(\n CODE_BLOCK_SURFACE,\n \"flex w-full min-w-0 flex-col overflow-hidden\",\n className,\n )}\n {...props}\n >\n {hasHeader ? (\n <div className=\"border-pho-secondary flex min-h-10 items-center gap-2 border-b py-1 pr-1.5 pl-3\">\n <div className=\"text-pho-secondary min-w-0 flex-1 truncate text-xs font-medium\">\n {title}\n </div>\n {actions}\n <Tooltip.Provider>\n {showExpandToggle ? (\n <HeaderToggle\n label={expandLabel}\n pressed={expanded}\n onPressedChange={setExpanded}\n >\n {expanded ? (\n <IconArrowsMinimize aria-hidden />\n ) : (\n <IconArrowsMaximize aria-hidden />\n )}\n </HeaderToggle>\n ) : null}\n {showWrapToggle ? (\n <HeaderToggle\n label=\"Wrap long lines\"\n pressed={wrap}\n onPressedChange={setWrap}\n >\n <IconTextWrap aria-hidden />\n </HeaderToggle>\n ) : null}\n </Tooltip.Provider>\n {showCopy ? (\n <CopyButton value={text} label={copyLabel} size=\"md\" />\n ) : null}\n </div>\n ) : null}\n {isEmpty ? (\n <p className=\"text-pho-description m-0 px-3 py-3 text-base\">{empty}</p>\n ) : scrolling ? (\n <section className=\"min-w-0\">\n <ScrollArea.Root\n fade={false}\n data-code-scroll=\"\"\n className=\"min-w-0 rounded-b-[inherit]\"\n style={{ height: `calc(${maxLines} * ${LINE_H} + ${PAD_Y} * 2)` }}\n >\n <ScrollArea.Viewport tabIndex={0} aria-label={scrollLabel}>\n <ScrollArea.Content>{body}</ScrollArea.Content>\n </ScrollArea.Viewport>\n <ScrollArea.Scrollbar>\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n {wrap ? null : (\n <ScrollArea.Scrollbar orientation=\"horizontal\">\n <ScrollArea.Thumb />\n </ScrollArea.Scrollbar>\n )}\n </ScrollArea.Root>\n </section>\n ) : (\n body\n )}\n {overflow === \"expand\" && folds ? (\n <div className=\"border-pho-secondary flex items-center border-t px-1.5 py-1\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-expanded={expanded}\n prefix={expanded ? IconChevronUp : IconChevronDown}\n onClick={() => setExpanded((prev) => !prev)}\n >\n {expanded ? \"Show less\" : `Show all ${lines.length} lines`}\n </Button>\n </div>\n ) : null}\n </div>\n );\n}\n\nCodeBlock.displayName = \"CodeBlock\";\n"],"x_google_ignoreList":[0],"mappings":"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"}
@@ -5,7 +5,7 @@ import { SPRING_SETTLE as P } from "../motion.js";
5
5
  import { t as j } from "./IconArrowUpRight-DGgKzQwV.js";
6
6
  import { t as V } from "./IconChevronLeft-CSWMKQ4C.js";
7
7
  import { t as Z } from "./animated-height-I44sUq0n.js";
8
- import { t as u } from "./dialog-DeM4axJ6.js";
8
+ import { t as u } from "./dialog-MPvem7yV.js";
9
9
  import { useEffect as $, useId as z, useLayoutEffect as A, useRef as F } from "react";
10
10
  import { Fragment as E, jsx as t, jsxs as d } from "react/jsx-runtime";
11
11
  import { LayoutGroup as H, motion as g, useReducedMotion as B } from "motion/react";
@@ -222,4 +222,4 @@ export {
222
222
  ye as t
223
223
  };
224
224
 
225
- //# sourceMappingURL=command-BfCCRaoc.js.map
225
+ //# sourceMappingURL=command-iYvU6Mhf.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"command-BfCCRaoc.js","names":[],"sources":["../../src/components/command/command.tsx"],"sourcesContent":["import {\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { IconArrowUpRight, IconChevronLeft } from \"@tabler/icons-react\";\nimport { SPRING_SETTLE } from \"../../motion\";\nimport { Command as CommandPrimitive, useCommandState } from \"cmdk\";\nimport { LayoutGroup, motion, useReducedMotion } from \"motion/react\";\nimport { AnimatedHeight } from \"../../utils/animated-height\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant, type VariantMap } from \"../../utils/resolve-variant\";\nimport { Dialog as PhoDialog } from \"../dialog\";\n\n/**\n * Spring for row moves (FLIP / shared-layout) — same feel as\n * `AnimatedHeight`: quick and critically damped, so rows glide to their new\n * slot without overshooting into neighbours.\n */\nconst ROW_MOVE_SPRING = SPRING_SETTLE;\n\nfunction Root({\n // Filtering is yours by default: filter in render (state above the\n // palette) so the rows' FLIP diff can glide survivors to their slots.\n // cmdk's built-in matcher reorders DOM imperatively — invisible to the\n // layout pass — so it is opt-in: pass `shouldFilter` to hand matching\n // and ranking back to cmdk at the cost of the animation.\n shouldFilter = false,\n className,\n children,\n ...props\n}: ComponentProps<typeof CommandPrimitive>) {\n // Namespace row layoutIds per palette instance — the docs page mounts the\n // inline demo and the dialog demo at once, with identical item values.\n const layoutNamespace = useId();\n return (\n <CommandPrimitive\n className={cn(\n \"bg-pho-primary text-pho-primary flex w-full flex-col overflow-hidden outline-none\",\n className,\n )}\n shouldFilter={shouldFilter}\n {...props}\n >\n <LayoutGroup id={layoutNamespace}>{children}</LayoutGroup>\n </CommandPrimitive>\n );\n}\n\n/**\n * The input row — a bottom hairline separates it from the list. Position\n * leading icons absolutely and pad the input (`pl-9`), mirroring\n * `Autocomplete.InputGroup`.\n */\nfunction InputGroup({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\n \"border-pho-secondary relative flex items-center border-b\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** SSR-safe layout effect (same pattern cmdk uses internally). */\nconst useIsomorphicLayoutEffect =\n typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\nfunction assignRef<T>(ref: Ref<T> | undefined, value: T | null) {\n if (typeof ref === \"function\") ref(value);\n else if (ref) ref.current = value;\n}\n\nfunction Input({\n className,\n value,\n ref: consumerRef,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Input>) {\n const inputRef = useRef<HTMLInputElement>(null);\n const search = useCommandState((state) => state.search);\n\n // cmdk stays uncontrolled here on purpose. Its controlled path syncs the\n // `value` prop into the search store through a passive effect — one painted\n // frame late — so on that stale frame the old row is still \"selected\" while\n // the list has already reflowed, and the selection pill visibly rides it\n // before snapping to the re-selected first row. Uncontrolled keystrokes\n // update search + first-row selection synchronously (pre-paint), killing\n // that frame in both directions (typing and clearing).\n //\n // The consumer-facing API is still controlled: external `value` changes\n // (programmatic reset, initial query) are replayed through the native input\n // path below so store, display, and selection take the same sync route.\n useIsomorphicLayoutEffect(() => {\n const input = inputRef.current;\n if (value == null || input == null || value === search) return;\n const setNativeValue = Object.getOwnPropertyDescriptor(\n HTMLInputElement.prototype,\n \"value\",\n )?.set;\n setNativeValue?.call(input, value);\n input.dispatchEvent(new Event(\"input\", { bubbles: true }));\n }, [value, search]);\n\n return (\n <CommandPrimitive.Input\n className={cn(\n // Borderless inside the palette surface — the InputGroup hairline\n // carries the edge. display-xs (18px) keeps iOS from zooming in.\n \"text-pho-primary placeholder:text-pho-placeholder text-display-xs w-full bg-transparent px-3 py-3 outline-none disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n {...props}\n ref={(node) => {\n inputRef.current = node;\n assignRef(consumerRef, node);\n }}\n />\n );\n}\n\nfunction List({\n className,\n children,\n ...props\n}: ComponentProps<typeof CommandPrimitive.List>) {\n return (\n // Same spring as the onboarding / invite Card shell — list height glides\n // when idle ↔ search (or filter) changes instead of jumping.\n <AnimatedHeight>\n {/* The scroller is a motion element with layoutScroll so the rows'\n FLIP projections account for its scroll offset — without it,\n scrolling reads as a layout change and every row glides to\n compensate. scroll-py keeps a breath above and below the row\n being scrolled into view. */}\n <motion.div\n layoutScroll\n className=\"max-h-[min(24rem,60vh)] scroll-py-1 overflow-y-auto overscroll-contain\"\n >\n <CommandPrimitive.List\n className={cn(\"relative isolate p-1\", className)}\n {...props}\n >\n {children}\n </CommandPrimitive.List>\n </motion.div>\n </AnimatedHeight>\n );\n}\n\nfunction Empty({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Empty>) {\n return (\n <CommandPrimitive.Empty\n className={cn(\n \"text-pho-description px-2.5 py-6 text-center text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Group({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Group>) {\n return (\n <CommandPrimitive.Group\n className={cn(\n // cmdk renders the `heading` prop in a [cmdk-group-heading] wrapper —\n // typography mirrors `Autocomplete.GroupLabel`.\n \"[&_[cmdk-group-heading]]:text-pho-secondary [&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Row layout mode:\n * - `item` / `subitem` / `subsubitem` — idle hierarchy (icon column + indent)\n * - `result` — flat search hit (breadcrumb + trailing scope)\n */\nexport type CommandItemLevel = \"item\" | \"subitem\" | \"subsubitem\" | \"result\";\nexport type CommandItemSize = \"sm\" | \"md\";\n\nconst ITEM_SIZES = {\n sm: {\n classes: \"gap-1.5 py-1 pr-2 text-sm\",\n description: \"Compact rows for filter lists and dense pickers\",\n },\n md: {\n classes: \"gap-2 py-2 pr-2.5 text-base\",\n description: \"Default palette row\",\n },\n} as const satisfies VariantMap;\n\nconst ITEM_TITLE_SIZES = {\n sm: { classes: \"text-sm\", description: \"Compact row title\" },\n md: { classes: \"text-md\", description: \"Default row title\" },\n} as const satisfies VariantMap;\n\nconst ITEM_ICON_SIZES = {\n sm: {\n classes: \"size-3.5 [&>svg]:size-3.5\",\n description: \"Compact leading glyph\",\n },\n md: {\n classes: \"size-4 [&>svg]:size-4\",\n description: \"Default leading glyph\",\n },\n} as const satisfies VariantMap;\n\ntype ItemPrimitiveProps = ComponentProps<typeof CommandPrimitive.Item>;\n\nexport interface CommandItemProps extends Omit<\n ItemPrimitiveProps,\n \"children\" | \"title\"\n> {\n /**\n * Row depth / mode in the palette:\n * - `item` — page / top destination (icon + title)\n * - `subitem` — section under an item (label aligns with the item title)\n * - `subsubitem` — row under a section (one step deeper)\n * - `result` — flat search hit (`title` + `path` crumbs + `scope`)\n */\n level?: CommandItemLevel;\n /**\n * Leading glyph. On idle `item` rows (and reserved for sub-levels). On\n * `result` rows, pass the resolved icon (self → parent → grandparent).\n */\n icon?: ReactNode;\n /**\n * When `level=\"result\"`, force the icon column so labels align across the\n * list even if this row's `icon` is empty. Set true when any sibling result\n * has an icon; omit when the whole result set is icon-less.\n */\n iconSlot?: boolean;\n /**\n * Row density. `sm` tightens padding and type for chip popovers\n * (Filter Bar options). Palette destinations stay `md`.\n * @default \"md\"\n */\n size?: CommandItemSize;\n /** Primary label. Prefer this over free-form children for the shared layout. */\n title?: ReactNode;\n /**\n * Ancestors after `title` for `level=\"result\"` — parent → page\n * (e.g. `[\"Agent profile\", \"Settings\"]` → `Name < Agent profile < Settings`).\n */\n path?: ReactNode[];\n /**\n * Trailing scope for `level=\"result\"` — `Project` vs `Personal`, not a nav group.\n */\n scope?: ReactNode;\n /** Shows a trailing external-link glyph (opens outside the app). */\n external?: boolean;\n /**\n * Free-form content. When `title` is set, rendered after the label stack.\n * When `title` is omitted, becomes the row body (legacy / simple items).\n */\n children?: ReactNode;\n}\n\n/** Leading icon column — `size-4` at `md`, tighter at `sm`. */\nfunction ItemIcon({\n className,\n size = \"md\",\n ...props\n}: ComponentProps<\"span\"> & { size?: CommandItemSize }) {\n return (\n <span\n className={cn(\n \"text-pho-secondary flex shrink-0 items-center justify-center\",\n resolveVariant(ITEM_ICON_SIZES, size),\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Primary label — medium + primary ink on `item` rows. */\nfunction ItemTitle({\n className,\n level = \"item\",\n size = \"md\",\n ...props\n}: ComponentProps<\"span\"> & {\n level?: CommandItemLevel;\n size?: CommandItemSize;\n}) {\n return (\n <span\n className={cn(\n \"block truncate\",\n resolveVariant(ITEM_TITLE_SIZES, size),\n level === \"item\" && \"text-pho-primary\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * One selectable row. Idle palettes use `level` + `icon` / `title`\n * (item → subitem → subsubitem). Searching uses `level=\"result\"` with `path`\n * crumbs and a trailing `scope` (Project / Personal). No description line —\n * match via `keywords` / aliases instead.\n */\nfunction ExternalGlyph() {\n return (\n <IconArrowUpRight\n aria-hidden\n className=\"text-pho-description size-4 shrink-0\"\n />\n );\n}\n\nfunction Item({\n className,\n level = \"item\",\n size = \"md\",\n icon,\n iconSlot,\n title,\n path,\n scope,\n external,\n children,\n value,\n ...props\n}: CommandItemProps) {\n const reduceMotion = useReducedMotion();\n // cmdk registers `value.trim()` and exposes the selected one as\n // `state.value` — mirrors cmdk's own `data-selected` computation.\n const trimmedValue = typeof value === \"string\" ? value.trim() : \"\";\n const selectedValue = useCommandState((state) => state.value);\n const isSelected = trimmedValue !== \"\" && selectedValue === trimmedValue;\n const structured = title != null;\n const isResult = level === \"result\";\n // Reserve the icon column when the row has an icon, or when the list asks\n // for alignment (`iconSlot`) even if this row's glyph is empty.\n const showResultIcon = isResult && (icon != null || iconSlot);\n\n const row = (\n <CommandPrimitive.Item\n data-level={level}\n data-size={size}\n value={value}\n className={cn(\n \"text-pho-secondary flex cursor-pointer items-center rounded-[calc(var(--radius-base)-4px)] outline-none select-none\",\n resolveVariant(ITEM_SIZES, size),\n // subsubitem steps in; item/subitem share the base gutter.\n level === \"subsubitem\" ? \"pl-6\" : \"pl-2\",\n // Secondary at rest; selection lifts to primary ink (Menu idiom).\n // The wash lands with it instantly — stepping through rows is a\n // snap, not a flight.\n \"data-[selected=true]:text-pho-primary data-[selected=true]:bg-pho-ghost-hover\",\n \"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n className,\n )}\n {...props}\n >\n {structured && isResult ? (\n <>\n {showResultIcon ? (\n <ItemIcon size={size} aria-hidden={icon == null ? true : undefined}>\n {icon ?? null}\n </ItemIcon>\n ) : null}\n {/* Same title size as idle ItemTitle so row height matches. */}\n <span\n className={cn(\n \"flex min-w-0 flex-1 items-center gap-1 overflow-hidden\",\n resolveVariant(ITEM_TITLE_SIZES, size),\n )}\n >\n <span className=\"text-pho-primary truncate\">{title}</span>\n {(path ?? []).map((segment, index) => (\n <span\n key={index}\n className=\"text-pho-description flex shrink-0 items-center gap-0.5\"\n >\n <IconChevronLeft aria-hidden className=\"size-4 shrink-0\" />\n {segment}\n </span>\n ))}\n </span>\n {scope != null && scope !== \"\" ? (\n <span className=\"text-pho-description shrink-0 text-xs\">\n {scope}\n </span>\n ) : null}\n {external ? <ExternalGlyph /> : null}\n {children}\n </>\n ) : structured ? (\n <>\n {/* Icon column always reserved so subitem labels share the item title edge. */}\n <ItemIcon size={size} aria-hidden={icon == null ? true : undefined}>\n {icon ?? null}\n </ItemIcon>\n <span className=\"min-w-0 flex-1\">\n <ItemTitle level={level} size={size}>\n {title}\n </ItemTitle>\n </span>\n {external ? <ExternalGlyph /> : null}\n {children}\n </>\n ) : (\n children\n )}\n </CommandPrimitive.Item>\n );\n\n if (reduceMotion) return row;\n\n return (\n // FLIP wrapper: rows that stay mounted glide when neighbours enter or\n // leave, and a row remounting elsewhere with the same `value` (idle group\n // ↔ flat search result) inherits the old bounds via its layoutId and\n // slides to the new slot — the iOS list-diff feel. Rows without a match\n // simply appear / disappear so the whole list never swarms.\n //\n // The selected row is the exception: it skips the travel and appears at\n // its final slot immediately, so the selection wash is never sitting on\n // empty space waiting for its row to fly in.\n <motion.div\n layout=\"position\"\n layoutId={typeof value === \"string\" ? value : undefined}\n initial={false}\n transition={isSelected ? { duration: 0 } : ROW_MOVE_SPRING}\n >\n {row}\n </motion.div>\n );\n}\n\nfunction Separator({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Separator>) {\n return (\n <CommandPrimitive.Separator\n className={cn(\n \"-mx-1 my-1 h-px bg-[var(--border-color-pho-secondary)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Loading({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Loading>) {\n return (\n <CommandPrimitive.Loading\n className={cn(\"text-pho-description px-2.5 py-1.5 text-base\", className)}\n {...props}\n />\n );\n}\n\ntype DialogRootProps = ComponentProps<typeof PhoDialog.Root>;\n\ninterface CommandDialogProps extends ComponentProps<typeof CommandPrimitive> {\n /** Controlled dialog state — pass straight through to `Dialog.Root`. */\n open?: DialogRootProps[\"open\"];\n onOpenChange?: DialogRootProps[\"onOpenChange\"];\n /** Accessible name for the palette (dialog and command menu). */\n label?: string;\n /** Extra classes for the dialog panel (not the command root). */\n className?: string;\n}\n\n/**\n * A command palette in a modal — Pho's `Dialog` overlay (Base UI) around a\n * `Command.Root`, raised above center. We deliberately skip cmdk's own\n * `Command.Dialog` (Radix) so overlays stay on one primitive stack.\n *\n * List height springs via `AnimatedHeight` (same feel as the Card shell on\n * onboarding / invite) — the input row stays put while results resize.\n */\nfunction Dialog({\n open,\n onOpenChange,\n label,\n className,\n children,\n ...props\n}: CommandDialogProps) {\n return (\n <PhoDialog.Root open={open} onOpenChange={onOpenChange}>\n <PhoDialog.Portal>\n <PhoDialog.Backdrop />\n <PhoDialog.Popup\n aria-label={label}\n // Palette sits above center so the list grows downward from a\n // stable top edge instead of jumping around it.\n className={cn(\n \"top-[max(4rem,18vh)] max-w-xl translate-y-0 overflow-hidden p-0\",\n className,\n )}\n >\n {/* The popup is position: fixed; layout animations inside a fixed\n element need a layoutRoot to project against, or their\n measurements drift with the page scroll. */}\n <motion.div layoutRoot>\n <Root label={label} {...props}>\n {children}\n </Root>\n </motion.div>\n </PhoDialog.Popup>\n </PhoDialog.Portal>\n </PhoDialog.Root>\n );\n}\n\n/**\n * Command menu built on `cmdk` — a filterable list of actions driven from a\n * single input, keyboard-first. Compose inline (`Command.Root`) or as a\n * ⌘K-style modal palette (`Command.Dialog`, which owns the overlay).\n * Filtering is yours by default — filter in render so the rows' diff can\n * glide; pass `shouldFilter` to hand matching and ranking to cmdk (its\n * imperative reorder skips the animation).\n *\n * Rows share one layout via `Command.Item` `level` — idle\n * `item` → `subitem` → `subsubitem`, or flat `result` while searching.\n */\nexport const Command = {\n Root,\n InputGroup,\n Input,\n List,\n Empty,\n Group,\n Item,\n ItemIcon,\n ItemTitle,\n Separator,\n Loading,\n Dialog,\n};\n\n/** Re-export of cmdk's state selector hook (search, value, filtered counts). */\nexport { useCommandState };\n"],"mappings":"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"}
1
+ {"version":3,"file":"command-iYvU6Mhf.js","names":[],"sources":["../../src/components/command/command.tsx"],"sourcesContent":["import {\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { IconArrowUpRight, IconChevronLeft } from \"@tabler/icons-react\";\nimport { SPRING_SETTLE } from \"../../motion\";\nimport { Command as CommandPrimitive, useCommandState } from \"cmdk\";\nimport { LayoutGroup, motion, useReducedMotion } from \"motion/react\";\nimport { AnimatedHeight } from \"../../utils/animated-height\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant, type VariantMap } from \"../../utils/resolve-variant\";\nimport { Dialog as PhoDialog } from \"../dialog\";\n\n/**\n * Spring for row moves (FLIP / shared-layout) — same feel as\n * `AnimatedHeight`: quick and critically damped, so rows glide to their new\n * slot without overshooting into neighbours.\n */\nconst ROW_MOVE_SPRING = SPRING_SETTLE;\n\nfunction Root({\n // Filtering is yours by default: filter in render (state above the\n // palette) so the rows' FLIP diff can glide survivors to their slots.\n // cmdk's built-in matcher reorders DOM imperatively — invisible to the\n // layout pass — so it is opt-in: pass `shouldFilter` to hand matching\n // and ranking back to cmdk at the cost of the animation.\n shouldFilter = false,\n className,\n children,\n ...props\n}: ComponentProps<typeof CommandPrimitive>) {\n // Namespace row layoutIds per palette instance — the docs page mounts the\n // inline demo and the dialog demo at once, with identical item values.\n const layoutNamespace = useId();\n return (\n <CommandPrimitive\n className={cn(\n \"bg-pho-primary text-pho-primary flex w-full flex-col overflow-hidden outline-none\",\n className,\n )}\n shouldFilter={shouldFilter}\n {...props}\n >\n <LayoutGroup id={layoutNamespace}>{children}</LayoutGroup>\n </CommandPrimitive>\n );\n}\n\n/**\n * The input row — a bottom hairline separates it from the list. Position\n * leading icons absolutely and pad the input (`pl-9`), mirroring\n * `Autocomplete.InputGroup`.\n */\nfunction InputGroup({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\n \"border-pho-secondary relative flex items-center border-b\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** SSR-safe layout effect (same pattern cmdk uses internally). */\nconst useIsomorphicLayoutEffect =\n typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\nfunction assignRef<T>(ref: Ref<T> | undefined, value: T | null) {\n if (typeof ref === \"function\") ref(value);\n else if (ref) ref.current = value;\n}\n\nfunction Input({\n className,\n value,\n ref: consumerRef,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Input>) {\n const inputRef = useRef<HTMLInputElement>(null);\n const search = useCommandState((state) => state.search);\n\n // cmdk stays uncontrolled here on purpose. Its controlled path syncs the\n // `value` prop into the search store through a passive effect — one painted\n // frame late — so on that stale frame the old row is still \"selected\" while\n // the list has already reflowed, and the selection pill visibly rides it\n // before snapping to the re-selected first row. Uncontrolled keystrokes\n // update search + first-row selection synchronously (pre-paint), killing\n // that frame in both directions (typing and clearing).\n //\n // The consumer-facing API is still controlled: external `value` changes\n // (programmatic reset, initial query) are replayed through the native input\n // path below so store, display, and selection take the same sync route.\n useIsomorphicLayoutEffect(() => {\n const input = inputRef.current;\n if (value == null || input == null || value === search) return;\n const setNativeValue = Object.getOwnPropertyDescriptor(\n HTMLInputElement.prototype,\n \"value\",\n )?.set;\n setNativeValue?.call(input, value);\n input.dispatchEvent(new Event(\"input\", { bubbles: true }));\n }, [value, search]);\n\n return (\n <CommandPrimitive.Input\n className={cn(\n // Borderless inside the palette surface — the InputGroup hairline\n // carries the edge. display-xs (18px) keeps iOS from zooming in.\n \"text-pho-primary placeholder:text-pho-placeholder text-display-xs w-full bg-transparent px-3 py-3 outline-none disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n {...props}\n ref={(node) => {\n inputRef.current = node;\n assignRef(consumerRef, node);\n }}\n />\n );\n}\n\nfunction List({\n className,\n children,\n ...props\n}: ComponentProps<typeof CommandPrimitive.List>) {\n return (\n // Same spring as the onboarding / invite Card shell — list height glides\n // when idle ↔ search (or filter) changes instead of jumping.\n <AnimatedHeight>\n {/* The scroller is a motion element with layoutScroll so the rows'\n FLIP projections account for its scroll offset — without it,\n scrolling reads as a layout change and every row glides to\n compensate. scroll-py keeps a breath above and below the row\n being scrolled into view. */}\n <motion.div\n layoutScroll\n className=\"max-h-[min(24rem,60vh)] scroll-py-1 overflow-y-auto overscroll-contain\"\n >\n <CommandPrimitive.List\n className={cn(\"relative isolate p-1\", className)}\n {...props}\n >\n {children}\n </CommandPrimitive.List>\n </motion.div>\n </AnimatedHeight>\n );\n}\n\nfunction Empty({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Empty>) {\n return (\n <CommandPrimitive.Empty\n className={cn(\n \"text-pho-description px-2.5 py-6 text-center text-base\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Group({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Group>) {\n return (\n <CommandPrimitive.Group\n className={cn(\n // cmdk renders the `heading` prop in a [cmdk-group-heading] wrapper —\n // typography mirrors `Autocomplete.GroupLabel`.\n \"[&_[cmdk-group-heading]]:text-pho-secondary [&_[cmdk-group-heading]]:px-2.5 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Row layout mode:\n * - `item` / `subitem` / `subsubitem` — idle hierarchy (icon column + indent)\n * - `result` — flat search hit (breadcrumb + trailing scope)\n */\nexport type CommandItemLevel = \"item\" | \"subitem\" | \"subsubitem\" | \"result\";\nexport type CommandItemSize = \"sm\" | \"md\";\n\nconst ITEM_SIZES = {\n sm: {\n classes: \"gap-1.5 py-1 pr-2 text-sm\",\n description: \"Compact rows for filter lists and dense pickers\",\n },\n md: {\n classes: \"gap-2 py-2 pr-2.5 text-base\",\n description: \"Default palette row\",\n },\n} as const satisfies VariantMap;\n\nconst ITEM_TITLE_SIZES = {\n sm: { classes: \"text-sm\", description: \"Compact row title\" },\n md: { classes: \"text-md\", description: \"Default row title\" },\n} as const satisfies VariantMap;\n\nconst ITEM_ICON_SIZES = {\n sm: {\n classes: \"size-3.5 [&>svg]:size-3.5\",\n description: \"Compact leading glyph\",\n },\n md: {\n classes: \"size-4 [&>svg]:size-4\",\n description: \"Default leading glyph\",\n },\n} as const satisfies VariantMap;\n\ntype ItemPrimitiveProps = ComponentProps<typeof CommandPrimitive.Item>;\n\nexport interface CommandItemProps extends Omit<\n ItemPrimitiveProps,\n \"children\" | \"title\"\n> {\n /**\n * Row depth / mode in the palette:\n * - `item` — page / top destination (icon + title)\n * - `subitem` — section under an item (label aligns with the item title)\n * - `subsubitem` — row under a section (one step deeper)\n * - `result` — flat search hit (`title` + `path` crumbs + `scope`)\n */\n level?: CommandItemLevel;\n /**\n * Leading glyph. On idle `item` rows (and reserved for sub-levels). On\n * `result` rows, pass the resolved icon (self → parent → grandparent).\n */\n icon?: ReactNode;\n /**\n * When `level=\"result\"`, force the icon column so labels align across the\n * list even if this row's `icon` is empty. Set true when any sibling result\n * has an icon; omit when the whole result set is icon-less.\n */\n iconSlot?: boolean;\n /**\n * Row density. `sm` tightens padding and type for chip popovers\n * (Filter Bar options). Palette destinations stay `md`.\n * @default \"md\"\n */\n size?: CommandItemSize;\n /** Primary label. Prefer this over free-form children for the shared layout. */\n title?: ReactNode;\n /**\n * Ancestors after `title` for `level=\"result\"` — parent → page\n * (e.g. `[\"Agent profile\", \"Settings\"]` → `Name < Agent profile < Settings`).\n */\n path?: ReactNode[];\n /**\n * Trailing scope for `level=\"result\"` — `Project` vs `Personal`, not a nav group.\n */\n scope?: ReactNode;\n /** Shows a trailing external-link glyph (opens outside the app). */\n external?: boolean;\n /**\n * Free-form content. When `title` is set, rendered after the label stack.\n * When `title` is omitted, becomes the row body (legacy / simple items).\n */\n children?: ReactNode;\n}\n\n/** Leading icon column — `size-4` at `md`, tighter at `sm`. */\nfunction ItemIcon({\n className,\n size = \"md\",\n ...props\n}: ComponentProps<\"span\"> & { size?: CommandItemSize }) {\n return (\n <span\n className={cn(\n \"text-pho-secondary flex shrink-0 items-center justify-center\",\n resolveVariant(ITEM_ICON_SIZES, size),\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Primary label — medium + primary ink on `item` rows. */\nfunction ItemTitle({\n className,\n level = \"item\",\n size = \"md\",\n ...props\n}: ComponentProps<\"span\"> & {\n level?: CommandItemLevel;\n size?: CommandItemSize;\n}) {\n return (\n <span\n className={cn(\n \"block truncate\",\n resolveVariant(ITEM_TITLE_SIZES, size),\n level === \"item\" && \"text-pho-primary\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * One selectable row. Idle palettes use `level` + `icon` / `title`\n * (item → subitem → subsubitem). Searching uses `level=\"result\"` with `path`\n * crumbs and a trailing `scope` (Project / Personal). No description line —\n * match via `keywords` / aliases instead.\n */\nfunction ExternalGlyph() {\n return (\n <IconArrowUpRight\n aria-hidden\n className=\"text-pho-description size-4 shrink-0\"\n />\n );\n}\n\nfunction Item({\n className,\n level = \"item\",\n size = \"md\",\n icon,\n iconSlot,\n title,\n path,\n scope,\n external,\n children,\n value,\n ...props\n}: CommandItemProps) {\n const reduceMotion = useReducedMotion();\n // cmdk registers `value.trim()` and exposes the selected one as\n // `state.value` — mirrors cmdk's own `data-selected` computation.\n const trimmedValue = typeof value === \"string\" ? value.trim() : \"\";\n const selectedValue = useCommandState((state) => state.value);\n const isSelected = trimmedValue !== \"\" && selectedValue === trimmedValue;\n const structured = title != null;\n const isResult = level === \"result\";\n // Reserve the icon column when the row has an icon, or when the list asks\n // for alignment (`iconSlot`) even if this row's glyph is empty.\n const showResultIcon = isResult && (icon != null || iconSlot);\n\n const row = (\n <CommandPrimitive.Item\n data-level={level}\n data-size={size}\n value={value}\n className={cn(\n \"text-pho-secondary flex cursor-pointer items-center rounded-[calc(var(--radius-base)-4px)] outline-none select-none\",\n resolveVariant(ITEM_SIZES, size),\n // subsubitem steps in; item/subitem share the base gutter.\n level === \"subsubitem\" ? \"pl-6\" : \"pl-2\",\n // Secondary at rest; selection lifts to primary ink (Menu idiom).\n // The wash lands with it instantly — stepping through rows is a\n // snap, not a flight.\n \"data-[selected=true]:text-pho-primary data-[selected=true]:bg-pho-ghost-hover\",\n \"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n className,\n )}\n {...props}\n >\n {structured && isResult ? (\n <>\n {showResultIcon ? (\n <ItemIcon size={size} aria-hidden={icon == null ? true : undefined}>\n {icon ?? null}\n </ItemIcon>\n ) : null}\n {/* Same title size as idle ItemTitle so row height matches. */}\n <span\n className={cn(\n \"flex min-w-0 flex-1 items-center gap-1 overflow-hidden\",\n resolveVariant(ITEM_TITLE_SIZES, size),\n )}\n >\n <span className=\"text-pho-primary truncate\">{title}</span>\n {(path ?? []).map((segment, index) => (\n <span\n key={index}\n className=\"text-pho-description flex shrink-0 items-center gap-0.5\"\n >\n <IconChevronLeft aria-hidden className=\"size-4 shrink-0\" />\n {segment}\n </span>\n ))}\n </span>\n {scope != null && scope !== \"\" ? (\n <span className=\"text-pho-description shrink-0 text-xs\">\n {scope}\n </span>\n ) : null}\n {external ? <ExternalGlyph /> : null}\n {children}\n </>\n ) : structured ? (\n <>\n {/* Icon column always reserved so subitem labels share the item title edge. */}\n <ItemIcon size={size} aria-hidden={icon == null ? true : undefined}>\n {icon ?? null}\n </ItemIcon>\n <span className=\"min-w-0 flex-1\">\n <ItemTitle level={level} size={size}>\n {title}\n </ItemTitle>\n </span>\n {external ? <ExternalGlyph /> : null}\n {children}\n </>\n ) : (\n children\n )}\n </CommandPrimitive.Item>\n );\n\n if (reduceMotion) return row;\n\n return (\n // FLIP wrapper: rows that stay mounted glide when neighbours enter or\n // leave, and a row remounting elsewhere with the same `value` (idle group\n // ↔ flat search result) inherits the old bounds via its layoutId and\n // slides to the new slot — the iOS list-diff feel. Rows without a match\n // simply appear / disappear so the whole list never swarms.\n //\n // The selected row is the exception: it skips the travel and appears at\n // its final slot immediately, so the selection wash is never sitting on\n // empty space waiting for its row to fly in.\n <motion.div\n layout=\"position\"\n layoutId={typeof value === \"string\" ? value : undefined}\n initial={false}\n transition={isSelected ? { duration: 0 } : ROW_MOVE_SPRING}\n >\n {row}\n </motion.div>\n );\n}\n\nfunction Separator({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Separator>) {\n return (\n <CommandPrimitive.Separator\n className={cn(\n \"-mx-1 my-1 h-px bg-[var(--border-color-pho-secondary)]\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Loading({\n className,\n ...props\n}: ComponentProps<typeof CommandPrimitive.Loading>) {\n return (\n <CommandPrimitive.Loading\n className={cn(\"text-pho-description px-2.5 py-1.5 text-base\", className)}\n {...props}\n />\n );\n}\n\ntype DialogRootProps = ComponentProps<typeof PhoDialog.Root>;\n\ninterface CommandDialogProps extends ComponentProps<typeof CommandPrimitive> {\n /** Controlled dialog state — pass straight through to `Dialog.Root`. */\n open?: DialogRootProps[\"open\"];\n onOpenChange?: DialogRootProps[\"onOpenChange\"];\n /** Accessible name for the palette (dialog and command menu). */\n label?: string;\n /** Extra classes for the dialog panel (not the command root). */\n className?: string;\n}\n\n/**\n * A command palette in a modal — Pho's `Dialog` overlay (Base UI) around a\n * `Command.Root`, raised above center. We deliberately skip cmdk's own\n * `Command.Dialog` (Radix) so overlays stay on one primitive stack.\n *\n * List height springs via `AnimatedHeight` (same feel as the Card shell on\n * onboarding / invite) — the input row stays put while results resize.\n */\nfunction Dialog({\n open,\n onOpenChange,\n label,\n className,\n children,\n ...props\n}: CommandDialogProps) {\n return (\n <PhoDialog.Root open={open} onOpenChange={onOpenChange}>\n <PhoDialog.Portal>\n <PhoDialog.Backdrop />\n <PhoDialog.Popup\n aria-label={label}\n // Palette sits above center so the list grows downward from a\n // stable top edge instead of jumping around it.\n className={cn(\n \"top-[max(4rem,18vh)] max-w-xl translate-y-0 overflow-hidden p-0\",\n className,\n )}\n >\n {/* The popup is position: fixed; layout animations inside a fixed\n element need a layoutRoot to project against, or their\n measurements drift with the page scroll. */}\n <motion.div layoutRoot>\n <Root label={label} {...props}>\n {children}\n </Root>\n </motion.div>\n </PhoDialog.Popup>\n </PhoDialog.Portal>\n </PhoDialog.Root>\n );\n}\n\n/**\n * Command menu built on `cmdk` — a filterable list of actions driven from a\n * single input, keyboard-first. Compose inline (`Command.Root`) or as a\n * ⌘K-style modal palette (`Command.Dialog`, which owns the overlay).\n * Filtering is yours by default — filter in render so the rows' diff can\n * glide; pass `shouldFilter` to hand matching and ranking to cmdk (its\n * imperative reorder skips the animation).\n *\n * Rows share one layout via `Command.Item` `level` — idle\n * `item` → `subitem` → `subsubitem`, or flat `result` while searching.\n */\nexport const Command = {\n Root,\n InputGroup,\n Input,\n List,\n Empty,\n Group,\n Item,\n ItemIcon,\n ItemTitle,\n Separator,\n Loading,\n Dialog,\n};\n\n/** Re-export of cmdk's state selector hook (search, value, filtered counts). */\nexport { useCommandState };\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { t as m } from "./cn-ChIgwEl3.js";
3
- import { a as E } from "./button-CgUS0j3D.js";
3
+ import { a as E } from "./button-C9VqBBIr.js";
4
4
  import { t as P } from "./close-button-GvqWbLl0.js";
5
5
  import { t as I } from "./animated-height-I44sUq0n.js";
6
6
  import { t as p } from "./scroll-area-DSwD9th7.js";
@@ -255,4 +255,4 @@ export {
255
255
  re as t
256
256
  };
257
257
 
258
- //# sourceMappingURL=dialog-DeM4axJ6.js.map
258
+ //# sourceMappingURL=dialog-MPvem7yV.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dialog-DeM4axJ6.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
+ {"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,6 +1,6 @@
1
1
  "use client";
2
2
  import { t as h } from "./cn-ChIgwEl3.js";
3
- import { a as x, o as R } from "./button-CgUS0j3D.js";
3
+ import { a as x, o as R } from "./button-C9VqBBIr.js";
4
4
  import { t as C } from "./createReactComponent-BqCmnqfX.js";
5
5
  import { t as S } from "./IconInfoCircle-L0zfhg7R.js";
6
6
  import { t as g } from "./IconAlertCircleFilled-VxKU8TYK.js";
@@ -249,4 +249,4 @@ export {
249
249
  M as t
250
250
  };
251
251
 
252
- //# sourceMappingURL=error-VvHnteyf.js.map
252
+ //# sourceMappingURL=error-D5SzZ0ev.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-VvHnteyf.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconAlertTriangle.mjs","../../src/components/error/problem.ts","../../src/components/error/error.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 9v4\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M12 16h.01\", \"key\": \"svg-2\" }]];\nconst IconAlertTriangle = createReactComponent(\"outline\", \"alert-triangle\", \"AlertTriangle\", __iconNode);\n\nexport { __iconNode, IconAlertTriangle as default };\n//# sourceMappingURL=IconAlertTriangle.mjs.map\n","/**\n * Client-side mirror of the `@photon-hq/error` response contract — the\n * RFC 9457 Problem Details body every Photon service returns for 4xx / 5xx.\n * Machine logic branches on `code`; `title` / `detail` / `remediation` are\n * the human-readable copy, already reviewed server-side and safe to render.\n *\n * Fetch layers may also hand us a thin status-only shape when the response\n * was not ok but the body was not a contract problem — `title` + `status`\n * still count so the UI can disclose the HTTP code we already know.\n */\n\nexport interface ProblemRemediation {\n /** What the user can do about it — a full sentence. */\n action?: string;\n /** Docs URL explaining the problem. */\n documentation?: string;\n}\n\nexport interface Problem {\n /** Stable machine-readable key (`RATE_LIMITED`) — the field to branch on. */\n code?: string;\n /** Human summary of the problem type (\"Too Many Requests\"). */\n title: string;\n /** HTTP status (4xx / 5xx). */\n status: number;\n /** Problem type URI (`urn:photon:problem:*` or an https URL). */\n type?: string;\n /** Occurrence-specific human sentence. */\n detail?: string;\n /** Correlation id for support (`X-Request-ID`). */\n requestId?: string;\n remediation?: ProblemRemediation;\n /** RFC 9457 extensions (`issues`, `actualVersion`, …). */\n [extension: string]: unknown;\n}\n\n/** Structural check: `title` + a 4xx/5xx status. `code` is optional. */\nexport function isProblem(value: unknown): value is Problem {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v.title === \"string\" &&\n typeof v.status === \"number\" &&\n Number.isInteger(v.status) &&\n v.status >= 400 &&\n v.status <= 599 &&\n (v.code === undefined || typeof v.code === \"string\")\n );\n}\n\n/**\n * Find the problem a caught value carries — the value itself, one typed onto\n * an error as a `problem` field (dashboard's `ApiError` shape), or one\n * wrapped in an `Error` `cause` chain (how fetch layers usually rethrow a\n * parsed body). Returns `null` when there is none.\n */\nexport function parseProblem(error: unknown): Problem | null {\n let current: unknown = error;\n for (\n let depth = 0;\n depth < 8 && typeof current === \"object\" && current !== null;\n depth++\n ) {\n if (isProblem(current)) return current;\n const carried = (current as { problem?: unknown }).problem;\n if (isProblem(carried)) return carried;\n current = (current as { cause?: unknown }).cause;\n }\n return null;\n}\n\nexport interface ErrorDescription {\n /** Short name of the failure — the problem `title`, or a generic fallback. */\n title: string;\n /** Sentence(s) to show — `detail` and `remediation.action` joined. */\n description?: string;\n /** Docs URL from `remediation.documentation`. */\n documentation?: string;\n /** Correlation id for support. */\n requestId?: string;\n /** The matched problem, when the input carried one. */\n problem?: Problem;\n}\n\n/**\n * Anything that isn't a problem renders as this — raw `Error` messages are\n * not contract copy and never shown (the same fail-closed stance as the\n * server side of `@photon-hq/error`). Always a full sentence (trailing\n * period).\n */\nexport const GENERIC_ERROR_TITLE = \"Something went wrong.\";\n\n/** Standard reason phrases for statuses we commonly surface without a body. */\nconst HTTP_REASON_PHRASE: Record<number, string> = {\n 400: \"Bad Request\",\n 401: \"Unauthorized\",\n 403: \"Forbidden\",\n 404: \"Not Found\",\n 408: \"Request Timeout\",\n 409: \"Conflict\",\n 410: \"Gone\",\n 413: \"Payload Too Large\",\n 415: \"Unsupported Media Type\",\n 422: \"Unprocessable Entity\",\n 429: \"Too Many Requests\",\n 500: \"Internal Server Error\",\n 501: \"Not Implemented\",\n 502: \"Bad Gateway\",\n 503: \"Service Unavailable\",\n 504: \"Gateway Timeout\",\n};\n\n/** One-sentence explanations when the server gave a status but no problem copy. */\nconst HTTP_STATUS_EXPLANATION: Record<number, string> = {\n 400: \"The request was malformed or incomplete.\",\n 401: \"You need to sign in again.\",\n 403: \"You don't have permission to do that.\",\n 404: \"The requested resource was not found.\",\n 408: \"The request timed out before the server responded.\",\n 409: \"The request conflicts with the current state.\",\n 410: \"That resource is no longer available.\",\n 413: \"The request was too large for the server to accept.\",\n 415: \"That media type isn't supported.\",\n 422: \"The request was understood but couldn't be processed.\",\n 429: \"Request rate limit exceeded. Wait a moment before trying again.\",\n 500: \"The server hit an unexpected error.\",\n 501: \"The server doesn't support that operation.\",\n 502: \"The gateway got an invalid response from an upstream server.\",\n 503: \"The service is temporarily unavailable.\",\n 504: \"The gateway timed out waiting for an upstream server.\",\n};\n\nfunction hasContractCode(problem: Problem): boolean {\n return typeof problem.code === \"string\" && problem.code !== \"\";\n}\n\n/** Reason phrase for a status — map first, then a non-generic `problem.title`. */\nexport function httpReasonPhrase(\n status: number,\n fallbackTitle?: string,\n): string | undefined {\n if (HTTP_REASON_PHRASE[status]) return HTTP_REASON_PHRASE[status];\n if (\n fallbackTitle &&\n fallbackTitle !== GENERIC_ERROR_TITLE &&\n fallbackTitle !== \"Request failed\"\n ) {\n return fallbackTitle.replace(/\\.$/, \"\");\n }\n return undefined;\n}\n\n/** Human sentence for a bare HTTP status, when the body carried no copy. */\nexport function httpStatusExplanation(status: number): string {\n return (\n HTTP_STATUS_EXPLANATION[status] ??\n \"The request failed with an unexpected status.\"\n );\n}\n\n/**\n * Sentence-case the first character. Server `detail` / `title` sometimes\n * arrive fully lowercase; UI copy always leads with a capital.\n */\nexport function capitalizeFirst(text: string): string {\n if (!text) return text;\n const first = text.charAt(0);\n const upper = first.toUpperCase();\n if (first === upper) return text;\n return upper + text.slice(1);\n}\n\n/**\n * Turn a caught value into displayable copy. `Error` and `ErrorView` call\n * this internally; use it directly for other surfaces (a toast, a banner).\n *\n * Status-only failures (HTTP not ok, but no contract `code` / copy) still\n * keep `problem` so the details panel can show the status. Title becomes the\n * reason phrase (e.g. \"Bad Gateway\"); description is a short explanation —\n * not just the numeric code.\n */\nexport function describeError(error: unknown): ErrorDescription {\n const problem = parseProblem(error);\n if (problem == null) return { title: GENERIC_ERROR_TITLE };\n\n const description =\n [problem.detail, problem.remediation?.action]\n .filter((part): part is string => typeof part === \"string\" && part !== \"\")\n .join(\" \") || undefined;\n\n if (!hasContractCode(problem) && description == null) {\n const reason = httpReasonPhrase(problem.status, problem.title);\n return {\n title: capitalizeFirst(reason ?? GENERIC_ERROR_TITLE),\n description: httpStatusExplanation(problem.status),\n requestId: problem.requestId,\n problem,\n };\n }\n\n return {\n title: capitalizeFirst(problem.title || GENERIC_ERROR_TITLE),\n description: description ? capitalizeFirst(description) : undefined,\n documentation: problem.remediation?.documentation,\n requestId: problem.requestId,\n problem,\n };\n}\n","import {\n useEffect,\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n} from \"react\";\nimport {\n IconAlertCircleFilled,\n IconAlertTriangle,\n IconInfoCircle,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button, ButtonLink } from \"../button/button\";\nimport { Popover } from \"../popover/popover\";\nimport { StatusView, type StatusViewSize } from \"../status-view/status-view\";\nimport {\n capitalizeFirst,\n describeError,\n httpReasonPhrase,\n type ErrorDescription,\n} from \"./problem\";\n\n/** Capitalize string copy; leave custom ReactNode overrides alone. */\nfunction displayCopy(value: ReactNode): ReactNode {\n return typeof value === \"string\" ? capitalizeFirst(value) : value;\n}\n\n/**\n * Design notes:\n * - ONE input: `error` is the caught value, whatever it is — a Problem\n * Details body from `@photon-hq/error`, an `Error` carrying one as\n * `cause`, or something unknown. The component derives its copy via\n * `describeError`; unknowns fall back to a generic line rather than\n * leaking raw messages.\n * - TWO presentations, one per altitude: `Error` is the inline line for\n * forms, cards, and action rows; `ErrorView` is the region / page state\n * built on StatusView (same `sm` / `base` size axis).\n * - Both render `null` when there is nothing to show, so they can sit\n * unconditionally in JSX (`<Error error={mutation.error} />`).\n * - Client-side *validation* is not this component's job — that belongs to\n * `Field.Error`, wired to control validity.\n */\n\nconst DOC_LINK_LABEL = \"Learn more\";\nconst RETRY_LABEL = \"Try again\";\n\ninterface ErrorBaseProps {\n /** The caught value — a problem body, an `Error` wrapping one, or unknown. */\n error?: unknown;\n /** Override the derived message. */\n children?: ReactNode;\n}\n\nexport interface ErrorProps\n extends ErrorBaseProps, Omit<ComponentProps<\"div\">, keyof ErrorBaseProps> {}\n\n/**\n * Error — one line of red ink naming a server failure (4xx / 5xx), placed\n * inline: under a form, in a card, beside the action that failed. Give it the\n * caught value and it renders the problem's `detail` (falling back to `title`,\n * then to a generic line), plus a docs link when the problem carries one.\n * Renders nothing while `error` is nullish, so it can stay mounted.\n *\n * For a region or page that failed to load, use {@link ErrorView}.\n */\nexport function Error({ error, children, className, ...props }: ErrorProps) {\n if (error == null && children == null) return null;\n const copy = describeError(error);\n return (\n <div\n role=\"alert\"\n className={cn(\n \"text-pho-error flex min-w-0 items-start gap-1.5 text-base\",\n className,\n )}\n {...props}\n >\n <span aria-hidden className=\"flex h-[1lh] shrink-0 items-center\">\n <IconAlertCircleFilled className=\"size-4\" />\n </span>\n <span className=\"min-w-0\">\n {displayCopy(children ?? copy.description ?? copy.title)}\n {copy.documentation != null && (\n <>\n {\" \"}\n <a\n href={copy.documentation}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"font-medium underline underline-offset-2\"\n >\n {DOC_LINK_LABEL}\n </a>\n </>\n )}\n {/* Trailing whitespace collapses when the details render null. */}{\" \"}\n <ErrorDetails copy={copy} />\n </span>\n </div>\n );\n}\n\nError.displayName = \"Error\";\n\n/**\n * Hover / focus disclosure on the inline line — the request's fuller story:\n * problem `title` (with the same alert icon + `text-pho-error` ink as the\n * inline line), the untruncated description, then `status` + `code` and the\n * copyable request id grouped below for a support handoff. Renders only when\n * the caught value actually carried a problem (or at least a request id); a\n * generic unknown has nothing more to disclose. Built on `Popover` rather\n * than `Tooltip` because the panel holds an interactive control (the copy\n * button) — `openOnHover` keeps the tooltip-like gesture.\n */\nfunction ErrorDetails({ copy }: { copy: ErrorDescription }) {\n const { problem, requestId } = copy;\n if (problem == null && requestId == null) return null;\n\n // Contract problems show `status CODE`; status-only shows `status Reason`.\n let statusLine: string | null = null;\n if (problem != null) {\n if (problem.code) {\n statusLine = `${problem.status} ${problem.code}`;\n } else {\n const reason = httpReasonPhrase(problem.status, problem.title);\n statusLine = reason\n ? `${problem.status} ${reason}`\n : String(problem.status);\n }\n }\n\n return (\n <Popover.Root>\n <Popover.Trigger\n openOnHover\n delay={150}\n aria-label=\"Error details\"\n className=\"outline-pho-brand inline-flex size-4 shrink-0 translate-y-[3px] cursor-help items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-2\"\n >\n <IconInfoCircle className=\"size-3.5\" />\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Positioner align=\"start\">\n <Popover.Popup className=\"text-pho-error\">\n <Popover.Title className=\"text-pho-error flex items-start gap-1.5\">\n <span aria-hidden className=\"flex h-[1lh] shrink-0 items-center\">\n <IconAlertCircleFilled className=\"size-4\" />\n </span>\n {copy.title}\n </Popover.Title>\n {copy.description != null && (\n <Popover.Description className=\"text-pho-error\">\n {copy.description}\n </Popover.Description>\n )}\n {(statusLine != null || requestId != null) && (\n <div className=\"text-pho-error mt-1 font-mono text-[10px] leading-snug\">\n {statusLine != null && <p>{statusLine}</p>}\n {requestId != null && (\n <RequestId requestId={requestId} className=\"mt-0\" />\n )}\n </div>\n )}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\n/** Request-id footnote — click copies the id for support handoff. */\nfunction RequestId({\n requestId,\n className,\n}: {\n requestId: string;\n className?: string;\n}) {\n const [copied, setCopied] = useState(false);\n const copiedTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(\n () => () => {\n if (copiedTimer.current) clearTimeout(copiedTimer.current);\n },\n [],\n );\n\n return (\n <span\n className={cn(\"mt-1 block font-mono text-[10px] leading-snug\", className)}\n >\n Request ID:{\" \"}\n <button\n type=\"button\"\n className=\"outline-pho-brand inline cursor-pointer underline-offset-2 select-all hover:underline focus-visible:underline focus-visible:outline-2 focus-visible:-outline-offset-1\"\n aria-label={\n copied ? \"Request ID copied\" : `Copy request ID ${requestId}`\n }\n onClick={async () => {\n try {\n await navigator.clipboard.writeText(requestId);\n } catch {\n return;\n }\n setCopied(true);\n if (copiedTimer.current) clearTimeout(copiedTimer.current);\n copiedTimer.current = setTimeout(() => setCopied(false), 1500);\n }}\n >\n {requestId}\n </button>\n <output className=\"sr-only\" aria-live=\"polite\">\n {copied ? \"Copied\" : \"\"}\n </output>\n </span>\n );\n}\n\ninterface ErrorViewBaseProps {\n /** The caught value — a problem body, an `Error` wrapping one, or unknown. */\n error?: unknown;\n /** Override the derived title. */\n title?: ReactNode;\n /** Override the derived description. */\n description?: ReactNode;\n /** Override the warning glyph. */\n icon?: ReactNode;\n /** Offer a retry — renders a \"Try again\" button. */\n onRetry?: () => void;\n /** Replace the built-in action row entirely. */\n actions?: ReactNode;\n /** Size variant — StatusView's axis. @default \"base\" */\n size?: StatusViewSize;\n}\n\nexport interface ErrorViewProps\n extends\n ErrorViewBaseProps,\n Omit<ComponentProps<\"div\">, keyof ErrorViewBaseProps | \"children\"> {}\n\n/**\n * ErrorView — the failed state of a region or page, built on StatusView:\n * warning icon over the problem's `title`, its `detail` and remediation\n * below, an action row (`onRetry` and the problem's docs link), and the\n * request id as a footnote for support. Announces via `role=\"alert\"`.\n *\n * Use `size=\"sm\"` inside cards and panels, the default `base` for whole\n * pages. Renders nothing while `error` is nullish (unless given a static\n * `title`), so it can sit unconditionally next to a query.\n */\nexport function ErrorView({\n error,\n title,\n description,\n icon,\n onRetry,\n actions,\n size = \"base\",\n ...props\n}: ErrorViewProps) {\n if (error == null && title == null) return null;\n const copy = describeError(error);\n\n const resolvedDescription = displayCopy(description ?? copy.description);\n const body =\n resolvedDescription != null || copy.requestId != null ? (\n <>\n {resolvedDescription}\n {copy.requestId != null && <RequestId requestId={copy.requestId} />}\n </>\n ) : undefined;\n\n const resolvedActions =\n actions ??\n (onRetry != null || copy.documentation != null ? (\n <>\n {onRetry != null && (\n <Button size=\"sm\" onClick={onRetry}>\n {RETRY_LABEL}\n </Button>\n )}\n {copy.documentation != null && (\n <ButtonLink\n size=\"sm\"\n variant=\"outlined\"\n href={copy.documentation}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {DOC_LINK_LABEL}\n </ButtonLink>\n )}\n </>\n ) : undefined);\n\n return (\n <StatusView\n role=\"alert\"\n size={size}\n icon={icon ?? <IconAlertTriangle />}\n title={displayCopy(title ?? copy.title)}\n description={body}\n actions={resolvedActions}\n {...props}\n />\n );\n}\n\nErrorView.displayName = \"ErrorView\";\n"],"x_google_ignoreList":[0],"mappings":"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"}
1
+ {"version":3,"file":"error-D5SzZ0ev.js","names":[],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.46.0_react@19.2.8/node_modules/@tabler/icons-react/dist/esm/icons/IconAlertTriangle.mjs","../../src/components/error/problem.ts","../../src/components/error/error.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 9v4\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M12 16h.01\", \"key\": \"svg-2\" }]];\nconst IconAlertTriangle = createReactComponent(\"outline\", \"alert-triangle\", \"AlertTriangle\", __iconNode);\n\nexport { __iconNode, IconAlertTriangle as default };\n//# sourceMappingURL=IconAlertTriangle.mjs.map\n","/**\n * Client-side mirror of the `@photon-hq/error` response contract — the\n * RFC 9457 Problem Details body every Photon service returns for 4xx / 5xx.\n * Machine logic branches on `code`; `title` / `detail` / `remediation` are\n * the human-readable copy, already reviewed server-side and safe to render.\n *\n * Fetch layers may also hand us a thin status-only shape when the response\n * was not ok but the body was not a contract problem — `title` + `status`\n * still count so the UI can disclose the HTTP code we already know.\n */\n\nexport interface ProblemRemediation {\n /** What the user can do about it — a full sentence. */\n action?: string;\n /** Docs URL explaining the problem. */\n documentation?: string;\n}\n\nexport interface Problem {\n /** Stable machine-readable key (`RATE_LIMITED`) — the field to branch on. */\n code?: string;\n /** Human summary of the problem type (\"Too Many Requests\"). */\n title: string;\n /** HTTP status (4xx / 5xx). */\n status: number;\n /** Problem type URI (`urn:photon:problem:*` or an https URL). */\n type?: string;\n /** Occurrence-specific human sentence. */\n detail?: string;\n /** Correlation id for support (`X-Request-ID`). */\n requestId?: string;\n remediation?: ProblemRemediation;\n /** RFC 9457 extensions (`issues`, `actualVersion`, …). */\n [extension: string]: unknown;\n}\n\n/** Structural check: `title` + a 4xx/5xx status. `code` is optional. */\nexport function isProblem(value: unknown): value is Problem {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v.title === \"string\" &&\n typeof v.status === \"number\" &&\n Number.isInteger(v.status) &&\n v.status >= 400 &&\n v.status <= 599 &&\n (v.code === undefined || typeof v.code === \"string\")\n );\n}\n\n/**\n * Find the problem a caught value carries — the value itself, one typed onto\n * an error as a `problem` field (dashboard's `ApiError` shape), or one\n * wrapped in an `Error` `cause` chain (how fetch layers usually rethrow a\n * parsed body). Returns `null` when there is none.\n */\nexport function parseProblem(error: unknown): Problem | null {\n let current: unknown = error;\n for (\n let depth = 0;\n depth < 8 && typeof current === \"object\" && current !== null;\n depth++\n ) {\n if (isProblem(current)) return current;\n const carried = (current as { problem?: unknown }).problem;\n if (isProblem(carried)) return carried;\n current = (current as { cause?: unknown }).cause;\n }\n return null;\n}\n\nexport interface ErrorDescription {\n /** Short name of the failure — the problem `title`, or a generic fallback. */\n title: string;\n /** Sentence(s) to show — `detail` and `remediation.action` joined. */\n description?: string;\n /** Docs URL from `remediation.documentation`. */\n documentation?: string;\n /** Correlation id for support. */\n requestId?: string;\n /** The matched problem, when the input carried one. */\n problem?: Problem;\n}\n\n/**\n * Anything that isn't a problem renders as this — raw `Error` messages are\n * not contract copy and never shown (the same fail-closed stance as the\n * server side of `@photon-hq/error`). Always a full sentence (trailing\n * period).\n */\nexport const GENERIC_ERROR_TITLE = \"Something went wrong.\";\n\n/** Standard reason phrases for statuses we commonly surface without a body. */\nconst HTTP_REASON_PHRASE: Record<number, string> = {\n 400: \"Bad Request\",\n 401: \"Unauthorized\",\n 403: \"Forbidden\",\n 404: \"Not Found\",\n 408: \"Request Timeout\",\n 409: \"Conflict\",\n 410: \"Gone\",\n 413: \"Payload Too Large\",\n 415: \"Unsupported Media Type\",\n 422: \"Unprocessable Entity\",\n 429: \"Too Many Requests\",\n 500: \"Internal Server Error\",\n 501: \"Not Implemented\",\n 502: \"Bad Gateway\",\n 503: \"Service Unavailable\",\n 504: \"Gateway Timeout\",\n};\n\n/** One-sentence explanations when the server gave a status but no problem copy. */\nconst HTTP_STATUS_EXPLANATION: Record<number, string> = {\n 400: \"The request was malformed or incomplete.\",\n 401: \"You need to sign in again.\",\n 403: \"You don't have permission to do that.\",\n 404: \"The requested resource was not found.\",\n 408: \"The request timed out before the server responded.\",\n 409: \"The request conflicts with the current state.\",\n 410: \"That resource is no longer available.\",\n 413: \"The request was too large for the server to accept.\",\n 415: \"That media type isn't supported.\",\n 422: \"The request was understood but couldn't be processed.\",\n 429: \"Request rate limit exceeded. Wait a moment before trying again.\",\n 500: \"The server hit an unexpected error.\",\n 501: \"The server doesn't support that operation.\",\n 502: \"The gateway got an invalid response from an upstream server.\",\n 503: \"The service is temporarily unavailable.\",\n 504: \"The gateway timed out waiting for an upstream server.\",\n};\n\nfunction hasContractCode(problem: Problem): boolean {\n return typeof problem.code === \"string\" && problem.code !== \"\";\n}\n\n/** Reason phrase for a status — map first, then a non-generic `problem.title`. */\nexport function httpReasonPhrase(\n status: number,\n fallbackTitle?: string,\n): string | undefined {\n if (HTTP_REASON_PHRASE[status]) return HTTP_REASON_PHRASE[status];\n if (\n fallbackTitle &&\n fallbackTitle !== GENERIC_ERROR_TITLE &&\n fallbackTitle !== \"Request failed\"\n ) {\n return fallbackTitle.replace(/\\.$/, \"\");\n }\n return undefined;\n}\n\n/** Human sentence for a bare HTTP status, when the body carried no copy. */\nexport function httpStatusExplanation(status: number): string {\n return (\n HTTP_STATUS_EXPLANATION[status] ??\n \"The request failed with an unexpected status.\"\n );\n}\n\n/**\n * Sentence-case the first character. Server `detail` / `title` sometimes\n * arrive fully lowercase; UI copy always leads with a capital.\n */\nexport function capitalizeFirst(text: string): string {\n if (!text) return text;\n const first = text.charAt(0);\n const upper = first.toUpperCase();\n if (first === upper) return text;\n return upper + text.slice(1);\n}\n\n/**\n * Turn a caught value into displayable copy. `Error` and `ErrorView` call\n * this internally; use it directly for other surfaces (a toast, a banner).\n *\n * Status-only failures (HTTP not ok, but no contract `code` / copy) still\n * keep `problem` so the details panel can show the status. Title becomes the\n * reason phrase (e.g. \"Bad Gateway\"); description is a short explanation —\n * not just the numeric code.\n */\nexport function describeError(error: unknown): ErrorDescription {\n const problem = parseProblem(error);\n if (problem == null) return { title: GENERIC_ERROR_TITLE };\n\n const description =\n [problem.detail, problem.remediation?.action]\n .filter((part): part is string => typeof part === \"string\" && part !== \"\")\n .join(\" \") || undefined;\n\n if (!hasContractCode(problem) && description == null) {\n const reason = httpReasonPhrase(problem.status, problem.title);\n return {\n title: capitalizeFirst(reason ?? GENERIC_ERROR_TITLE),\n description: httpStatusExplanation(problem.status),\n requestId: problem.requestId,\n problem,\n };\n }\n\n return {\n title: capitalizeFirst(problem.title || GENERIC_ERROR_TITLE),\n description: description ? capitalizeFirst(description) : undefined,\n documentation: problem.remediation?.documentation,\n requestId: problem.requestId,\n problem,\n };\n}\n","import {\n useEffect,\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n} from \"react\";\nimport {\n IconAlertCircleFilled,\n IconAlertTriangle,\n IconInfoCircle,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button, ButtonLink } from \"../button/button\";\nimport { Popover } from \"../popover/popover\";\nimport { StatusView, type StatusViewSize } from \"../status-view/status-view\";\nimport {\n capitalizeFirst,\n describeError,\n httpReasonPhrase,\n type ErrorDescription,\n} from \"./problem\";\n\n/** Capitalize string copy; leave custom ReactNode overrides alone. */\nfunction displayCopy(value: ReactNode): ReactNode {\n return typeof value === \"string\" ? capitalizeFirst(value) : value;\n}\n\n/**\n * Design notes:\n * - ONE input: `error` is the caught value, whatever it is — a Problem\n * Details body from `@photon-hq/error`, an `Error` carrying one as\n * `cause`, or something unknown. The component derives its copy via\n * `describeError`; unknowns fall back to a generic line rather than\n * leaking raw messages.\n * - TWO presentations, one per altitude: `Error` is the inline line for\n * forms, cards, and action rows; `ErrorView` is the region / page state\n * built on StatusView (same `sm` / `base` size axis).\n * - Both render `null` when there is nothing to show, so they can sit\n * unconditionally in JSX (`<Error error={mutation.error} />`).\n * - Client-side *validation* is not this component's job — that belongs to\n * `Field.Error`, wired to control validity.\n */\n\nconst DOC_LINK_LABEL = \"Learn more\";\nconst RETRY_LABEL = \"Try again\";\n\ninterface ErrorBaseProps {\n /** The caught value — a problem body, an `Error` wrapping one, or unknown. */\n error?: unknown;\n /** Override the derived message. */\n children?: ReactNode;\n}\n\nexport interface ErrorProps\n extends ErrorBaseProps, Omit<ComponentProps<\"div\">, keyof ErrorBaseProps> {}\n\n/**\n * Error — one line of red ink naming a server failure (4xx / 5xx), placed\n * inline: under a form, in a card, beside the action that failed. Give it the\n * caught value and it renders the problem's `detail` (falling back to `title`,\n * then to a generic line), plus a docs link when the problem carries one.\n * Renders nothing while `error` is nullish, so it can stay mounted.\n *\n * For a region or page that failed to load, use {@link ErrorView}.\n */\nexport function Error({ error, children, className, ...props }: ErrorProps) {\n if (error == null && children == null) return null;\n const copy = describeError(error);\n return (\n <div\n role=\"alert\"\n className={cn(\n \"text-pho-error flex min-w-0 items-start gap-1.5 text-base\",\n className,\n )}\n {...props}\n >\n <span aria-hidden className=\"flex h-[1lh] shrink-0 items-center\">\n <IconAlertCircleFilled className=\"size-4\" />\n </span>\n <span className=\"min-w-0\">\n {displayCopy(children ?? copy.description ?? copy.title)}\n {copy.documentation != null && (\n <>\n {\" \"}\n <a\n href={copy.documentation}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"font-medium underline underline-offset-2\"\n >\n {DOC_LINK_LABEL}\n </a>\n </>\n )}\n {/* Trailing whitespace collapses when the details render null. */}{\" \"}\n <ErrorDetails copy={copy} />\n </span>\n </div>\n );\n}\n\nError.displayName = \"Error\";\n\n/**\n * Hover / focus disclosure on the inline line — the request's fuller story:\n * problem `title` (with the same alert icon + `text-pho-error` ink as the\n * inline line), the untruncated description, then `status` + `code` and the\n * copyable request id grouped below for a support handoff. Renders only when\n * the caught value actually carried a problem (or at least a request id); a\n * generic unknown has nothing more to disclose. Built on `Popover` rather\n * than `Tooltip` because the panel holds an interactive control (the copy\n * button) — `openOnHover` keeps the tooltip-like gesture.\n */\nfunction ErrorDetails({ copy }: { copy: ErrorDescription }) {\n const { problem, requestId } = copy;\n if (problem == null && requestId == null) return null;\n\n // Contract problems show `status CODE`; status-only shows `status Reason`.\n let statusLine: string | null = null;\n if (problem != null) {\n if (problem.code) {\n statusLine = `${problem.status} ${problem.code}`;\n } else {\n const reason = httpReasonPhrase(problem.status, problem.title);\n statusLine = reason\n ? `${problem.status} ${reason}`\n : String(problem.status);\n }\n }\n\n return (\n <Popover.Root>\n <Popover.Trigger\n openOnHover\n delay={150}\n aria-label=\"Error details\"\n className=\"outline-pho-brand inline-flex size-4 shrink-0 translate-y-[3px] cursor-help items-center justify-center rounded-full opacity-70 transition-opacity hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-2\"\n >\n <IconInfoCircle className=\"size-3.5\" />\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Positioner align=\"start\">\n <Popover.Popup className=\"text-pho-error\">\n <Popover.Title className=\"text-pho-error flex items-start gap-1.5\">\n <span aria-hidden className=\"flex h-[1lh] shrink-0 items-center\">\n <IconAlertCircleFilled className=\"size-4\" />\n </span>\n {copy.title}\n </Popover.Title>\n {copy.description != null && (\n <Popover.Description className=\"text-pho-error\">\n {copy.description}\n </Popover.Description>\n )}\n {(statusLine != null || requestId != null) && (\n <div className=\"text-pho-error mt-1 font-mono text-[10px] leading-snug\">\n {statusLine != null && <p>{statusLine}</p>}\n {requestId != null && (\n <RequestId requestId={requestId} className=\"mt-0\" />\n )}\n </div>\n )}\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\n/** Request-id footnote — click copies the id for support handoff. */\nfunction RequestId({\n requestId,\n className,\n}: {\n requestId: string;\n className?: string;\n}) {\n const [copied, setCopied] = useState(false);\n const copiedTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(\n () => () => {\n if (copiedTimer.current) clearTimeout(copiedTimer.current);\n },\n [],\n );\n\n return (\n <span\n className={cn(\"mt-1 block font-mono text-[10px] leading-snug\", className)}\n >\n Request ID:{\" \"}\n <button\n type=\"button\"\n className=\"outline-pho-brand inline cursor-pointer underline-offset-2 select-all hover:underline focus-visible:underline focus-visible:outline-2 focus-visible:-outline-offset-1\"\n aria-label={\n copied ? \"Request ID copied\" : `Copy request ID ${requestId}`\n }\n onClick={async () => {\n try {\n await navigator.clipboard.writeText(requestId);\n } catch {\n return;\n }\n setCopied(true);\n if (copiedTimer.current) clearTimeout(copiedTimer.current);\n copiedTimer.current = setTimeout(() => setCopied(false), 1500);\n }}\n >\n {requestId}\n </button>\n <output className=\"sr-only\" aria-live=\"polite\">\n {copied ? \"Copied\" : \"\"}\n </output>\n </span>\n );\n}\n\ninterface ErrorViewBaseProps {\n /** The caught value — a problem body, an `Error` wrapping one, or unknown. */\n error?: unknown;\n /** Override the derived title. */\n title?: ReactNode;\n /** Override the derived description. */\n description?: ReactNode;\n /** Override the warning glyph. */\n icon?: ReactNode;\n /** Offer a retry — renders a \"Try again\" button. */\n onRetry?: () => void;\n /** Replace the built-in action row entirely. */\n actions?: ReactNode;\n /** Size variant — StatusView's axis. @default \"base\" */\n size?: StatusViewSize;\n}\n\nexport interface ErrorViewProps\n extends\n ErrorViewBaseProps,\n Omit<ComponentProps<\"div\">, keyof ErrorViewBaseProps | \"children\"> {}\n\n/**\n * ErrorView — the failed state of a region or page, built on StatusView:\n * warning icon over the problem's `title`, its `detail` and remediation\n * below, an action row (`onRetry` and the problem's docs link), and the\n * request id as a footnote for support. Announces via `role=\"alert\"`.\n *\n * Use `size=\"sm\"` inside cards and panels, the default `base` for whole\n * pages. Renders nothing while `error` is nullish (unless given a static\n * `title`), so it can sit unconditionally next to a query.\n */\nexport function ErrorView({\n error,\n title,\n description,\n icon,\n onRetry,\n actions,\n size = \"base\",\n ...props\n}: ErrorViewProps) {\n if (error == null && title == null) return null;\n const copy = describeError(error);\n\n const resolvedDescription = displayCopy(description ?? copy.description);\n const body =\n resolvedDescription != null || copy.requestId != null ? (\n <>\n {resolvedDescription}\n {copy.requestId != null && <RequestId requestId={copy.requestId} />}\n </>\n ) : undefined;\n\n const resolvedActions =\n actions ??\n (onRetry != null || copy.documentation != null ? (\n <>\n {onRetry != null && (\n <Button size=\"sm\" onClick={onRetry}>\n {RETRY_LABEL}\n </Button>\n )}\n {copy.documentation != null && (\n <ButtonLink\n size=\"sm\"\n variant=\"outlined\"\n href={copy.documentation}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {DOC_LINK_LABEL}\n </ButtonLink>\n )}\n </>\n ) : undefined);\n\n return (\n <StatusView\n role=\"alert\"\n size={size}\n icon={icon ?? <IconAlertTriangle />}\n title={displayCopy(title ?? copy.title)}\n description={body}\n actions={resolvedActions}\n {...props}\n />\n );\n}\n\nErrorView.displayName = \"ErrorView\";\n"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;AASA,IAAM,IAAa;AAAA,EAAC,CAAC,QAAQ;AAAA,IAAE,GAAK;AAAA,IAAW,KAAO;AAAA,EAAQ,CAAC;AAAA,EAAG,CAAC,QAAQ;AAAA,IAAE,GAAK;AAAA,IAA4I,KAAO;AAAA,EAAQ,CAAC;AAAA,EAAG,CAAC,QAAQ;AAAA,IAAE,GAAK;AAAA,IAAc,KAAO;AAAA,EAAQ,CAAC;AAAC,GAC1R,IAAoB,EAAqB,WAAW,kBAAkB,iBAAiB,CAAU;AC2BvG,SAAgB,EAAU,GAAkC;AAC1D,MAAI,OAAO,KAAU,YAAY,MAAU,KAAM,QAAO;AACxD,QAAM,IAAI;AACV,SACE,OAAO,EAAE,SAAU,YACnB,OAAO,EAAE,UAAW,YACpB,OAAO,UAAU,EAAE,MAAM,KACzB,EAAE,UAAU,OACZ,EAAE,UAAU,QACX,EAAE,SAAS,UAAa,OAAO,EAAE,QAAS;AAE/C;AAQA,SAAgB,EAAa,GAAgC;AAC3D,MAAI,IAAmB;AACvB,WACM,IAAQ,GACZ,IAAQ,KAAK,OAAO,KAAY,YAAY,MAAY,MACxD,KACA;AACA,QAAI,EAAU,CAAO,EAAG,QAAO;AAC/B,UAAM,IAAW,EAAkC;AACnD,QAAI,EAAU,CAAO,EAAG,QAAO;AAC/B,IAAA,IAAW,EAAgC;AAAA,EAC7C;AACA,SAAO;AACT;AAqBA,IAAa,IAAsB,yBAG7B,IAA6C;AAAA,EACjD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP,GAGM,IAAkD;AAAA,EACtD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAEA,SAAS,EAAgB,GAA2B;AAClD,SAAO,OAAO,EAAQ,QAAS,YAAY,EAAQ,SAAS;AAC9D;AAGA,SAAgB,EACd,GACA,GACoB;AACpB,MAAI,EAAmB,CAAA,EAAS,QAAO,EAAmB,CAAA;AAC1D,MACE,KACA,MAAA,2BACA,MAAkB,iBAElB,QAAO,EAAc,QAAQ,OAAO,EAAE;AAG1C;AAGA,SAAgB,EAAsB,GAAwB;AAC5D,SACE,EAAwB,CAAA,KACxB;AAEJ;AAMA,SAAgB,EAAgB,GAAsB;AACpD,MAAI,CAAC,EAAM,QAAO;AAClB,QAAM,IAAQ,EAAK,OAAO,CAAC,GACrB,IAAQ,EAAM,YAAY;AAChC,SAAI,MAAU,IAAc,IACrB,IAAQ,EAAK,MAAM,CAAC;AAC7B;AAWA,SAAgB,EAAc,GAAkC;AAC9D,QAAM,IAAU,EAAa,CAAK;AAClC,MAAI,KAAW,KAAM,QAAO,EAAE,OAAO,EAAoB;AAEzD,QAAM,IACJ,CAAC,EAAQ,QAAQ,EAAQ,aAAa,MAAM,EACzC,OAAA,CAAQ,MAAyB,OAAO,KAAS,YAAY,MAAS,EAAE,EACxE,KAAK,GAAG,KAAK;AAElB,SAAI,CAAC,EAAgB,CAAO,KAAK,KAAe,OAEvC;AAAA,IACL,OAAO,EAFM,EAAiB,EAAQ,QAAQ,EAAQ,KAE/B,KAAA,uBAA6B;AAAA,IACpD,aAAa,EAAsB,EAAQ,MAAM;AAAA,IACjD,WAAW,EAAQ;AAAA,IACnB,SAAA;AAAA,EACF,IAGK;AAAA,IACL,OAAO,EAAgB,EAAQ,SAAA,uBAA4B;AAAA,IAC3D,aAAa,IAAc,EAAgB,CAAW,IAAI;AAAA,IAC1D,eAAe,EAAQ,aAAa;AAAA,IACpC,WAAW,EAAQ;AAAA,IACnB,SAAA;AAAA,EACF;AACF;ACvLA,SAAS,EAAY,GAA6B;AAChD,SAAO,OAAO,KAAU,WAAW,EAAgB,CAAK,IAAI;AAC9D;AAkBA,IAAM,IAAiB,cACjB,IAAc;AAqBpB,SAAgB,EAAM,EAAE,OAAA,GAAO,UAAA,GAAU,WAAA,GAAW,GAAG,EAAA,GAAqB;AAC1E,MAAI,KAAS,QAAQ,KAAY,KAAM,QAAO;AAC9C,QAAM,IAAO,EAAc,CAAK;AAChC,SACE,gBAAA,EAAC,OAAD;AAAA,IACE,MAAK;AAAA,IACL,WAAW,EACT,6DACA,CACF;AAAA,IACA,GAAI;AAAA,IANN,UAAA,CAQE,gBAAA,EAAC,QAAD;AAAA,MAAM,eAAA;AAAA,MAAY,WAAU;AAAA,MAC1B,UAAA,gBAAA,EAAC,GAAD,EAAuB,WAAU,SAAU,CAAA;AAAA,IACvC,CAAA,GACN,gBAAA,EAAC,QAAD;AAAA,MAAM,WAAU;AAAA,MAAhB,UAAA;AAAA,QACG,EAAY,KAAY,EAAK,eAAe,EAAK,KAAK;AAAA,QACtD,EAAK,iBAAiB,QACrB,gBAAA,EAAA,GAAA,EAAA,UAAA,CACG,KACD,gBAAA,EAAC,KAAD;AAAA,UACE,MAAM,EAAK;AAAA,UACX,QAAO;AAAA,UACP,KAAI;AAAA,UACJ,WAAU;AAAA,UAET,UAAA;AAAA,QACA,CAAA,CACH,EAAA,CAAA;AAAA,QAEgE;AAAA,QACpE,gBAAA,EAAC,GAAD,EAAoB,MAAA,EAAO,CAAA;AAAA,MACvB;AAAA,IACH,CAAA,CAAA;AAAA;AAET;AAEA,EAAM,cAAc;AAYpB,SAAS,EAAa,EAAE,MAAA,EAAA,GAAoC;AAC1D,QAAM,EAAE,SAAA,GAAS,WAAA,EAAA,IAAc;AAC/B,MAAI,KAAW,QAAQ,KAAa,KAAM,QAAO;AAGjD,MAAI,IAA4B;AAChC,MAAI,KAAW;AACb,QAAI,EAAQ,KACV,CAAA,IAAa,GAAG,EAAQ,MAAA,IAAU,EAAQ,IAAA;AAAA,SACrC;AACL,YAAM,IAAS,EAAiB,EAAQ,QAAQ,EAAQ,KAAK;AAC7D,MAAA,IAAa,IACT,GAAG,EAAQ,MAAA,IAAU,CAAA,KACrB,OAAO,EAAQ,MAAM;AAAA,IAC3B;AAGF,SACE,gBAAA,EAAC,EAAQ,MAAT,EAAA,UAAA,CACE,gBAAA,EAAC,EAAQ,SAAT;AAAA,IACE,aAAA;AAAA,IACA,OAAO;AAAA,IACP,cAAW;AAAA,IACX,WAAU;AAAA,IAEV,UAAA,gBAAA,EAAC,GAAD,EAAgB,WAAU,WAAY,CAAA;AAAA,EACvB,CAAA,GACjB,gBAAA,EAAC,EAAQ,QAAT,EAAA,UACE,gBAAA,EAAC,EAAQ,YAAT;AAAA,IAAoB,OAAM;AAAA,IACxB,UAAA,gBAAA,EAAC,EAAQ,OAAT;AAAA,MAAe,WAAU;AAAA,MAAzB,UAAA;AAAA,QACE,gBAAA,EAAC,EAAQ,OAAT;AAAA,UAAe,WAAU;AAAA,UAAzB,UAAA,CACE,gBAAA,EAAC,QAAD;AAAA,YAAM,eAAA;AAAA,YAAY,WAAU;AAAA,YAC1B,UAAA,gBAAA,EAAC,GAAD,EAAuB,WAAU,SAAU,CAAA;AAAA,UACvC,CAAA,GACL,EAAK,KACO;AAAA;QACd,EAAK,eAAe,QACnB,gBAAA,EAAC,EAAQ,aAAT;AAAA,UAAqB,WAAU;AAAA,UAC5B,UAAA,EAAK;AAAA,QACa,CAAA;AAAA,SAErB,KAAc,QAAQ,KAAa,SACnC,gBAAA,EAAC,OAAD;AAAA,UAAK,WAAU;AAAA,UAAf,UAAA,CACG,KAAc,QAAQ,gBAAA,EAAC,KAAD,EAAA,UAAI,EAAc,CAAA,GACxC,KAAa,QACZ,gBAAA,EAAC,GAAD;AAAA,YAAsB,WAAA;AAAA,YAAW,WAAU;AAAA,UAAQ,CAAA,CAElD;AAAA;MAEM;AAAA;EACG,CAAA,EACN,CAAA,CACJ,EAAA,CAAA;AAElB;AAGA,SAAS,EAAU,EACjB,WAAA,GACA,WAAA,EAAA,GAIC;AACD,QAAM,CAAC,GAAQ,CAAA,IAAa,EAAS,EAAK,GACpC,IAAc,EAA6C,IAAI;AAErE,SAAA,EAAA,MAAA,MACc;AACV,IAAI,EAAY,WAAS,aAAa,EAAY,OAAO;AAAA,EAC3D,GACA,CAAC,CACH,GAGE,gBAAA,EAAC,QAAD;AAAA,IACE,WAAW,EAAG,iDAAiD,CAAS;AAAA,IAD1E,UAAA;AAAA,MAEC;AAAA,MACa;AAAA,MACZ,gBAAA,EAAC,UAAD;AAAA,QACE,MAAK;AAAA,QACL,WAAU;AAAA,QACV,cACE,IAAS,sBAAsB,mBAAmB,CAAA;AAAA,QAEpD,SAAS,YAAY;AACnB,cAAI;AACF,kBAAM,UAAU,UAAU,UAAU,CAAS;AAAA,UAC/C,QAAQ;AACN;AAAA,UACF;AACA,UAAA,EAAU,EAAI,GACV,EAAY,WAAS,aAAa,EAAY,OAAO,GACzD,EAAY,UAAU,WAAA,MAAiB,EAAU,EAAK,GAAG,IAAI;AAAA,QAC/D;AAAA,QAEC,UAAA;AAAA,MACK,CAAA;AAAA,MACR,gBAAA,EAAC,UAAD;AAAA,QAAQ,WAAU;AAAA,QAAU,aAAU;AAAA,QACnC,UAAA,IAAS,WAAW;AAAA,MACf,CAAA;AAAA,IACJ;AAAA;AAEV;AAkCA,SAAgB,EAAU,EACxB,OAAA,GACA,OAAA,GACA,aAAA,GACA,MAAA,GACA,SAAA,GACA,SAAA,GACA,MAAA,IAAO,QACP,GAAG,EAAA,GACc;AACjB,MAAI,KAAS,QAAQ,KAAS,KAAM,QAAO;AAC3C,QAAM,IAAO,EAAc,CAAK,GAE1B,IAAsB,EAAY,KAAe,EAAK,WAAW,GACjE,IACJ,KAAuB,QAAQ,EAAK,aAAa,OAC/C,gBAAA,EAAA,GAAA,EAAA,UAAA,CACG,GACA,EAAK,aAAa,QAAQ,gBAAA,EAAC,GAAD,EAAW,WAAW,EAAK,UAAY,CAAA,CAClE,EAAA,CAAA,IACA,QAEA,IACJ,MACC,KAAW,QAAQ,EAAK,iBAAiB,OACxC,gBAAA,EAAA,GAAA,EAAA,UAAA,CACG,KAAW,QACV,gBAAA,EAAC,GAAD;AAAA,IAAQ,MAAK;AAAA,IAAK,SAAS;AAAA,IACxB,UAAA;AAAA,EACK,CAAA,GAET,EAAK,iBAAiB,QACrB,gBAAA,EAAC,GAAD;AAAA,IACE,MAAK;AAAA,IACL,SAAQ;AAAA,IACR,MAAM,EAAK;AAAA,IACX,QAAO;AAAA,IACP,KAAI;AAAA,IAEH,UAAA;AAAA,EACS,CAAA,CAEd,EAAA,CAAA,IACA;AAEN,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,MAAK;AAAA,IACC,MAAA;AAAA,IACN,MAAM,KAAQ,gBAAA,EAAC,GAAD,CAAoB,CAAA;AAAA,IAClC,OAAO,EAAY,KAAS,EAAK,KAAK;AAAA,IACtC,aAAa;AAAA,IACb,SAAS;AAAA,IACT,GAAI;AAAA,EACL,CAAA;AAEL;AAEA,EAAU,cAAc"}
@@ -1,13 +1,13 @@
1
1
  "use client";
2
2
  import { t as y } from "./cn-ChIgwEl3.js";
3
- import { a as P } from "./button-CgUS0j3D.js";
3
+ import { a as P } from "./button-C9VqBBIr.js";
4
4
  import { t as R } from "./createReactComponent-BqCmnqfX.js";
5
5
  import { t as S } from "./IconCheck-D2WuculQ.js";
6
6
  import { t as L } from "./IconSearch-BKAHkLyX.js";
7
7
  import { t as $ } from "./IconX-pZ9vrtSr.js";
8
8
  import { t as g } from "./popover-BhBJO346.js";
9
9
  import { t as w } from "./input-group-fc9_jD4d.js";
10
- import { t as d } from "./command-BfCCRaoc.js";
10
+ import { t as d } from "./command-iYvU6Mhf.js";
11
11
  import { useRef as D, useState as T } from "react";
12
12
  import { jsx as a, jsxs as p } from "react/jsx-runtime";
13
13
  var E = [["path", {
@@ -258,4 +258,4 @@ export {
258
258
  z as t
259
259
  };
260
260
 
261
- //# sourceMappingURL=filter-bar-BcpeTKCC.js.map
261
+ //# sourceMappingURL=filter-bar-B-oYYBsU.js.map