@hex-core/components 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tsup-dts-rollup.d.ts +575 -18
- package/dist/accordion.js.map +1 -1
- package/dist/alert-dialog.js.map +1 -1
- package/dist/alert.js.map +1 -1
- package/dist/arc.js.map +1 -1
- package/dist/attachment.js.map +1 -1
- package/dist/audio-player.js.map +1 -1
- package/dist/audio-waveform.js.map +1 -1
- package/dist/auth-forgot-password.js.map +1 -1
- package/dist/auth-reset-password.js.map +1 -1
- package/dist/auth-sign-in-split.js.map +1 -1
- package/dist/auth-sign-up-card.js.map +1 -1
- package/dist/auth-verify-email.js.map +1 -1
- package/dist/auth-verify-otp.js.map +1 -1
- package/dist/avatar.js.map +1 -1
- package/dist/badge.js.map +1 -1
- package/dist/branch.d.ts +2 -0
- package/dist/branch.js +136 -0
- package/dist/branch.js.map +1 -0
- package/dist/breadcrumb.js.map +1 -1
- package/dist/button.js.map +1 -1
- package/dist/calendar.js.map +1 -1
- package/dist/canvas.js.map +1 -1
- package/dist/card.js.map +1 -1
- package/dist/chain-of-thought.d.ts +3 -0
- package/dist/chain-of-thought.js +119 -0
- package/dist/chain-of-thought.js.map +1 -0
- package/dist/checkbox.js.map +1 -1
- package/dist/chord.js.map +1 -1
- package/dist/citation.js.map +1 -1
- package/dist/cloze.js.map +1 -1
- package/dist/cluster.js.map +1 -1
- package/dist/code-block-copy.js.map +1 -1
- package/dist/code-block.js.map +1 -1
- package/dist/color-picker.js.map +1 -1
- package/dist/combobox.js.map +1 -1
- package/dist/command.js.map +1 -1
- package/dist/compare-table.js.map +1 -1
- package/dist/composer.js.map +1 -1
- package/dist/container.js.map +1 -1
- package/dist/context-menu.js.map +1 -1
- package/dist/conversation.d.ts +3 -0
- package/dist/conversation.js +358 -0
- package/dist/conversation.js.map +1 -0
- package/dist/data-table.js.map +1 -1
- package/dist/date-picker.js.map +1 -1
- package/dist/deck.js.map +1 -1
- package/dist/dendrogram.js.map +1 -1
- package/dist/diagram.js.map +1 -1
- package/dist/dialog.js.map +1 -1
- package/dist/drawer.js.map +1 -1
- package/dist/dropdown-menu.js.map +1 -1
- package/dist/dropzone.js.map +1 -1
- package/dist/empty.js.map +1 -1
- package/dist/error-state.js.map +1 -1
- package/dist/file-tree.js.map +1 -1
- package/dist/flashcard.js.map +1 -1
- package/dist/flowchart.js.map +1 -1
- package/dist/form.js.map +1 -1
- package/dist/funnel.js.map +1 -1
- package/dist/gantt.js.map +1 -1
- package/dist/grid.js.map +1 -1
- package/dist/hover-card.js.map +1 -1
- package/dist/image-occlusion.js.map +1 -1
- package/dist/index.d.ts +21 -0
- package/dist/index.js +1011 -13
- package/dist/index.js.map +1 -1
- package/dist/inline-citation.d.ts +2 -0
- package/dist/inline-citation.js +108 -0
- package/dist/inline-citation.js.map +1 -0
- package/dist/input-otp.js.map +1 -1
- package/dist/input.js.map +1 -1
- package/dist/label.js.map +1 -1
- package/dist/loading-indicator.js.map +1 -1
- package/dist/loading.js.map +1 -1
- package/dist/markdown.d.ts +1 -0
- package/dist/markdown.js +784 -4
- package/dist/markdown.js.map +1 -1
- package/dist/matrix.js.map +1 -1
- package/dist/menubar.js.map +1 -1
- package/dist/message-actions.js.map +1 -1
- package/dist/message-list.js.map +1 -1
- package/dist/message.js.map +1 -1
- package/dist/mind-map.js.map +1 -1
- package/dist/multi-combobox.js.map +1 -1
- package/dist/navigation-menu.js.map +1 -1
- package/dist/org-chart.js.map +1 -1
- package/dist/pagination.js.map +1 -1
- package/dist/plan.d.ts +3 -0
- package/dist/plan.js +183 -0
- package/dist/plan.js.map +1 -0
- package/dist/popover.js.map +1 -1
- package/dist/progress.js.map +1 -1
- package/dist/pyramid.js.map +1 -1
- package/dist/quiz.js.map +1 -1
- package/dist/radio-group.js.map +1 -1
- package/dist/reasoning.js.map +1 -1
- package/dist/resizable.js.map +1 -1
- package/dist/sankey.js.map +1 -1
- package/dist/schemas.d.ts +8 -0
- package/dist/schemas.js +774 -17
- package/dist/schemas.js.map +1 -1
- package/dist/scroll-area.js.map +1 -1
- package/dist/select.js.map +1 -1
- package/dist/separator.js.map +1 -1
- package/dist/sequence.js.map +1 -1
- package/dist/sheet.js.map +1 -1
- package/dist/shimmer.d.ts +2 -0
- package/dist/shimmer.js +39 -0
- package/dist/shimmer.js.map +1 -0
- package/dist/sidebar.js.map +1 -1
- package/dist/skeleton.js.map +1 -1
- package/dist/slider.js.map +1 -1
- package/dist/sources.d.ts +3 -0
- package/dist/sources.js +164 -0
- package/dist/sources.js.map +1 -0
- package/dist/spaced-repetition.js.map +1 -1
- package/dist/spacer.js.map +1 -1
- package/dist/speech-recognition.js.map +1 -1
- package/dist/stack.js.map +1 -1
- package/dist/stepper.js.map +1 -1
- package/dist/suggestion.js.map +1 -1
- package/dist/sunburst.js.map +1 -1
- package/dist/switch.js.map +1 -1
- package/dist/table.js.map +1 -1
- package/dist/tabs.js.map +1 -1
- package/dist/tag.js.map +1 -1
- package/dist/task.d.ts +3 -0
- package/dist/task.js +189 -0
- package/dist/task.js.map +1 -0
- package/dist/terminal.js +11 -0
- package/dist/terminal.js.map +1 -1
- package/dist/textarea.js.map +1 -1
- package/dist/time-axis.js.map +1 -1
- package/dist/time-picker.js.map +1 -1
- package/dist/timeline.js.map +1 -1
- package/dist/toggle-group.js.map +1 -1
- package/dist/toggle.js.map +1 -1
- package/dist/tool-call.js +5 -6
- package/dist/tool-call.js.map +1 -1
- package/dist/toolbar.js.map +1 -1
- package/dist/tooltip.js.map +1 -1
- package/dist/tree-map.js.map +1 -1
- package/dist/tree.js.map +1 -1
- package/dist/venn.js.map +1 -1
- package/package.json +8 -3
package/dist/markdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/markdown/markdown.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;AC8BA,SAAS,QAAA,CAAS,EAAE,QAAA,EAAU,SAAA,EAAU,EAAkB;AACzD,EAAA,uBACC,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACV,2CAAA;AAAA,QACA,6DAAA;AAAA,QACA,yEAAA;AAAA,QACA,yFAAA;AAAA,QACA;AAAA,OACD;AAAA,MAEC;AAAA;AAAA,GACF;AAEF","file":"markdown.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Streamdown } from \"streamdown\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Streaming-safe markdown renderer. Wraps Vercel's `streamdown` so partial\n * input mid-stream — unclosed code fences, half-typed tags, dangling\n * brackets — renders gracefully instead of throwing or flashing raw text.\n *\n * Public prop surface is intentionally minimal (`children` + `className`)\n * so this primitive's DTS doesn't drag in `streamdown`'s full type graph.\n * Doing so would transitively pull Shiki's 600-literal `BundledLanguage`\n * union into the rollup-dts pass and exhaust heap. For per-element\n * overrides (custom `pre`, `code`, `a`, `img`, mermaid, math, line\n * numbers, plugins, etc.) drop down to `Streamdown` directly:\n *\n * ```tsx\n * import { Streamdown } from \"streamdown\";\n * import { CodeBlock } from \"@hex-core/components\";\n * <Streamdown components={{ pre: (p) => <CodeBlock {...p} /> }}>{md}</Streamdown>\n * ```\n *\n * @example\n * <Message role=\"assistant\">\n * <Markdown>{streamingText}</Markdown>\n * </Message>\n */\nexport interface MarkdownProps {\n\t/** Raw markdown. May be a partial chunk during streaming. */\n\tchildren: string;\n\tclassName?: string;\n}\n\n/**\n * Renders streaming-safe markdown.\n * @param props - children string + optional Streamdown overrides\n * @returns A Streamdown root scoped with prose styles\n */\nfunction Markdown({ children, className }: MarkdownProps) {\n\treturn (\n\t\t<Streamdown\n\t\t\tclassName={cn(\n\t\t\t\t\"prose prose-sm max-w-none text-foreground\",\n\t\t\t\t\"prose-headings:text-foreground prose-strong:text-foreground\",\n\t\t\t\t\"prose-a:text-primary prose-a:underline-offset-4 hover:prose-a:underline\",\n\t\t\t\t\"prose-code:text-foreground prose-code:before:content-none prose-code:after:content-none\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</Streamdown>\n\t);\n}\n\nexport { Markdown };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/inline-citation/inline-citation.tsx","../src/ai/reasoning/reasoning.tsx","../src/ai/citation/citation.tsx","../src/ai/sources/sources.tsx","../src/ai/tool-call/tool-call.tsx","../src/ai/markdown/close-unterminated.ts","../src/ai/markdown/remark-admonitions.ts","../src/ai/markdown/markdown.tsx"],"names":["jsxs","jsx","CollapsiblePrimitive2","Chevron","CollapsiblePrimitive3","Fragment"],"mappings":"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","file":"markdown.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as HoverCardPrimitive from \"@radix-ui/react-hover-card\";\nimport * as React from \"react\";\nimport { cn, safeUrl } from \"../../lib/utils.js\";\n\n/**\n * Inline footnote-style reference with a hover-preview popover.\n *\n * Pairs with `<Sources>` for the bottom-of-card list. Block-level\n * `<Citation>` chips are too large to embed mid-sentence; this primitive\n * fills the inline-text gap with a `<sup>[N]</sup>` and an\n * Anthropic-style hover preview showing the source title + URL.\n *\n * The Markdown component routes `[N](url)` shapes through this slot —\n * authors don't write the JSX directly in the streaming path.\n *\n * @example\n * The frontier models all publish reasoning evals\n * <InlineCitation index={1} title=\"Anthropic — Claude Sonnet 4.5\"\n * url=\"https://anthropic.com/claude\" />.\n */\nexport interface InlineCitationProps {\n\t/** Footnote number (1-based). Renders inside the visible `<sup>`. */\n\tindex: number;\n\t/** Source title shown in the hover preview. */\n\ttitle: string;\n\t/** Optional URL — when set, the trigger becomes a focusable anchor. */\n\turl?: string;\n\t/** Optional excerpt or context shown under the title in the preview. */\n\texcerpt?: string;\n\t/** Open delay in ms (matches Radix default ~700). */\n\topenDelay?: number;\n\tclassName?: string;\n}\n\n/**\n * Render an inline citation reference with hover preview.\n * @param props - Index, title, optional url + excerpt.\n * @returns A `<sup>` with a Radix HoverCard popover.\n */\nfunction InlineCitation({\n\tindex,\n\ttitle,\n\turl: rawUrl,\n\texcerpt,\n\topenDelay = 200,\n\tclassName,\n}: InlineCitationProps) {\n\t// Gate the URL against `javascript:` / `data:` / `vbscript:` schemes\n\t// before it reaches an `<a href>`. Markdown-path callers already pass\n\t// rehype-sanitized hrefs, but direct-JSX consumers can hand us anything.\n\tconst url = safeUrl(rawUrl);\n\tconst triggerClasses = cn(\n\t\t\"inline-flex select-none items-center justify-center rounded-sm bg-primary/10 px-1 py-0.5 text-[0.7em] font-mono font-semibold text-primary leading-none\",\n\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\"hover:bg-primary/15\",\n\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\",\n\t\tclassName,\n\t);\n\n\tconst trigger = url ? (\n\t\t<a\n\t\t\thref={url}\n\t\t\ttarget=\"_blank\"\n\t\t\trel=\"noreferrer noopener external\"\n\t\t\tclassName={triggerClasses}\n\t\t\taria-label={`Source ${index}: ${title}`}\n\t\t>\n\t\t\t[{index}]\n\t\t</a>\n\t) : (\n\t\t// No URL → still focusable so keyboard users can open the popover.\n\t\t// Real <button type=\"button\"> over a styled span so the trigger\n\t\t// honors space/enter activation natively.\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={triggerClasses}\n\t\t\taria-label={`Source ${index}: ${title}`}\n\t\t>\n\t\t\t[{index}]\n\t\t</button>\n\t);\n\n\treturn (\n\t\t<HoverCardPrimitive.Root openDelay={openDelay}>\n\t\t\t<HoverCardPrimitive.Trigger asChild>\n\t\t\t\t<sup className=\"inline-block leading-none\">{trigger}</sup>\n\t\t\t</HoverCardPrimitive.Trigger>\n\t\t\t<HoverCardPrimitive.Portal>\n\t\t\t\t<HoverCardPrimitive.Content\n\t\t\t\t\tside=\"top\"\n\t\t\t\t\talign=\"center\"\n\t\t\t\t\tsideOffset={4}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"z-50 max-w-xs rounded-md border border-border bg-popover p-3 text-popover-foreground shadow-md\",\n\t\t\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<div className=\"flex flex-col gap-1\">\n\t\t\t\t\t\t<span className=\"font-mono text-[10px] text-muted-foreground\">[{index}]</span>\n\t\t\t\t\t\t<span className=\"text-sm font-medium leading-snug text-foreground\">{title}</span>\n\t\t\t\t\t\t{excerpt ? (\n\t\t\t\t\t\t\t<span className=\"text-xs leading-relaxed text-muted-foreground\">{excerpt}</span>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t{url ? (\n\t\t\t\t\t\t\t<span className=\"truncate text-xs text-primary underline-offset-2 hover:underline\">\n\t\t\t\t\t\t\t\t{inferDisplayUrl(url)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t</HoverCardPrimitive.Content>\n\t\t\t</HoverCardPrimitive.Portal>\n\t\t</HoverCardPrimitive.Root>\n\t);\n}\n\nfunction inferDisplayUrl(href: string): string {\n\ttry {\n\t\tconst url = new URL(href);\n\t\treturn url.hostname.replace(/^www\\./, \"\") + url.pathname;\n\t} catch {\n\t\treturn href;\n\t}\n}\n\nexport { InlineCitation };\n","\"use client\";\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Collapsible \"thinking\" block. Designed for Anthropic-style reasoning\n * traces or Chain-of-Thought scratchpads — content the user can optionally\n * inspect without it dominating the response. Header shows a label and the\n * thinking duration if provided.\n *\n * Headless on content: pass any `children`. Pair with `Markdown` if the\n * reasoning is markdown-formatted.\n *\n * @example\n * <Reasoning durationMs={4200}>\n * <Markdown>{thinking}</Markdown>\n * </Reasoning>\n */\nexport interface ReasoningProps {\n\tchildren: React.ReactNode;\n\tdefaultOpen?: boolean;\n\t/** Time spent thinking, in milliseconds. Renders as \"Thought for 4.2s\". */\n\tdurationMs?: number;\n\t/** Override the default \"Thinking\" / \"Thought for X\" label. */\n\tlabel?: string;\n\tclassName?: string;\n}\n\n/**\n * Renders a collapsible thinking-trace block.\n * @param props - children + optional duration\n * @returns A Collapsible with a labelled header and content body\n */\nfunction Reasoning({\n\tchildren,\n\tdefaultOpen = false,\n\tdurationMs,\n\tlabel,\n\tclassName,\n}: ReasoningProps) {\n\tconst headerLabel =\n\t\tlabel ?? (typeof durationMs === \"number\" ? formatThoughtFor(durationMs) : \"Thinking\");\n\n\treturn (\n\t\t<CollapsiblePrimitive.Root\n\t\t\tdefaultOpen={defaultOpen}\n\t\t\tclassName={cn(\"overflow-hidden rounded-md border-l-2 border-foreground/15 bg-muted/20\", className)}\n\t\t>\n\t\t\t<CollapsiblePrimitive.Trigger\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"group flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-muted-foreground\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\"hover:text-foreground\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<SparkleGlyph />\n\t\t\t\t<span className=\"font-medium italic\">{headerLabel}</span>\n\t\t\t\t<Chevron />\n\t\t\t</CollapsiblePrimitive.Trigger>\n\t\t\t<CollapsiblePrimitive.Content className=\"overflow-hidden border-t border-foreground/[0.06] px-3 py-2 text-sm text-muted-foreground\">\n\t\t\t\t{children}\n\t\t\t</CollapsiblePrimitive.Content>\n\t\t</CollapsiblePrimitive.Root>\n\t);\n}\n\nfunction formatThoughtFor(ms: number): string {\n\tif (ms < 1000) return `Thought for ${ms}ms`;\n\tconst seconds = ms / 1000;\n\tconst formatted = seconds >= 10 ? Math.round(seconds).toString() : seconds.toFixed(1);\n\treturn `Thought for ${formatted}s`;\n}\n\nfunction SparkleGlyph() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"12\"\n\t\t\theight=\"12\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"shrink-0\"\n\t\t>\n\t\t\t<path d=\"M8 1.5l1.5 4 4 1.5-4 1.5L8 12.5 6.5 8.5l-4-1.5 4-1.5L8 1.5z\" />\n\t\t</svg>\n\t);\n}\n\nfunction Chevron() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"12\"\n\t\t\theight=\"12\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"ml-auto shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180\"\n\t\t>\n\t\t\t<path d=\"M4 6l4 4 4-4\" />\n\t\t</svg>\n\t);\n}\n\nexport { Reasoning };\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Source attribution chip — renders a citation for a RAG hit, search\n * result, or any external reference the assistant pulled from. Becomes a\n * clickable anchor when `url` is provided; otherwise a static span.\n *\n * @example\n * <Citation title=\"auth-overview.md\" url={src.url} page={3} />\n * @example\n * <Cluster gap=\"xs\">\n * {sources.map((s, i) => (\n * <Citation key={s.id} title={s.title} url={s.url} index={i + 1} />\n * ))}\n * </Cluster>\n */\nexport interface CitationProps {\n\ttitle: string;\n\turl?: string;\n\tpage?: number;\n\t/** Numeric index for inline footnote-style display (e.g. \"[1] auth.md\"). */\n\tindex?: number;\n\tclassName?: string;\n\tchildren?: React.ReactNode;\n}\n\n/**\n * Renders a source citation chip. Uses an `<a>` when `url` is set so the\n * chip is keyboard-focusable + opens in a new tab; falls back to a\n * non-interactive span otherwise.\n *\n * @param props - title + optional url, page, index\n * @returns An anchor or span styled as a chip\n */\nfunction Citation({ title, url, page, index, className, children }: CitationProps) {\n\tconst baseClasses = cn(\n\t\t\"inline-flex items-center gap-1.5 rounded-md border border-foreground/15 bg-card px-2 py-0.5 text-xs\",\n\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\tclassName,\n\t);\n\n\tconst body = (\n\t\t<>\n\t\t\t{typeof index === \"number\" ? (\n\t\t\t\t<span className=\"font-mono text-[10px] font-semibold text-muted-foreground\">[{index}]</span>\n\t\t\t) : (\n\t\t\t\t<DocGlyph />\n\t\t\t)}\n\t\t\t<span className=\"truncate text-foreground\">{title}</span>\n\t\t\t{typeof page === \"number\" ? (\n\t\t\t\t<span className=\"text-muted-foreground\">p.{page}</span>\n\t\t\t) : null}\n\t\t\t{children}\n\t\t</>\n\t);\n\n\tif (url) {\n\t\treturn (\n\t\t\t<a\n\t\t\t\thref={url}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\tbaseClasses,\n\t\t\t\t\t\"hover:border-foreground/30 hover:bg-secondary/40 hover:shadow-sm\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{body}\n\t\t\t</a>\n\t\t);\n\t}\n\n\treturn <span className={baseClasses}>{body}</span>;\n}\n\nfunction DocGlyph() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"11\"\n\t\t\theight=\"11\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"shrink-0 text-muted-foreground\"\n\t\t>\n\t\t\t<path d=\"M9 1.5H4.5A1.5 1.5 0 0 0 3 3v10a1.5 1.5 0 0 0 1.5 1.5h7A1.5 1.5 0 0 0 13 13V5.5L9 1.5z\" />\n\t\t\t<path d=\"M9 1.5V5.5h4\" />\n\t\t</svg>\n\t);\n}\n\nexport { Citation };\n","\"use client\";\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\nimport * as React from \"react\";\nimport { cn, safeUrl } from \"../../lib/utils.js\";\nimport { Citation } from \"../citation/citation.js\";\n\n/**\n * Bordered card listing 1–N citation chips for a RAG response.\n *\n * Header reads \"N sources\" and is a clickable Radix Collapsible trigger;\n * body renders one `<Citation>` per source (re-using the in-house chip).\n * Defaults to open so consumers don't have to expand to see what was\n * cited.\n *\n * @example\n * <Sources\n * sources={[\n * { title: \"Auth research\", url: \"https://example.com/auth\", page: 3 },\n * { title: \"OAuth 2.1 spec\", url: \"https://oauth.net/2.1\" },\n * ]}\n * />\n */\nexport interface SourcesProps {\n\t/** Citation rows. Each becomes a `<Citation>` chip. */\n\tsources: SourceRef[];\n\t/** Whether the list is expanded by default. */\n\tdefaultOpen?: boolean;\n\tclassName?: string;\n}\n\n/** Per-source data passed to a Citation chip. */\nexport interface SourceRef {\n\ttitle: string;\n\turl?: string;\n\tpage?: number;\n\t/** Optional 1-based index. Falls back to array position. Use to keep\n\t * the inline `<InlineCitation>` index aligned with the panel row when\n\t * the model emits non-1-based numbering. */\n\tindex?: number;\n}\n\n/**\n * Render a sources panel for an LLM response. Returns null when the\n * sources array is empty — consumers don't get a \"0 sources\" empty\n * card; they just don't render the panel at all.\n *\n * @param props - The list of sources + open-state default.\n * @returns A Collapsible wrapping a Citation cluster, or null if empty.\n */\nfunction Sources({ sources, defaultOpen = true, className }: SourcesProps) {\n\tif (sources.length === 0) return null;\n\tconst count = sources.length;\n\tconst headerLabel = count === 1 ? \"1 source\" : `${count} sources`;\n\n\treturn (\n\t\t<CollapsiblePrimitive.Root\n\t\t\tdefaultOpen={defaultOpen}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-hidden rounded-md border border-border bg-card text-card-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<CollapsiblePrimitive.Trigger\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"group flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-muted-foreground\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\"hover:text-foreground\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<DocStackGlyph />\n\t\t\t\t<span className=\"font-medium\">{headerLabel}</span>\n\t\t\t\t<Chevron />\n\t\t\t</CollapsiblePrimitive.Trigger>\n\t\t\t<CollapsiblePrimitive.Content className=\"overflow-hidden border-t border-foreground/[0.06]\">\n\t\t\t\t<div className=\"flex flex-wrap items-center gap-1.5 p-2\">\n\t\t\t\t\t{sources.map((s, i) => (\n\t\t\t\t\t\t<Citation\n\t\t\t\t\t\t\tkey={`${s.url ?? s.title}-${i}`}\n\t\t\t\t\t\t\ttitle={s.title}\n\t\t\t\t\t\t\t// Gate the URL even though markdown-path callers already\n\t\t\t\t\t\t\t// route through `safeUrl` — direct-JSX consumers can hand\n\t\t\t\t\t\t\t// us anything.\n\t\t\t\t\t\t\turl={safeUrl(s.url)}\n\t\t\t\t\t\t\tpage={s.page}\n\t\t\t\t\t\t\tindex={s.index ?? i + 1}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</CollapsiblePrimitive.Content>\n\t\t</CollapsiblePrimitive.Root>\n\t);\n}\n\nfunction DocStackGlyph() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"12\"\n\t\t\theight=\"12\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"shrink-0\"\n\t\t>\n\t\t\t<path d=\"M5 3h7l1.5 1.5V13H5V3z\" />\n\t\t\t<path d=\"M3 5v8.5L4.5 15H11\" />\n\t\t</svg>\n\t);\n}\n\nfunction Chevron() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"12\"\n\t\t\theight=\"12\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"ml-auto shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180\"\n\t\t>\n\t\t\t<path d=\"M4 6l4 4 4-4\" />\n\t\t</svg>\n\t);\n}\n\nexport { Sources };\n","\"use client\";\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport type { ToolCallState } from \"../types.js\";\n\nconst STATE_LABEL: Record<ToolCallState, string> = {\n\tpending: \"Pending\",\n\trunning: \"Running\",\n\tresult: \"Done\",\n\terror: \"Error\",\n};\n\nconst STATE_CLASSES: Record<ToolCallState, string> = {\n\tpending: \"bg-muted text-muted-foreground\",\n\t// `text-foreground` (12:1) survives axe's mid-pulse capture; the\n\t// previous `text-primary` (`#7081a8` on dark `--muted`, 4.28:1) was\n\t// intermittently flagged below AA 4.5:1 at the 10px badge size when\n\t// `animate-pulse` caught the scan during a low-opacity frame.\n\trunning: \"bg-muted text-foreground font-medium animate-pulse\",\n\tresult: \"bg-accent/30 text-accent-foreground\",\n\terror: \"bg-destructive/15 text-destructive\",\n};\n\n/**\n * Collapsible card displaying a tool / function invocation. Header shows the\n * tool name and lifecycle state badge; body reveals the JSON-stringified\n * arguments and result on expand.\n *\n * Display-only — the component does not run the tool. Wire it up in the\n * consumer (AI SDK `tool-*` parts → ToolCall props, LangChain\n * `AIMessage.tool_calls` → ToolCall props).\n *\n * @example\n * <ToolCall\n * name=\"searchDocs\"\n * state=\"result\"\n * args={{ query: \"auth\" }}\n * result={{ hits: 12 }}\n * />\n */\nexport interface ToolCallProps {\n\tname: string;\n\tstate: ToolCallState;\n\targs?: unknown;\n\tresult?: unknown;\n\tdefaultOpen?: boolean;\n\tclassName?: string;\n}\n\n/**\n * Renders a tool-invocation card with collapsible details.\n * @param props - tool name, state, optional args/result\n * @returns A Collapsible wrapping a header + JSON body\n */\nfunction ToolCall({\n\tname,\n\tstate,\n\targs,\n\tresult,\n\tdefaultOpen = false,\n\tclassName,\n}: ToolCallProps) {\n\treturn (\n\t\t<CollapsiblePrimitive.Root\n\t\t\tdefaultOpen={defaultOpen}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-hidden rounded-md border bg-card text-card-foreground\",\n\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\"data-[state=open]:shadow-sm\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<CollapsiblePrimitive.Trigger\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"group flex w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm\",\n\t\t\t\t\t\"hover:bg-muted/40\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<span className=\"flex min-w-0 items-center gap-2\">\n\t\t\t\t\t<ToolGlyph />\n\t\t\t\t\t<span className=\"truncate font-mono text-xs text-foreground\">{name}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium\",\n\t\t\t\t\t\t\tSTATE_CLASSES[state],\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{STATE_LABEL[state]}\n\t\t\t\t\t</span>\n\t\t\t\t</span>\n\t\t\t\t<Chevron />\n\t\t\t</CollapsiblePrimitive.Trigger>\n\t\t\t<CollapsiblePrimitive.Content className=\"overflow-hidden border-t bg-muted/20 px-3 py-2 text-xs\">\n\t\t\t\t{args !== undefined ? <CodeSection label=\"Arguments\" value={args} /> : null}\n\t\t\t\t{result !== undefined ? <CodeSection label=\"Result\" value={result} /> : null}\n\t\t\t\t{args === undefined && result === undefined ? (\n\t\t\t\t\t<p className=\"text-muted-foreground\">No arguments or result yet.</p>\n\t\t\t\t) : null}\n\t\t\t</CollapsiblePrimitive.Content>\n\t\t</CollapsiblePrimitive.Root>\n\t);\n}\n\nfunction CodeSection({ label, value }: { label: string; value: unknown }) {\n\tconst text = typeof value === \"string\" ? value : safeStringify(value);\n\treturn (\n\t\t<div className=\"space-y-1 py-1\">\n\t\t\t<div className=\"text-[10px] uppercase tracking-wide text-muted-foreground\">{label}</div>\n\t\t\t<pre className=\"overflow-x-auto rounded bg-background/60 p-2 font-mono text-[11px] leading-snug\">\n\t\t\t\t{text}\n\t\t\t</pre>\n\t\t</div>\n\t);\n}\n\nfunction safeStringify(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value, null, 2);\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n\nfunction ToolGlyph() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"14\"\n\t\t\theight=\"14\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"shrink-0 text-muted-foreground\"\n\t\t>\n\t\t\t<path d=\"M11.5 1.5l3 3-2.5 2.5-3-3 2.5-2.5z\" />\n\t\t\t<path d=\"M9 4l-7 7v3h3l7-7\" />\n\t\t</svg>\n\t);\n}\n\nfunction Chevron() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"14\"\n\t\t\theight=\"14\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"shrink-0 text-muted-foreground transition-transform duration-200 group-data-[state=open]:rotate-180\"\n\t\t>\n\t\t\t<path d=\"M4 6l4 4 4-4\" />\n\t\t</svg>\n\t);\n}\n\nexport { ToolCall };\n","/**\n * Streaming-safe markdown pre-processor. Detects unterminated tokens at\n * end-of-input and appends synthetic closers so `react-markdown`'s\n * parser doesn't render half-tokens as raw text or throw.\n *\n * Used by the `Markdown` component when consumers stream LLM output\n * one chunk at a time. Pure function — no I/O, no React, no plugins —\n * so it's trivially unit-testable as a truth table.\n *\n * Order matters. We close in this priority:\n * 1. Fenced code blocks (` ``` `) — most disruptive if open.\n * 2. HTML tags (`<tag` without `>`) — would consume rest of stream as attribute.\n * 3. Link parentheses (`[text](url`) — `react-markdown` falls back to text on these.\n * 4. Link brackets (`[text` no `]`) — consumes potentially huge bodies.\n * 5. Inline backticks (`` ` ``) — small but visible.\n * 6. Strikethrough (`~~`) — GFM extension.\n * 7. Bold (`**`) — must close before single `*` so we don't double-count.\n * 8. Italic (`*`, `_`) — last (most ambiguous).\n *\n * For tokens 5–8 we operate over a mask-view that replaces fenced\n * regions with whitespace of the same length, so an unclosed `**`\n * inside ` ``` ` doesn't trigger a closer.\n */\n\n/**\n * Pre-process raw markdown for the streaming-safe renderer.\n * @param input - Raw markdown string, possibly mid-stream.\n * @returns Input with synthetic closers appended for each open-at-EOF token.\n */\nexport function closeUnterminated(input: string): string {\n\tlet working = input;\n\tconst suffixes: string[] = [];\n\n\t// 1. Fenced code: count lines that are exactly ``` (allowing optional language tag on opener).\n\tif (hasUnclosedFence(working)) {\n\t\tsuffixes.push(\"\\n```\\n\");\n\t\t// Mask the open fence's content so steps 5–8 ignore it.\n\t\tworking = maskOpenFence(working);\n\t}\n\n\t// Mask all CLOSED fenced regions for step 5–8 — the content inside\n\t// closed fences is not subject to inline-token rules either. Then mask\n\t// CommonMark backslash-escapes (`\\*`, `` \\` ``, `\\_`, etc.) so the\n\t// inline counters don't treat escaped delimiters as openers.\n\tconst masked = maskEscapes(maskClosedFences(working));\n\n\t// 2a. HTML comment at any position with no `-->` close — the comment\n\t// would otherwise consume the rest of the stream as comment body.\n\tif (/<!--(?![\\s\\S]*-->)/.test(working)) {\n\t\tsuffixes.push(\"-->\");\n\t}\n\t// 2b. HTML tag at tail: `<tag` (with optional attrs) with no closing `>`.\n\t// Skipped if a `<!--` already triggered the comment closer above\n\t// (otherwise we'd add both `-->` and `>` for the same opener).\n\telse if (/<[a-zA-Z][^<>]*$/.test(working)) {\n\t\tsuffixes.push(\">\");\n\t}\n\n\t// 3 + 4. Link parens / brackets at tail.\n\t//\n\t// `[^[\\]]` instead of `[^\\]]` for the bracket-content character class:\n\t// excluding `[` AND `]` makes the engine reject mid-class on a nested\n\t// `[`, so input like `[[[[[…` runs in O(n) instead of O(n²) (CodeQL\n\t// flags the looser `[^\\]]*` form as polynomial). Same idea on the\n\t// paren clause: `[^()]` rejects nested `(` immediately.\n\tif (/\\[[^[\\]]*\\]\\([^()]*$/.test(working)) {\n\t\tsuffixes.push(\")\");\n\t} else if (/\\[[^[\\]]*$/.test(working)) {\n\t\tsuffixes.push(\"]\");\n\t}\n\n\t// 5. Inline backticks per line (in masked view, so fences excluded).\n\tlet backtickOdd = 0;\n\tfor (const line of masked.split(\"\\n\")) {\n\t\t// Only count single backticks — fenced code is masked out, but\n\t\t// a line like `` `foo` `bar` `` is two pairs (count 4 = even).\n\t\tconst count = (line.match(/`/g) ?? []).length;\n\t\tif (count % 2 === 1) backtickOdd++;\n\t}\n\tif (backtickOdd % 2 === 1) {\n\t\tsuffixes.push(\"`\");\n\t}\n\n\t// 6. Strikethrough — count `~~` markers (each pair brackets one\n\t// strikethrough span; an odd count means an opener with no closer).\n\tconst strikeMarkers = countOutsideMaskedFences(masked, /~~/g);\n\tif (strikeMarkers % 2 === 1) {\n\t\tsuffixes.push(\"~~\");\n\t}\n\n\t// 7. Bold. Walk the string and count `**` runs without consuming `***`\n\t// (which is bold + italic). A `**bold**` is two markers; `***both***`\n\t// is one `**` then one `*` then content then `*` then `**`.\n\tconst { boldOdd, italicAsteriskOdd } = countBoldItalic(masked);\n\tif (boldOdd) suffixes.push(\"**\");\n\t// 8. Italic. Asterisk first, then underscore.\n\tif (italicAsteriskOdd) suffixes.push(\"*\");\n\tif (countUnderscoreItalic(masked) % 2 === 1) suffixes.push(\"_\");\n\n\tif (suffixes.length === 0) return input;\n\treturn input + suffixes.join(\"\");\n}\n\n/**\n * A fence opener / closer is a line whose trim is exactly ``` or ```lang.\n * @param input - Raw markdown.\n * @returns True when there's an odd number of fence delimiter lines.\n */\nfunction hasUnclosedFence(input: string): boolean {\n\tconst fenceRe = /^[ \\t]*```/gm;\n\tconst matches = input.match(fenceRe);\n\treturn matches !== null && matches.length % 2 === 1;\n}\n\n/**\n * Replace the open fence (its opener line + everything after) with\n * whitespace of equal length. The opener line itself is included so its\n * fence delimiter doesn't show up in the inline-backtick / bold counts.\n * Inline tokens inside an open fence don't apply.\n * @param input - Raw markdown with a possibly-unclosed trailing fence.\n * @returns The same string with the open fence + content masked to spaces.\n */\nfunction maskOpenFence(input: string): string {\n\tconst fenceRe = /^[ \\t]*```/gm;\n\tconst matches: RegExpExecArray[] = [];\n\tlet m: RegExpExecArray | null;\n\t// biome-ignore lint/suspicious/noAssignInExpressions: standard regex iteration\n\twhile ((m = fenceRe.exec(input)) !== null) {\n\t\tmatches.push(m);\n\t}\n\tif (matches.length % 2 !== 1) return input;\n\tconst lastOpener = matches[matches.length - 1];\n\tif (!lastOpener) return input;\n\t// Mask from the start of the fence line (lastOpener.index points at\n\t// the first ``` char) through end-of-input, preserving newlines.\n\tconst start = lastOpener.index;\n\treturn input.slice(0, start) + input.slice(start).replace(/[^\\n]/g, \" \");\n}\n\n/**\n * Replace whole closed fence pairs (opener line + content + closer line)\n * with whitespace, keeping newlines. Both delimiter lines are masked so\n * the inline-token counters don't see their backtick characters.\n * @param input - Raw markdown.\n * @returns The same string with paired fences masked to whitespace.\n */\nfunction maskClosedFences(input: string): string {\n\tconst fenceRe = /^[ \\t]*```/gm;\n\tconst indices: number[] = [];\n\tlet m: RegExpExecArray | null;\n\t// biome-ignore lint/suspicious/noAssignInExpressions: standard regex iteration\n\twhile ((m = fenceRe.exec(input)) !== null) {\n\t\tindices.push(m.index);\n\t}\n\tlet out = input;\n\tconst pairCount = Math.floor(indices.length / 2);\n\tfor (let i = 0; i < pairCount; i++) {\n\t\tconst openIdx = indices[i * 2];\n\t\tconst closeIdx = indices[i * 2 + 1];\n\t\tif (openIdx === undefined || closeIdx === undefined) continue;\n\t\t// Mask from the opener-line start through the closer-line end so\n\t\t// no `` ``` `` survives in the masked view.\n\t\tconst closeEnd = out.indexOf(\"\\n\", closeIdx);\n\t\tconst regionEnd = closeEnd < 0 ? out.length : closeEnd;\n\t\tconst before = out.slice(0, openIdx);\n\t\tconst region = out.slice(openIdx, regionEnd).replace(/[^\\n]/g, \" \");\n\t\tconst after = out.slice(regionEnd);\n\t\tout = before + region + after;\n\t}\n\treturn out;\n}\n\n/**\n * Count regex matches over the masked view.\n * @param masked - Markdown with closed/open fences masked to whitespace.\n * @param re - Pattern to count occurrences of.\n * @returns The number of matches.\n */\nfunction countOutsideMaskedFences(masked: string, re: RegExp): number {\n\tconst matches = masked.match(re);\n\treturn matches?.length ?? 0;\n}\n\n/**\n * CommonMark-escapable characters. A backslash followed by any of these\n * produces the literal character in the rendered output and the\n * delimiter loses its syntactic role — so the inline counters must not\n * see it as a token opener.\n */\nconst ESCAPABLE = \"\\\\`*_~[](){}<>#+-.!|\";\n\n/**\n * Mask `\\<escapable>` pairs as two-space runs. Length-preserving so the\n * masked view stays index-compatible with the original input. `\\\\`\n * (literal backslash) consumes both backslashes; `\\n` (non-escapable\n * letter) is left intact.\n * @param input - The (already fence-masked) markdown view.\n * @returns The same view with escape sequences neutralized.\n */\nfunction maskEscapes(input: string): string {\n\tlet out = \"\";\n\tlet i = 0;\n\twhile (i < input.length) {\n\t\t// `?? \"\"` satisfies `noUncheckedIndexedAccess`; the bounds check\n\t\t// already proves `input[i + 1]` is a string.\n\t\tif (input[i] === \"\\\\\" && i + 1 < input.length && ESCAPABLE.includes(input[i + 1] ?? \"\")) {\n\t\t\tout += \" \";\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tout += input[i];\n\t\ti++;\n\t}\n\treturn out;\n}\n\n/**\n * Count bold (double-asterisk) and asterisk-italic (single-asterisk)\n * markers, accounting for triple-asterisk which counts as one bold plus\n * one italic. Returns parity flags so callers can decide closers.\n * @param masked - Markdown with fences masked to whitespace.\n * @returns Parity flags for bold and asterisk-italic markers.\n */\nfunction countBoldItalic(masked: string): { boldOdd: boolean; italicAsteriskOdd: boolean } {\n\t// Strip word-internal asterisks first (markdown ignores them) — be conservative.\n\tlet bold = 0;\n\tlet italic = 0;\n\tlet i = 0;\n\twhile (i < masked.length) {\n\t\tconst ch = masked[i];\n\t\tif (ch !== \"*\") {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\t// Count run length of consecutive `*`.\n\t\tlet run = 0;\n\t\twhile (i + run < masked.length && masked[i + run] === \"*\") run++;\n\t\t// Decompose: every pair is one `**`, leftover single is `*`.\n\t\tbold += Math.floor(run / 2);\n\t\titalic += run % 2;\n\t\ti += run;\n\t}\n\treturn { boldOdd: bold % 2 === 1, italicAsteriskOdd: italic % 2 === 1 };\n}\n\n/**\n * Count underscore italic markers. Markdown only treats `_foo_` as italic\n * when the underscores are at word boundaries — `foo_bar_baz` is plain\n * text. We approximate by only counting underscores where one side is\n * whitespace, line-start, or line-end.\n * @param masked - Markdown with fences masked to whitespace.\n * @returns The number of underscore markers eligible to act as italic.\n */\nfunction countUnderscoreItalic(masked: string): number {\n\tlet count = 0;\n\tfor (let i = 0; i < masked.length; i++) {\n\t\tif (masked[i] !== \"_\") continue;\n\t\tconst prev = i === 0 ? \" \" : masked[i - 1];\n\t\tconst next = i === masked.length - 1 ? \" \" : masked[i + 1];\n\t\tconst prevWs = prev === undefined || /[\\s]/.test(prev);\n\t\tconst nextWs = next === undefined || /[\\s]/.test(next);\n\t\tif (prevWs || nextWs) count++;\n\t}\n\treturn count;\n}\n","import type { Blockquote, Paragraph, Root, Text } from \"mdast\";\nimport { visit } from \"unist-util-visit\";\n\nconst SUPPORTED = new Set([\"think\"]);\n\n/**\n * Tag blockquotes that start with `[!think]` as admonitions of type\n * `think`. Strips the marker text from the rendered content and writes\n * the type onto `node.data.hProperties` so the rehype pass surfaces it\n * as a `data-admonition` attribute on the `<blockquote>` element. Slot\n * renderers in the React layer then route that attribute to\n * `<Reasoning>`.\n *\n * Pure transform; no I/O. Operates on the mdast tree before\n * `remark-rehype` produces hast.\n *\n * Only ships `[!think]` in Phase 2. Other admonitions\n * (`[!warn]`/`[!info]`/`[!error]`) can be added by extending the\n * `SUPPORTED` set without touching slot wiring.\n *\n * @returns A unified plugin transformer.\n */\nexport function remarkAdmonitions() {\n\treturn (tree: Root) => {\n\t\tvisit(tree, \"blockquote\", (node: Blockquote) => {\n\t\t\tconst marker = extractMarker(node);\n\t\t\tif (!marker || !SUPPORTED.has(marker.type)) return;\n\t\t\tstripMarkerText(node, marker.length);\n\t\t\tnode.data = node.data ?? {};\n\t\t\tnode.data.hProperties = {\n\t\t\t\t...(node.data.hProperties ?? {}),\n\t\t\t\tdataAdmonition: marker.type,\n\t\t\t};\n\t\t});\n\t};\n}\n\ninterface MarkerHit {\n\ttype: string;\n\t/** Number of characters to strip from the leading text node. */\n\tlength: number;\n}\n\n/**\n * Read the leading text of the first paragraph and detect a `[!type]`\n * marker. Returns null when the blockquote doesn't start with one.\n *\n * @param bq - The blockquote node to inspect.\n * @returns The matched admonition type + the marker length, or null.\n */\nfunction extractMarker(bq: Blockquote): MarkerHit | null {\n\tconst firstChild = bq.children[0];\n\tif (!firstChild || firstChild.type !== \"paragraph\") return null;\n\tconst firstText = firstChild.children[0];\n\tif (!firstText || firstText.type !== \"text\") return null;\n\tconst match = /^\\[!([a-z]+)\\]\\s*\\n?/.exec(firstText.value);\n\tif (!match) return null;\n\tconst type = match[1];\n\tif (!type) return null;\n\treturn { type, length: match[0].length };\n}\n\n/**\n * Remove the marker text from the leading text node so the rendered\n * blockquote shows only the body. If the text node becomes empty after\n * stripping, drop it.\n *\n * @param bq - The blockquote whose leading text needs trimming.\n * @param length - Number of characters to strip from the leading text.\n */\nfunction stripMarkerText(bq: Blockquote, length: number): void {\n\tconst firstChild: Paragraph | undefined = isParagraph(bq.children[0])\n\t\t? bq.children[0]\n\t\t: undefined;\n\tif (!firstChild) return;\n\tconst firstText: Text | undefined = isText(firstChild.children[0])\n\t\t? firstChild.children[0]\n\t\t: undefined;\n\tif (!firstText) return;\n\tconst stripped: Text = { ...firstText, value: firstText.value.slice(length) };\n\tif (stripped.value.length === 0) {\n\t\tfirstChild.children.shift();\n\t} else {\n\t\tfirstChild.children[0] = stripped;\n\t}\n}\n\nfunction isParagraph(node: Blockquote[\"children\"][number] | undefined): node is Paragraph {\n\treturn node?.type === \"paragraph\";\n}\n\nfunction isText(node: Paragraph[\"children\"][number] | undefined): node is Text {\n\treturn node?.type === \"text\";\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport ReactMarkdown from \"react-markdown\";\nimport rehypeRaw from \"rehype-raw\";\nimport rehypeSanitize, { defaultSchema } from \"rehype-sanitize\";\nimport remarkGfm from \"remark-gfm\";\nimport { InlineCitation } from \"../inline-citation/inline-citation.js\";\nimport { Reasoning } from \"../reasoning/reasoning.js\";\nimport { Sources, type SourceRef } from \"../sources/sources.js\";\nimport { ToolCall } from \"../tool-call/tool-call.js\";\nimport type { ToolCallState } from \"../types.js\";\nimport { cn, safeUrl } from \"../../lib/utils.js\";\nimport { closeUnterminated } from \"./close-unterminated.js\";\nimport { remarkAdmonitions } from \"./remark-admonitions.js\";\n\n/**\n * Streaming-safe markdown renderer with AI-aware element slots.\n *\n * Native pipeline (no `streamdown`): `react-markdown` + `remark-gfm`\n * for tables/task lists, `rehype-raw` to preserve the custom\n * `<tool-call>` element, `rehype-sanitize` to whitelist our slot tags,\n * `closeUnterminated` for streaming recovery (closes mid-stream `**`,\n * fences, links, tags before the parser sees them).\n *\n * Slot wiring:\n * - **Fenced code** (` ```lang `) → `<pre><code class=\"language-*\">` (client-safe; consumers post-highlight).\n * - **Footnote-style links** (`[1](url)`) → `<InlineCitation>` (inline `<sup>` with hover preview).\n * - **`<sources data='[…]' />`** → `<Sources>` (collapsible RAG-source list).\n * - **`<tool-call name=… state=… args=… result=…/>`** → `<ToolCall>`.\n * - **`> [!think]\\n> body`** blockquotes → `<Reasoning>`.\n *\n * The fenced-code slot doesn't route to the in-house `<CodeBlock>`\n * because CodeBlock is an async Server Component and Markdown runs\n * client-side. Consumers in an RSC tree can compose `<CodeBlock>`\n * directly when they need server-side Shiki highlighting.\n *\n * @example\n * <Message role=\"assistant\">\n * <Markdown>{streamingText}</Markdown>\n * </Message>\n */\nexport interface MarkdownProps {\n\t/** Raw markdown. May be a partial chunk during streaming. */\n\tchildren: string;\n\tclassName?: string;\n}\n\n// Allowlist for the AI-aware slot tags + attrs. `hast-util-sanitize`\n// normalizes element tag names to lowercase before lookup, so the\n// `tool-call` and `sources` keys are the literal kebab-case HTML tag\n// names. The `dataAdmonition` attribute key is the camelCase\n// hast-property name — it serializes to the kebab `data-admonition`\n// attribute on the rendered `<blockquote>`, which the\n// `ReasoningOrQuoteSlot` reads as `rest[\"data-admonition\"]`.\nconst SANITIZE_SCHEMA = {\n\t...defaultSchema,\n\ttagNames: [...(defaultSchema.tagNames ?? []), \"tool-call\", \"sources\"],\n\tattributes: {\n\t\t...(defaultSchema.attributes ?? {}),\n\t\t\"tool-call\": [\"name\", \"state\", \"args\", \"result\"],\n\t\tsources: [\"data\"],\n\t\tblockquote: [\n\t\t\t...((defaultSchema.attributes ?? {}).blockquote ?? []),\n\t\t\t\"dataAdmonition\",\n\t\t],\n\t},\n};\n\nconst COMPONENTS = {\n\tcode: CodeBlockSlot,\n\ta: CitationOrLinkSlot,\n\tblockquote: ReasoningOrQuoteSlot,\n\t\"tool-call\": ToolCallSlot,\n\tsources: SourcesSlot,\n} as const;\n\n/**\n * Render streaming-safe markdown with AI-aware slot wiring.\n *\n * @param props - The markdown source string + optional className.\n * @returns A `<div>` wrapping the rendered markdown tree.\n */\nfunction Markdown({ children, className }: MarkdownProps) {\n\tconst safe = React.useMemo(() => closeUnterminated(children), [children]);\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"prose prose-sm max-w-none text-foreground\",\n\t\t\t\t\"prose-headings:text-foreground prose-strong:text-foreground\",\n\t\t\t\t\"prose-a:text-primary prose-a:underline-offset-4 hover:prose-a:underline\",\n\t\t\t\t\"prose-code:text-foreground prose-code:before:content-none prose-code:after:content-none\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{/*\n\t\t\t * SECURITY INVARIANT: rehype-sanitize MUST follow rehype-raw.\n\t\t\t * Reordering re-opens raw <script>/<iframe>/event-handler\n\t\t\t * injection from any markdown source — including streamed model\n\t\t\t * output, where an attacker could prompt-inject arbitrary HTML.\n\t\t\t * The sanitize schema's `tagNames` allowlist is the only line\n\t\t\t * of defense once raw HTML is parsed.\n\t\t\t */}\n\t\t\t<ReactMarkdown\n\t\t\t\tremarkPlugins={[remarkGfm, remarkAdmonitions]}\n\t\t\t\trehypePlugins={[rehypeRaw, [rehypeSanitize, SANITIZE_SCHEMA]]}\n\t\t\t\tcomponents={COMPONENTS}\n\t\t\t>\n\t\t\t\t{safe}\n\t\t\t</ReactMarkdown>\n\t\t</div>\n\t);\n}\n\nexport { Markdown, closeUnterminated };\n\n// ─── Slot renderers ────────────────────────────────────────────────────\n//\n// Inlined into this file (rather than imported from a `slots/`\n// subdirectory) so the registry-build distribution path ships a single\n// self-contained `markdown.tsx`. The npm-published `@hex-core/components`\n// has tsup inline imports anyway; the CLI distribution path\n// (`npx hex add markdown`) only walks one file deep, so nested slots\n// would break consumer compiles.\n\n// In markdown, `[1](url)` parses as a link whose TEXT is \"1\" — the\n// brackets are syntax, not content. So a \"footnote-style\" link is one\n// whose visible text is a bare integer.\nconst FOOTNOTE_RE = /^(\\d+)$/;\n\ninterface CitationLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {\n\t/** Hast node passed by react-markdown@10 — destructured to keep it off the DOM. */\n\tnode?: unknown;\n}\n\n/**\n * `react-markdown` `a` renderer. Footnote-style numeric links become\n * `<InlineCitation>` (inline `<sup>` + hover preview); everything else\n * renders as a default link with prose styling.\n *\n * The block-level `<Citation>` chip is still importable separately —\n * use it inside a `<Sources>` panel where the chip-shaped UI fits, and\n * use this slot for inline mid-sentence references.\n *\n * @param props - Anchor attributes + react-markdown's hast `node` (dropped).\n * @returns Either an `<InlineCitation>` or an `<a>`.\n */\nfunction CitationOrLinkSlot({\n\thref,\n\tchildren,\n\tclassName,\n\tnode: _node,\n\t...rest\n}: CitationLinkProps) {\n\tconst text = extractText(children);\n\tconst footnote = FOOTNOTE_RE.exec(text);\n\tif (footnote && href) {\n\t\tconst index = Number(footnote[1]);\n\t\treturn <InlineCitation index={index} url={href} title={inferCitationTitle(href)} />;\n\t}\n\treturn (\n\t\t<a href={href} className={className} {...rest}>\n\t\t\t{children}\n\t\t</a>\n\t);\n}\n\n/**\n * Flatten a React-children value to a string for footnote-pattern\n * matching. Footnote links from `react-markdown` come through as a\n * single string child (`<a>1</a>`), so we only need string + array\n * unwrapping; nested elements correctly fall through to a default\n * `<a>` since their text doesn't match `^\\d+$` anyway.\n *\n * @param children - The link's React children.\n * @returns The flattened text content (empty for non-string trees).\n */\nfunction extractText(children: React.ReactNode): string {\n\tif (typeof children === \"string\") return children;\n\tif (Array.isArray(children)) return children.map(extractText).join(\"\");\n\treturn \"\";\n}\n\n/**\n * Pick a Citation title from the URL: hostname for absolute URLs,\n * the raw href for relative paths or anchors. Empty hostnames (e.g.\n * `mailto:foo@bar`) fall back to the href so the chip never renders\n * with an empty title.\n */\nfunction inferCitationTitle(href: string): string {\n\ttry {\n\t\tconst url = new URL(href);\n\t\tconst hostname = url.hostname.replace(/^www\\./, \"\");\n\t\treturn hostname.length > 0 ? hostname : href;\n\t} catch {\n\t\treturn href;\n\t}\n}\n\ninterface CodeBlockSlotProps extends React.HTMLAttributes<HTMLElement> {\n\t/** Hast node from react-markdown@10 — used to discriminate fenced vs inline. */\n\tnode?: unknown;\n}\n\n/**\n * `react-markdown` `code` renderer.\n *\n * - **Block (fenced):** renders `<code class=\"language-*\" data-fenced>`\n * inside a `<pre>` wrapper that react-markdown adds. We tag the\n * className so consumer-side highlighters can target it.\n * - **Inline:** plain `<code>` with token + muted-bg styling.\n *\n * Detects fenced via `language-*` className OR newline in children\n * (the parser only emits multi-line content for fenced blocks, never\n * for inline code). react-markdown@10 dropped the `inline` prop, so\n * we don't rely on it.\n *\n * @param props - HTML attributes + react-markdown's hast `node` (dropped).\n * @returns A `<code>` element.\n */\nfunction CodeBlockSlot({ className, children, node: _node, ...rest }: CodeBlockSlotProps) {\n\tconst langMatch = /language-([a-zA-Z0-9-]+)/.exec(className ?? \"\");\n\t// Fence detection. Prefer the className signal; fall back to the\n\t// children shape. `Array.isArray && length > 1` guards the case where\n\t// a downstream plugin replaces the string child with a React subtree\n\t// (then `String(children) === \"[object Object]\"` would falsely flip\n\t// fenced → inline).\n\tconst isFenced =\n\t\tBoolean(langMatch) ||\n\t\t(Array.isArray(children) && children.length > 1) ||\n\t\tString(children ?? \"\").includes(\"\\n\");\n\n\tif (!isFenced) {\n\t\treturn (\n\t\t\t<code\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"rounded bg-muted px-[0.3em] py-[0.15em] font-mono text-[0.85em]\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...rest}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</code>\n\t\t);\n\t}\n\n\treturn (\n\t\t<code\n\t\t\tclassName={cn(\"font-mono text-sm\", className)}\n\t\t\tdata-fenced=\"true\"\n\t\t\t{...rest}\n\t\t>\n\t\t\t{children}\n\t\t</code>\n\t);\n}\n\ninterface ReasoningSlotProps extends React.BlockquoteHTMLAttributes<HTMLQuoteElement> {\n\t\"data-admonition\"?: string;\n\t/** Hast node from react-markdown@10 — destructured to keep it off the DOM. */\n\tnode?: unknown;\n}\n\n/**\n * `react-markdown` `blockquote` renderer. Routes `[!think]` admonitions\n * to `<Reasoning>` (tagged via the `remarkAdmonitions` mdast plugin);\n * everything else renders as a styled blockquote.\n *\n * @param props - Blockquote attributes + react-markdown's hast `node` (dropped).\n * @returns Either a `<Reasoning>` or a default `<blockquote>`.\n */\nfunction ReasoningOrQuoteSlot({\n\tchildren,\n\tclassName,\n\tnode: _node,\n\t...rest\n}: ReasoningSlotProps) {\n\tif (rest[\"data-admonition\"] === \"think\") {\n\t\treturn <Reasoning>{children}</Reasoning>;\n\t}\n\treturn (\n\t\t<blockquote\n\t\t\tclassName={cn(\n\t\t\t\t\"my-4 border-l-2 border-border pl-4 italic text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...rest}\n\t\t>\n\t\t\t{children}\n\t\t</blockquote>\n\t);\n}\n\ninterface ToolCallAttrs {\n\tname?: string;\n\tstate?: string;\n\targs?: string;\n\tresult?: string;\n\tchildren?: React.ReactNode;\n\t/** Hast node from react-markdown@10 — destructured to keep it off the DOM. */\n\tnode?: unknown;\n}\n\nconst VALID_TOOL_CALL_STATES: Record<ToolCallState, true> = {\n\tpending: true,\n\trunning: true,\n\tresult: true,\n\terror: true,\n};\n\n/**\n * Renderer for the custom `<tool-call>` HTML tag (preserved by\n * `rehype-raw`, allowed in the sanitize schema). Reads `name`\n * (required), `state` (defaults to `result`), and JSON-stringified\n * `args` / `result` from the element attributes; renders `<ToolCall>`.\n * Falls back to passthrough if `name` is missing — keeps malformed\n * mid-stream fragments from crashing the render.\n *\n * @param props - Tool-call attributes + hast `node` (dropped).\n * @returns A `<ToolCall>` or a Fragment passthrough.\n */\nfunction ToolCallSlot({ name, state, args, result, children, node: _node }: ToolCallAttrs) {\n\tif (!name) return <>{children}</>;\n\tconst parsedState: ToolCallState = isToolCallState(state) ? state : \"result\";\n\treturn (\n\t\t<ToolCall\n\t\t\tname={name}\n\t\t\tstate={parsedState}\n\t\t\targs={parseJson(args)}\n\t\t\tresult={parseJson(result)}\n\t\t/>\n\t);\n}\n\nfunction isToolCallState(value: unknown): value is ToolCallState {\n\treturn typeof value === \"string\" && value in VALID_TOOL_CALL_STATES;\n}\n\nfunction parseJson(raw: string | undefined): unknown {\n\tif (raw === undefined || raw === \"\") return undefined;\n\ttry {\n\t\treturn JSON.parse(raw);\n\t} catch {\n\t\treturn raw;\n\t}\n}\n\ninterface SourcesSlotAttrs {\n\t/** JSON-stringified `SourceRef[]`. Parsed lazily. */\n\tdata?: string;\n\tchildren?: React.ReactNode;\n\t/** Hast node from react-markdown@10 — destructured to keep it off the DOM. */\n\tnode?: unknown;\n}\n\n/**\n * Renderer for the custom `<sources>` HTML tag (preserved by\n * `rehype-raw`, allowed in the sanitize schema).\n *\n * Reads a JSON-stringified `data` attribute holding a `SourceRef[]`\n * and renders `<Sources>`. Bad JSON, missing data, or a non-array\n * payload all fall through to a Fragment passthrough — keeps malformed\n * mid-stream fragments from crashing the render.\n *\n * @param props - The serialized `data` attribute + hast `node` (dropped).\n * @returns A `<Sources>` panel or a Fragment passthrough.\n */\nfunction SourcesSlot({ data, children, node: _node }: SourcesSlotAttrs) {\n\t// Memoize the parse pass — every Markdown re-render (each streaming\n\t// token!) would otherwise re-parse the (potentially large) JSON\n\t// payload from scratch. Same pattern as `closeUnterminated` upstream.\n\tconst sources = React.useMemo(() => parseSources(data), [data]);\n\tif (!sources) return <>{children}</>;\n\treturn <Sources sources={sources} />;\n}\n\nfunction parseSources(raw: string | undefined): SourceRef[] | null {\n\tif (raw === undefined || raw === \"\") return null;\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (!Array.isArray(parsed)) return null;\n\tconst result: SourceRef[] = [];\n\tfor (const item of parsed) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\t// `in`-narrowing keeps each property access typed as `unknown`,\n\t\t// so the typeof guards below narrow without an `as` cast.\n\t\tif (!(\"title\" in item) || typeof item.title !== \"string\") continue;\n\t\tconst ref: SourceRef = { title: item.title };\n\t\tif (\"url\" in item && typeof item.url === \"string\") {\n\t\t\tconst url = safeUrl(item.url);\n\t\t\tif (url !== undefined) ref.url = url;\n\t\t}\n\t\tif (\"page\" in item && typeof item.page === \"number\") ref.page = item.page;\n\t\tif (\"index\" in item && typeof item.index === \"number\") ref.index = item.index;\n\t\tresult.push(ref);\n\t}\n\treturn result;\n}\n"]}
|
package/dist/matrix.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/matrix/matrix.tsx"],"names":[],"mappings":"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","file":"matrix.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Adjacency-matrix diagram. Square grid where cell (row i, col j)\n * encodes the relationship from node i to node j by color intensity.\n * Pure SVG; no heavy peer dependency. Best for dense graphs where\n * node-link diagrams turn into \"hairballs\" — Matrix scales gracefully\n * to hundreds of nodes if the SVG is sized to match.\n *\n * @example\n * <Matrix\n * nodes={[\"A\", \"B\", \"C\", \"D\"].map((id) => ({ id, label: id }))}\n * matrix={[\n * [0, 5, 8, 1],\n * [3, 0, 2, 4],\n * [6, 0, 0, 7],\n * [2, 1, 9, 0],\n * ]}\n * />\n */\nexport type MatrixNode = {\n\tid: string;\n\tlabel: string;\n};\n\nexport interface MatrixProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n\t/** Nodes — rows AND columns. Order matches `matrix` rows/columns. */\n\tnodes: MatrixNode[];\n\t/** Square N×N matrix of values. matrix[i][j] = relationship from node i to node j. */\n\tmatrix: number[][];\n\t/** Pixel size of the rendered SVG (it's square). Default 480. */\n\tsize?: number;\n\t/** Pixel reserved for row/column labels along the edges. Default 80. */\n\tlabelMargin?: number;\n\t/** Show numeric values inside cells when the cell is large enough. Default true. */\n\tshowValues?: boolean;\n\t/** Fired when a cell is hovered (or hover ends, with `null`). */\n\tonCellHover?: (cell: { row: MatrixNode; col: MatrixNode; value: number } | null) => void;\n\t/** Fired when a cell is clicked. */\n\tonCellClick?: (cell: { row: MatrixNode; col: MatrixNode; value: number }) => void;\n}\n\ninterface LaidOutCell {\n\trow: MatrixNode;\n\tcol: MatrixNode;\n\trowIndex: number;\n\tcolIndex: number;\n\tvalue: number;\n\tx: number;\n\ty: number;\n\tintensity: number;\n}\n\n/** Below this px size, in-cell numeric labels become unreadable and are hidden. */\nconst MIN_CELL_SIZE_FOR_VALUE = 28;\n\nfunction Matrix({\n\tnodes,\n\tmatrix,\n\tsize = 480,\n\tlabelMargin = 80,\n\tshowValues = true,\n\tonCellHover,\n\tonCellClick,\n\tclassName,\n\t...rest\n}: MatrixProps) {\n\tconst cells = React.useMemo(() => layout(nodes, matrix, size, labelMargin), [nodes, matrix, size, labelMargin]);\n\tconst desc = `Matrix with ${nodes.length} node${nodes.length === 1 ? \"\" : \"s\"} (${nodes.length}×${nodes.length} cells)`;\n\tconst cellSize = nodes.length > 0 ? (size - labelMargin) / nodes.length : 0;\n\n\treturn (\n\t\t<svg\n\t\t\t{...rest}\n\t\t\tdata-hex-matrix\n\t\t\trole=\"img\"\n\t\t\twidth={size}\n\t\t\theight={size}\n\t\t\tviewBox={`0 0 ${size} ${size}`}\n\t\t\tclassName={cn(\"block\", className)}\n\t\t>\n\t\t\t<title>Adjacency matrix</title>\n\t\t\t<desc>{desc}</desc>\n\t\t\t<g data-hex-matrix-rows>\n\t\t\t\t{nodes.map((n, i) => (\n\t\t\t\t\t<text\n\t\t\t\t\t\tkey={`row-${n.id}`}\n\t\t\t\t\t\tx={labelMargin - 4}\n\t\t\t\t\t\ty={labelMargin + cellSize * i + cellSize / 2}\n\t\t\t\t\t\tdy=\"0.35em\"\n\t\t\t\t\t\ttextAnchor=\"end\"\n\t\t\t\t\t\tfontSize={10}\n\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{n.label}\n\t\t\t\t\t</text>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t<g data-hex-matrix-cols>\n\t\t\t\t{nodes.map((n, i) => (\n\t\t\t\t\t<text\n\t\t\t\t\t\tkey={`col-${n.id}`}\n\t\t\t\t\t\tx={labelMargin + cellSize * i + cellSize / 2}\n\t\t\t\t\t\ty={labelMargin - 4}\n\t\t\t\t\t\ttextAnchor=\"end\"\n\t\t\t\t\t\tfontSize={10}\n\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\ttransform={`rotate(-45 ${labelMargin + cellSize * i + cellSize / 2} ${labelMargin - 4})`}\n\t\t\t\t\t>\n\t\t\t\t\t\t{n.label}\n\t\t\t\t\t</text>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t<g data-hex-matrix-cells>\n\t\t\t\t{cells.map((c) => {\n\t\t\t\t\tconst interactive = Boolean(onCellHover || onCellClick);\n\t\t\t\t\tconst cellPayload = { row: c.row, col: c.col, value: c.value };\n\t\t\t\t\tconst fireHover = (cell: typeof cellPayload | null) => onCellHover?.(cell);\n\t\t\t\t\tconst handleActivate = () => onCellClick?.(cellPayload);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<g\n\t\t\t\t\t\t\tkey={`${c.rowIndex}-${c.colIndex}`}\n\t\t\t\t\t\t\tdata-hex-matrix-cell\n\t\t\t\t\t\t\tdata-row={c.rowIndex}\n\t\t\t\t\t\t\tdata-col={c.colIndex}\n\t\t\t\t\t\t\trole={interactive ? \"button\" : undefined}\n\t\t\t\t\t\t\ttabIndex={interactive ? 0 : undefined}\n\t\t\t\t\t\t\taria-label={interactive ? `${c.row.label} → ${c.col.label}: ${c.value}` : undefined}\n\t\t\t\t\t\t\tstyle={interactive ? { cursor: \"pointer\" } : undefined}\n\t\t\t\t\t\t\tonMouseEnter={onCellHover ? () => fireHover(cellPayload) : undefined}\n\t\t\t\t\t\t\tonMouseLeave={onCellHover ? () => fireHover(null) : undefined}\n\t\t\t\t\t\t\tonFocus={onCellHover ? () => fireHover(cellPayload) : undefined}\n\t\t\t\t\t\t\tonBlur={onCellHover ? () => fireHover(null) : undefined}\n\t\t\t\t\t\t\tonClick={onCellClick ? handleActivate : undefined}\n\t\t\t\t\t\t\tonKeyDown={onCellClick ? (e) => activateOnKey(e, handleActivate) : undefined}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t\tx={c.x}\n\t\t\t\t\t\t\t\ty={c.y}\n\t\t\t\t\t\t\t\twidth={cellSize}\n\t\t\t\t\t\t\t\theight={cellSize}\n\t\t\t\t\t\t\t\t// Floor at 0.08 so empty cells are visible as grid lines;\n\t\t\t\t\t\t\t\t// ramp up to 0.95 for max-value cells. `--chart-1` carries\n\t\t\t\t\t\t\t\t// the hue, opacity carries the magnitude. Falls back to\n\t\t\t\t\t\t\t\t// `--primary` for consumers whose theme presets predate\n\t\t\t\t\t\t\t\t// the chart token family.\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--chart-1, var(--primary)))\"\n\t\t\t\t\t\t\t\tfillOpacity={0.08 + 0.87 * c.intensity}\n\t\t\t\t\t\t\t\tstroke=\"hsl(var(--background))\"\n\t\t\t\t\t\t\t\tstrokeWidth={0.5}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t{showValues && cellSize > MIN_CELL_SIZE_FOR_VALUE && c.value !== 0 ? (\n\t\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\t\tx={c.x + cellSize / 2}\n\t\t\t\t\t\t\t\t\ty={c.y + cellSize / 2}\n\t\t\t\t\t\t\t\t\tdy=\"0.35em\"\n\t\t\t\t\t\t\t\t\ttextAnchor=\"middle\"\n\t\t\t\t\t\t\t\t\tfontSize={9}\n\t\t\t\t\t\t\t\t\t// Above ~0.55 intensity the cell is dark enough that\n\t\t\t\t\t\t\t\t\t// background-tone foreground reads better.\n\t\t\t\t\t\t\t\t\tfill={c.intensity > 0.55 ? \"hsl(var(--background))\" : \"hsl(var(--foreground))\"}\n\t\t\t\t\t\t\t\t\tstyle={{ pointerEvents: \"none\" }}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{c.value}\n\t\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</g>\n\t\t</svg>\n\t);\n}\n\nfunction layout(\n\tnodes: MatrixNode[],\n\tmatrix: number[][],\n\tsize: number,\n\tlabelMargin: number,\n): LaidOutCell[] {\n\tif (nodes.length === 0) return [];\n\tconst cellSize = (size - labelMargin) / nodes.length;\n\tlet maxValue = 0;\n\tfor (const row of matrix) {\n\t\tfor (const v of row) if (v > maxValue) maxValue = v;\n\t}\n\tconst cells: LaidOutCell[] = [];\n\tfor (let i = 0; i < nodes.length; i++) {\n\t\tfor (let j = 0; j < nodes.length; j++) {\n\t\t\tconst value = matrix[i]?.[j] ?? 0;\n\t\t\tcells.push({\n\t\t\t\trow: nodes[i],\n\t\t\t\tcol: nodes[j],\n\t\t\t\trowIndex: i,\n\t\t\t\tcolIndex: j,\n\t\t\t\tvalue,\n\t\t\t\tx: labelMargin + cellSize * j,\n\t\t\t\ty: labelMargin + cellSize * i,\n\t\t\t\tintensity: maxValue > 0 ? value / maxValue : 0,\n\t\t\t});\n\t\t}\n\t}\n\treturn cells;\n}\n\nfunction activateOnKey(e: React.KeyboardEvent, fn: () => void): void {\n\tif (e.key === \"Enter\" || e.key === \" \") {\n\t\te.preventDefault();\n\t\tfn();\n\t}\n}\n\nexport { Matrix };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/matrix/matrix.tsx"],"names":[],"mappings":"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","file":"matrix.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Adjacency-matrix diagram. Square grid where cell (row i, col j)\n * encodes the relationship from node i to node j by color intensity.\n * Pure SVG; no heavy peer dependency. Best for dense graphs where\n * node-link diagrams turn into \"hairballs\" — Matrix scales gracefully\n * to hundreds of nodes if the SVG is sized to match.\n *\n * @example\n * <Matrix\n * nodes={[\"A\", \"B\", \"C\", \"D\"].map((id) => ({ id, label: id }))}\n * matrix={[\n * [0, 5, 8, 1],\n * [3, 0, 2, 4],\n * [6, 0, 0, 7],\n * [2, 1, 9, 0],\n * ]}\n * />\n */\nexport type MatrixNode = {\n\tid: string;\n\tlabel: string;\n};\n\nexport interface MatrixProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n\t/** Nodes — rows AND columns. Order matches `matrix` rows/columns. */\n\tnodes: MatrixNode[];\n\t/** Square N×N matrix of values. matrix[i][j] = relationship from node i to node j. */\n\tmatrix: number[][];\n\t/** Pixel size of the rendered SVG (it's square). Default 480. */\n\tsize?: number;\n\t/** Pixel reserved for row/column labels along the edges. Default 80. */\n\tlabelMargin?: number;\n\t/** Show numeric values inside cells when the cell is large enough. Default true. */\n\tshowValues?: boolean;\n\t/** Fired when a cell is hovered (or hover ends, with `null`). */\n\tonCellHover?: (cell: { row: MatrixNode; col: MatrixNode; value: number } | null) => void;\n\t/** Fired when a cell is clicked. */\n\tonCellClick?: (cell: { row: MatrixNode; col: MatrixNode; value: number }) => void;\n}\n\ninterface LaidOutCell {\n\trow: MatrixNode;\n\tcol: MatrixNode;\n\trowIndex: number;\n\tcolIndex: number;\n\tvalue: number;\n\tx: number;\n\ty: number;\n\tintensity: number;\n}\n\n/** Below this px size, in-cell numeric labels become unreadable and are hidden. */\nconst MIN_CELL_SIZE_FOR_VALUE = 28;\n\nfunction Matrix({\n\tnodes,\n\tmatrix,\n\tsize = 480,\n\tlabelMargin = 80,\n\tshowValues = true,\n\tonCellHover,\n\tonCellClick,\n\tclassName,\n\t...rest\n}: MatrixProps) {\n\tconst cells = React.useMemo(() => layout(nodes, matrix, size, labelMargin), [nodes, matrix, size, labelMargin]);\n\tconst desc = `Matrix with ${nodes.length} node${nodes.length === 1 ? \"\" : \"s\"} (${nodes.length}×${nodes.length} cells)`;\n\tconst cellSize = nodes.length > 0 ? (size - labelMargin) / nodes.length : 0;\n\n\treturn (\n\t\t<svg\n\t\t\t{...rest}\n\t\t\tdata-hex-matrix\n\t\t\trole=\"img\"\n\t\t\twidth={size}\n\t\t\theight={size}\n\t\t\tviewBox={`0 0 ${size} ${size}`}\n\t\t\tclassName={cn(\"block\", className)}\n\t\t>\n\t\t\t<title>Adjacency matrix</title>\n\t\t\t<desc>{desc}</desc>\n\t\t\t<g data-hex-matrix-rows>\n\t\t\t\t{nodes.map((n, i) => (\n\t\t\t\t\t<text\n\t\t\t\t\t\tkey={`row-${n.id}`}\n\t\t\t\t\t\tx={labelMargin - 4}\n\t\t\t\t\t\ty={labelMargin + cellSize * i + cellSize / 2}\n\t\t\t\t\t\tdy=\"0.35em\"\n\t\t\t\t\t\ttextAnchor=\"end\"\n\t\t\t\t\t\tfontSize={10}\n\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{n.label}\n\t\t\t\t\t</text>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t<g data-hex-matrix-cols>\n\t\t\t\t{nodes.map((n, i) => (\n\t\t\t\t\t<text\n\t\t\t\t\t\tkey={`col-${n.id}`}\n\t\t\t\t\t\tx={labelMargin + cellSize * i + cellSize / 2}\n\t\t\t\t\t\ty={labelMargin - 4}\n\t\t\t\t\t\ttextAnchor=\"end\"\n\t\t\t\t\t\tfontSize={10}\n\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\ttransform={`rotate(-45 ${labelMargin + cellSize * i + cellSize / 2} ${labelMargin - 4})`}\n\t\t\t\t\t>\n\t\t\t\t\t\t{n.label}\n\t\t\t\t\t</text>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t<g data-hex-matrix-cells>\n\t\t\t\t{cells.map((c) => {\n\t\t\t\t\tconst interactive = Boolean(onCellHover || onCellClick);\n\t\t\t\t\tconst cellPayload = { row: c.row, col: c.col, value: c.value };\n\t\t\t\t\tconst fireHover = (cell: typeof cellPayload | null) => onCellHover?.(cell);\n\t\t\t\t\tconst handleActivate = () => onCellClick?.(cellPayload);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<g\n\t\t\t\t\t\t\tkey={`${c.rowIndex}-${c.colIndex}`}\n\t\t\t\t\t\t\tdata-hex-matrix-cell\n\t\t\t\t\t\t\tdata-row={c.rowIndex}\n\t\t\t\t\t\t\tdata-col={c.colIndex}\n\t\t\t\t\t\t\trole={interactive ? \"button\" : undefined}\n\t\t\t\t\t\t\ttabIndex={interactive ? 0 : undefined}\n\t\t\t\t\t\t\taria-label={interactive ? `${c.row.label} → ${c.col.label}: ${c.value}` : undefined}\n\t\t\t\t\t\t\tstyle={interactive ? { cursor: \"pointer\" } : undefined}\n\t\t\t\t\t\t\tonMouseEnter={onCellHover ? () => fireHover(cellPayload) : undefined}\n\t\t\t\t\t\t\tonMouseLeave={onCellHover ? () => fireHover(null) : undefined}\n\t\t\t\t\t\t\tonFocus={onCellHover ? () => fireHover(cellPayload) : undefined}\n\t\t\t\t\t\t\tonBlur={onCellHover ? () => fireHover(null) : undefined}\n\t\t\t\t\t\t\tonClick={onCellClick ? handleActivate : undefined}\n\t\t\t\t\t\t\tonKeyDown={onCellClick ? (e) => activateOnKey(e, handleActivate) : undefined}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t\tx={c.x}\n\t\t\t\t\t\t\t\ty={c.y}\n\t\t\t\t\t\t\t\twidth={cellSize}\n\t\t\t\t\t\t\t\theight={cellSize}\n\t\t\t\t\t\t\t\t// Floor at 0.08 so empty cells are visible as grid lines;\n\t\t\t\t\t\t\t\t// ramp up to 0.95 for max-value cells. `--chart-1` carries\n\t\t\t\t\t\t\t\t// the hue, opacity carries the magnitude. Falls back to\n\t\t\t\t\t\t\t\t// `--primary` for consumers whose theme presets predate\n\t\t\t\t\t\t\t\t// the chart token family.\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--chart-1, var(--primary)))\"\n\t\t\t\t\t\t\t\tfillOpacity={0.08 + 0.87 * c.intensity}\n\t\t\t\t\t\t\t\tstroke=\"hsl(var(--background))\"\n\t\t\t\t\t\t\t\tstrokeWidth={0.5}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t{showValues && cellSize > MIN_CELL_SIZE_FOR_VALUE && c.value !== 0 ? (\n\t\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\t\tx={c.x + cellSize / 2}\n\t\t\t\t\t\t\t\t\ty={c.y + cellSize / 2}\n\t\t\t\t\t\t\t\t\tdy=\"0.35em\"\n\t\t\t\t\t\t\t\t\ttextAnchor=\"middle\"\n\t\t\t\t\t\t\t\t\tfontSize={9}\n\t\t\t\t\t\t\t\t\t// Above ~0.55 intensity the cell is dark enough that\n\t\t\t\t\t\t\t\t\t// background-tone foreground reads better.\n\t\t\t\t\t\t\t\t\tfill={c.intensity > 0.55 ? \"hsl(var(--background))\" : \"hsl(var(--foreground))\"}\n\t\t\t\t\t\t\t\t\tstyle={{ pointerEvents: \"none\" }}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{c.value}\n\t\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</g>\n\t\t</svg>\n\t);\n}\n\nfunction layout(\n\tnodes: MatrixNode[],\n\tmatrix: number[][],\n\tsize: number,\n\tlabelMargin: number,\n): LaidOutCell[] {\n\tif (nodes.length === 0) return [];\n\tconst cellSize = (size - labelMargin) / nodes.length;\n\tlet maxValue = 0;\n\tfor (const row of matrix) {\n\t\tfor (const v of row) if (v > maxValue) maxValue = v;\n\t}\n\tconst cells: LaidOutCell[] = [];\n\tfor (let i = 0; i < nodes.length; i++) {\n\t\tfor (let j = 0; j < nodes.length; j++) {\n\t\t\tconst value = matrix[i]?.[j] ?? 0;\n\t\t\tcells.push({\n\t\t\t\trow: nodes[i],\n\t\t\t\tcol: nodes[j],\n\t\t\t\trowIndex: i,\n\t\t\t\tcolIndex: j,\n\t\t\t\tvalue,\n\t\t\t\tx: labelMargin + cellSize * j,\n\t\t\t\ty: labelMargin + cellSize * i,\n\t\t\t\tintensity: maxValue > 0 ? value / maxValue : 0,\n\t\t\t});\n\t\t}\n\t}\n\treturn cells;\n}\n\nfunction activateOnKey(e: React.KeyboardEvent, fn: () => void): void {\n\tif (e.key === \"Enter\" || e.key === \" \") {\n\t\te.preventDefault();\n\t\tfn();\n\t}\n}\n\nexport { Matrix };\n"]}
|
package/dist/menubar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/menubar/menubar.tsx"],"names":[],"mappings":"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","file":"menubar.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as MenubarPrimitive from \"@radix-ui/react-menubar\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Top-level menu bar (File / Edit / View style). */\nconst Menubar = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Root>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>\n>(({ className, ...props }, ref) => (\n\t<MenubarPrimitive.Root\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex h-[var(--control-height-md,2.5rem)] items-center space-x-1 rounded-md border border-foreground/[0.08] bg-background p-[var(--space-1,0.25rem)]\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nMenubar.displayName = \"Menubar\";\n\n// The explicit `as typeof ...Primitive.X` casts below are load-bearing: without them,\n// tsup's dts build fails with TS2742 \"The inferred type of X cannot be named without a\n// reference to @radix-ui/react-context\" on direct re-exports of Radix primitives. Do not\n// remove without verifying `pnpm --filter @hex-core/components build` still succeeds.\n\n/** A top-level menu in the bar (e.g. \"File\"). */\nconst MenubarMenu = MenubarPrimitive.Menu as typeof MenubarPrimitive.Menu;\n\n/** Groups related items inside a menu content. */\nconst MenubarGroup = MenubarPrimitive.Group as typeof MenubarPrimitive.Group;\n\n/** Portals menu content into the body. */\nconst MenubarPortal = MenubarPrimitive.Portal as typeof MenubarPrimitive.Portal;\n\n/** Group for checkable radio items. */\nconst MenubarRadioGroup = MenubarPrimitive.RadioGroup as typeof MenubarPrimitive.RadioGroup;\n\n/** The clickable menu label in the bar. */\nconst MenubarTrigger = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Trigger>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n\t<MenubarPrimitive.Trigger\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex cursor-default select-none items-center rounded-sm px-[var(--space-3,0.75rem)] py-1.5 text-sm font-medium outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nMenubarTrigger.displayName = \"MenubarTrigger\";\n\n/** The menu panel shown when a trigger opens. */\nconst MenubarContent = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>\n>(({ className, align = \"start\", alignOffset = -4, sideOffset = 8, ...props }, ref) => (\n\t<MenubarPrimitive.Portal>\n\t\t<MenubarPrimitive.Content\n\t\t\tref={ref}\n\t\t\talign={align}\n\t\t\talignOffset={alignOffset}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 min-w-[12rem] overflow-hidden rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-1,0.25rem)] text-popover-foreground shadow-md\",\n\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</MenubarPrimitive.Portal>\n));\nMenubarContent.displayName = \"MenubarContent\";\n\n/** A clickable menu item. */\nconst MenubarItem = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<MenubarPrimitive.Item\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center gap-[var(--gap-sm,0.5rem)] rounded-sm px-[var(--space-2,0.5rem)] py-1.5 text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tinset && \"pl-[var(--space-8,2rem)]\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nMenubarItem.displayName = \"MenubarItem\";\n\n/** A non-interactive heading label. */\nconst MenubarLabel = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Label>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<MenubarPrimitive.Label\n\t\tref={ref}\n\t\tclassName={cn(\"px-[var(--space-2,0.5rem)] py-1.5 text-sm font-semibold\", inset && \"pl-[var(--space-8,2rem)]\", className)}\n\t\t{...props}\n\t/>\n));\nMenubarLabel.displayName = \"MenubarLabel\";\n\n/** Horizontal divider. */\nconst MenubarSeparator = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Separator>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n\t<MenubarPrimitive.Separator\n\t\tref={ref}\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] my-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nMenubarSeparator.displayName = \"MenubarSeparator\";\n\n/**\n * Right-aligned keyboard shortcut text.\n * @returns A span with muted typography\n */\nfunction MenubarShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport {\n\tMenubar,\n\tMenubarMenu,\n\tMenubarTrigger,\n\tMenubarContent,\n\tMenubarItem,\n\tMenubarLabel,\n\tMenubarSeparator,\n\tMenubarShortcut,\n\tMenubarGroup,\n\tMenubarPortal,\n\tMenubarRadioGroup,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/menubar/menubar.tsx"],"names":[],"mappings":"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","file":"menubar.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as MenubarPrimitive from \"@radix-ui/react-menubar\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Top-level menu bar (File / Edit / View style). */\nconst Menubar = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Root>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>\n>(({ className, ...props }, ref) => (\n\t<MenubarPrimitive.Root\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex h-[var(--control-height-md,2.5rem)] items-center space-x-1 rounded-md border border-foreground/[0.08] bg-background p-[var(--space-1,0.25rem)]\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nMenubar.displayName = \"Menubar\";\n\n// The explicit `as typeof ...Primitive.X` casts below are load-bearing: without them,\n// tsup's dts build fails with TS2742 \"The inferred type of X cannot be named without a\n// reference to @radix-ui/react-context\" on direct re-exports of Radix primitives. Do not\n// remove without verifying `pnpm --filter @hex-core/components build` still succeeds.\n\n/** A top-level menu in the bar (e.g. \"File\"). */\nconst MenubarMenu = MenubarPrimitive.Menu as typeof MenubarPrimitive.Menu;\n\n/** Groups related items inside a menu content. */\nconst MenubarGroup = MenubarPrimitive.Group as typeof MenubarPrimitive.Group;\n\n/** Portals menu content into the body. */\nconst MenubarPortal = MenubarPrimitive.Portal as typeof MenubarPrimitive.Portal;\n\n/** Group for checkable radio items. */\nconst MenubarRadioGroup = MenubarPrimitive.RadioGroup as typeof MenubarPrimitive.RadioGroup;\n\n/** The clickable menu label in the bar. */\nconst MenubarTrigger = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Trigger>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n\t<MenubarPrimitive.Trigger\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex cursor-default select-none items-center rounded-sm px-[var(--space-3,0.75rem)] py-1.5 text-sm font-medium outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nMenubarTrigger.displayName = \"MenubarTrigger\";\n\n/** The menu panel shown when a trigger opens. */\nconst MenubarContent = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>\n>(({ className, align = \"start\", alignOffset = -4, sideOffset = 8, ...props }, ref) => (\n\t<MenubarPrimitive.Portal>\n\t\t<MenubarPrimitive.Content\n\t\t\tref={ref}\n\t\t\talign={align}\n\t\t\talignOffset={alignOffset}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 min-w-[12rem] overflow-hidden rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-1,0.25rem)] text-popover-foreground shadow-md\",\n\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</MenubarPrimitive.Portal>\n));\nMenubarContent.displayName = \"MenubarContent\";\n\n/** A clickable menu item. */\nconst MenubarItem = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<MenubarPrimitive.Item\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center gap-[var(--gap-sm,0.5rem)] rounded-sm px-[var(--space-2,0.5rem)] py-1.5 text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tinset && \"pl-[var(--space-8,2rem)]\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nMenubarItem.displayName = \"MenubarItem\";\n\n/** A non-interactive heading label. */\nconst MenubarLabel = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Label>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<MenubarPrimitive.Label\n\t\tref={ref}\n\t\tclassName={cn(\"px-[var(--space-2,0.5rem)] py-1.5 text-sm font-semibold\", inset && \"pl-[var(--space-8,2rem)]\", className)}\n\t\t{...props}\n\t/>\n));\nMenubarLabel.displayName = \"MenubarLabel\";\n\n/** Horizontal divider. */\nconst MenubarSeparator = React.forwardRef<\n\tReact.ComponentRef<typeof MenubarPrimitive.Separator>,\n\tReact.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n\t<MenubarPrimitive.Separator\n\t\tref={ref}\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] my-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nMenubarSeparator.displayName = \"MenubarSeparator\";\n\n/**\n * Right-aligned keyboard shortcut text.\n * @returns A span with muted typography\n */\nfunction MenubarShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport {\n\tMenubar,\n\tMenubarMenu,\n\tMenubarTrigger,\n\tMenubarContent,\n\tMenubarItem,\n\tMenubarLabel,\n\tMenubarSeparator,\n\tMenubarShortcut,\n\tMenubarGroup,\n\tMenubarPortal,\n\tMenubarRadioGroup,\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/message-actions/message-actions.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACmBA,SAAS,eAAe,EAAE,SAAA,EAAW,QAAA,EAAU,GAAG,OAAM,EAAwB;AAC/E,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACV,yCAAA;AAAA,QACA,qEAAA;AAAA,QACA,4EAAA;AAAA,QACA;AAAA,OACD;AAAA,MACC,GAAG,KAAA;AAAA,MAEH;AAAA;AAAA,GACF;AAEF","file":"message-actions.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Inline action row beneath a message — typically holds copy / regenerate /\n * thumbs-up / thumbs-down buttons. Pure container: it sets the layout and\n * leaves the buttons (and their handlers) to the consumer.\n *\n * Renders below the message body with subtle hover-reveal styling — the\n * row is dimmed by default and brightens when the parent hovers.\n *\n * @example\n * <Message role=\"assistant\">\n * <Markdown>{text}</Markdown>\n * <MessageActions>\n * <Button variant=\"ghost\" size=\"icon\" onClick={() => copy(text)}><CopyIcon /></Button>\n * <Button variant=\"ghost\" size=\"icon\" onClick={onRegenerate}><RetryIcon /></Button>\n * </MessageActions>\n * </Message>\n */\nexport interface MessageActionsProps extends React.HTMLAttributes<HTMLDivElement> {\n\tchildren: React.ReactNode;\n}\n\n/**\n * Renders the action-button row.\n * @param props - children buttons\n * @returns A flex container styled for in-message actions\n */\nfunction MessageActions({ className, children, ...props }: MessageActionsProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"mt-2 flex items-center gap-1 opacity-60\",\n\t\t\t\t\"transition-opacity duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\"group-hover/message:opacity-100 hover:opacity-100 focus-within:opacity-100\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { MessageActions };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/message-actions/message-actions.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACmBA,SAAS,eAAe,EAAE,SAAA,EAAW,QAAA,EAAU,GAAG,OAAM,EAAwB;AAC/E,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACV,yCAAA;AAAA,QACA,qEAAA;AAAA,QACA,4EAAA;AAAA,QACA;AAAA,OACD;AAAA,MACC,GAAG,KAAA;AAAA,MAEH;AAAA;AAAA,GACF;AAEF","file":"message-actions.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Inline action row beneath a message — typically holds copy / regenerate /\n * thumbs-up / thumbs-down buttons. Pure container: it sets the layout and\n * leaves the buttons (and their handlers) to the consumer.\n *\n * Renders below the message body with subtle hover-reveal styling — the\n * row is dimmed by default and brightens when the parent hovers.\n *\n * @example\n * <Message role=\"assistant\">\n * <Markdown>{text}</Markdown>\n * <MessageActions>\n * <Button variant=\"ghost\" size=\"icon\" onClick={() => copy(text)}><CopyIcon /></Button>\n * <Button variant=\"ghost\" size=\"icon\" onClick={onRegenerate}><RetryIcon /></Button>\n * </MessageActions>\n * </Message>\n */\nexport interface MessageActionsProps extends React.HTMLAttributes<HTMLDivElement> {\n\tchildren: React.ReactNode;\n}\n\n/**\n * Renders the action-button row.\n * @param props - children buttons\n * @returns A flex container styled for in-message actions\n */\nfunction MessageActions({ className, children, ...props }: MessageActionsProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"mt-2 flex items-center gap-1 opacity-60\",\n\t\t\t\t\"transition-opacity duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\"group-hover/message:opacity-100 hover:opacity-100 focus-within:opacity-100\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { MessageActions };\n"]}
|
package/dist/message-list.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/message-list/message-list.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACaA,IAAM,wBAAA,GAA2B,EAAA;AAOjC,SAAS,WAAA,CAAY;AAAA,EACpB,UAAA,GAAa,IAAA;AAAA,EACb,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACJ,CAAA,EAAqB;AACpB,EAAA,MAAM,GAAA,GAAY,aAAuB,IAAI,CAAA;AAC7C,EAAA,MAAM,gBAAA,GAAyB,aAAO,IAAI,CAAA;AAE1C,EAAM,gBAAU,MAAM;AACrB,IAAA,MAAM,KAAK,GAAA,CAAI,OAAA;AACf,IAAA,IAAI,CAAC,EAAA,IAAM,CAAC,UAAA,EAAY;AACxB,IAAA,IAAI,iBAAiB,OAAA,EAAS;AAC7B,MAAA,EAAA,CAAG,YAAY,EAAA,CAAG,YAAA;AAAA,IACnB;AAAA,EACD,CAAA,EAAG,CAAC,UAAA,EAAY,QAAQ,CAAC,CAAA;AAEzB,EAAA,SAAS,aAAa,KAAA,EAAsC;AAC3D,IAAA,MAAM,KAAK,KAAA,CAAM,aAAA;AACjB,IAAA,MAAM,QAAA,GAAW,EAAA,CAAG,YAAA,GAAe,EAAA,CAAG,YAAY,EAAA,CAAG,YAAA;AACrD,IAAA,gBAAA,CAAiB,UAAU,QAAA,GAAW,wBAAA;AACtC,IAAA,KAAA,CAAM,WAAW,KAAK,CAAA;AAAA,EACvB;AAEA,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,GAAA;AAAA,MACA,IAAA,EAAK,KAAA;AAAA,MACL,WAAA,EAAU,QAAA;AAAA,MACV,eAAA,EAAc,WAAA;AAAA,MACd,SAAA,EAAW,EAAA,CAAG,+BAAA,EAAiC,SAAS,CAAA;AAAA,MACvD,GAAG,KAAA;AAAA,MACJ,QAAA,EAAU,YAAA;AAAA,MAET;AAAA;AAAA,GACF;AAEF","file":"message-list.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Auto-scrolling viewport for a stream of chat messages. When `autoScroll`\n * is true (default), the container pins to the bottom whenever its content\n * changes — including during streaming token updates. Detects whether the\n * user has scrolled away from the bottom and pauses auto-scroll until they\n * scroll back, so reading earlier turns doesn't fight the stream.\n *\n * @example\n * <MessageList>\n * {messages.map((m) => <Message key={m.id} role={m.role}>{m.content}</Message>)}\n * </MessageList>\n */\nexport interface MessageListProps extends React.HTMLAttributes<HTMLDivElement> {\n\t/** Auto-scroll to bottom on content change (when user is already near the bottom). Default: true. */\n\tautoScroll?: boolean;\n\tchildren: React.ReactNode;\n}\n\nconst NEAR_BOTTOM_THRESHOLD_PX = 80;\n\n/**\n * Renders the scrolling message viewport.\n * @param props - children + autoScroll toggle\n * @returns A scrollable div that auto-pins to bottom when streaming\n */\nfunction MessageList({\n\tautoScroll = true,\n\tclassName,\n\tchildren,\n\t...props\n}: MessageListProps) {\n\tconst ref = React.useRef<HTMLDivElement>(null);\n\tconst stickToBottomRef = React.useRef(true);\n\n\tReact.useEffect(() => {\n\t\tconst el = ref.current;\n\t\tif (!el || !autoScroll) return;\n\t\tif (stickToBottomRef.current) {\n\t\t\tel.scrollTop = el.scrollHeight;\n\t\t}\n\t}, [autoScroll, children]);\n\n\tfunction handleScroll(event: React.UIEvent<HTMLDivElement>) {\n\t\tconst el = event.currentTarget;\n\t\tconst distance = el.scrollHeight - el.scrollTop - el.clientHeight;\n\t\tstickToBottomRef.current = distance < NEAR_BOTTOM_THRESHOLD_PX;\n\t\tprops.onScroll?.(event);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\trole=\"log\"\n\t\t\taria-live=\"polite\"\n\t\t\taria-relevant=\"additions\"\n\t\t\tclassName={cn(\"flex flex-col overflow-y-auto\", className)}\n\t\t\t{...props}\n\t\t\tonScroll={handleScroll}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { MessageList };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/message-list/message-list.tsx"],"names":[],"mappings":";;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACaA,IAAM,wBAAA,GAA2B,EAAA;AAOjC,SAAS,WAAA,CAAY;AAAA,EACpB,UAAA,GAAa,IAAA;AAAA,EACb,SAAA;AAAA,EACA,QAAA;AAAA,EACA,GAAG;AACJ,CAAA,EAAqB;AACpB,EAAA,MAAM,GAAA,GAAY,aAAuB,IAAI,CAAA;AAC7C,EAAA,MAAM,gBAAA,GAAyB,aAAO,IAAI,CAAA;AAE1C,EAAM,gBAAU,MAAM;AACrB,IAAA,MAAM,KAAK,GAAA,CAAI,OAAA;AACf,IAAA,IAAI,CAAC,EAAA,IAAM,CAAC,UAAA,EAAY;AACxB,IAAA,IAAI,iBAAiB,OAAA,EAAS;AAC7B,MAAA,EAAA,CAAG,YAAY,EAAA,CAAG,YAAA;AAAA,IACnB;AAAA,EACD,CAAA,EAAG,CAAC,UAAA,EAAY,QAAQ,CAAC,CAAA;AAEzB,EAAA,SAAS,aAAa,KAAA,EAAsC;AAC3D,IAAA,MAAM,KAAK,KAAA,CAAM,aAAA;AACjB,IAAA,MAAM,QAAA,GAAW,EAAA,CAAG,YAAA,GAAe,EAAA,CAAG,YAAY,EAAA,CAAG,YAAA;AACrD,IAAA,gBAAA,CAAiB,UAAU,QAAA,GAAW,wBAAA;AACtC,IAAA,KAAA,CAAM,WAAW,KAAK,CAAA;AAAA,EACvB;AAEA,EAAA,uBACC,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACA,GAAA;AAAA,MACA,IAAA,EAAK,KAAA;AAAA,MACL,WAAA,EAAU,QAAA;AAAA,MACV,eAAA,EAAc,WAAA;AAAA,MACd,SAAA,EAAW,EAAA,CAAG,+BAAA,EAAiC,SAAS,CAAA;AAAA,MACvD,GAAG,KAAA;AAAA,MACJ,QAAA,EAAU,YAAA;AAAA,MAET;AAAA;AAAA,GACF;AAEF","file":"message-list.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Auto-scrolling viewport for a stream of chat messages. When `autoScroll`\n * is true (default), the container pins to the bottom whenever its content\n * changes — including during streaming token updates. Detects whether the\n * user has scrolled away from the bottom and pauses auto-scroll until they\n * scroll back, so reading earlier turns doesn't fight the stream.\n *\n * @example\n * <MessageList>\n * {messages.map((m) => <Message key={m.id} role={m.role}>{m.content}</Message>)}\n * </MessageList>\n */\nexport interface MessageListProps extends React.HTMLAttributes<HTMLDivElement> {\n\t/** Auto-scroll to bottom on content change (when user is already near the bottom). Default: true. */\n\tautoScroll?: boolean;\n\tchildren: React.ReactNode;\n}\n\nconst NEAR_BOTTOM_THRESHOLD_PX = 80;\n\n/**\n * Renders the scrolling message viewport.\n * @param props - children + autoScroll toggle\n * @returns A scrollable div that auto-pins to bottom when streaming\n */\nfunction MessageList({\n\tautoScroll = true,\n\tclassName,\n\tchildren,\n\t...props\n}: MessageListProps) {\n\tconst ref = React.useRef<HTMLDivElement>(null);\n\tconst stickToBottomRef = React.useRef(true);\n\n\tReact.useEffect(() => {\n\t\tconst el = ref.current;\n\t\tif (!el || !autoScroll) return;\n\t\tif (stickToBottomRef.current) {\n\t\t\tel.scrollTop = el.scrollHeight;\n\t\t}\n\t}, [autoScroll, children]);\n\n\tfunction handleScroll(event: React.UIEvent<HTMLDivElement>) {\n\t\tconst el = event.currentTarget;\n\t\tconst distance = el.scrollHeight - el.scrollTop - el.clientHeight;\n\t\tstickToBottomRef.current = distance < NEAR_BOTTOM_THRESHOLD_PX;\n\t\tprops.onScroll?.(event);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\trole=\"log\"\n\t\t\taria-live=\"polite\"\n\t\t\taria-relevant=\"additions\"\n\t\t\tclassName={cn(\"flex flex-col overflow-y-auto\", className)}\n\t\t\t{...props}\n\t\t\tonScroll={handleScroll}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { MessageList };\n"]}
|
package/dist/message.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/message/message.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACLA,IAAM,eAAA,GAAkB,GAAA;AAAA,EACvB;AAAA,IACC,qCAAA;AAAA,IACA;AAAA,GACD,CAAE,KAAK,GAAG,CAAA;AAAA,EACV;AAAA,IACC,QAAA,EAAU;AAAA,MACT,IAAA,EAAM;AAAA,QACL,IAAA,EAAM,iCAAA;AAAA,QACN,SAAA,EAAW,8BAAA;AAAA,QACX,MAAA,EAAQ,uCAAA;AAAA,QACR,IAAA,EAAM;AAAA;AACP,KACD;AAAA,IACA,eAAA,EAAiB;AAAA,MAChB,IAAA,EAAM;AAAA;AACP;AAEF;AA8BA,SAAS,QAAQ,EAAE,IAAA,EAAM,WAAW,QAAA,EAAU,GAAG,OAAM,EAAiB;AACvE,EAAA,uBACC,GAAA,CAAC,KAAA,EAAA,EAAI,WAAA,EAAW,IAAA,EAAM,WAAW,EAAA,CAAG,eAAA,CAAgB,EAAE,IAAA,EAAM,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,OAC7E,QAAA,EACF,CAAA;AAEF","file":"message.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport type { Role } from \"../types.js\";\n\nconst messageVariants = cva(\n\t[\n\t\t\"flex w-full gap-3 px-4 py-3 text-sm\",\n\t\t\"transition-colors duration-[var(--duration-normal,200ms)] ease-out\",\n\t].join(\" \"),\n\t{\n\t\tvariants: {\n\t\t\trole: {\n\t\t\t\tuser: \"bg-secondary/40 text-foreground\",\n\t\t\t\tassistant: \"bg-card text-card-foreground\",\n\t\t\t\tsystem: \"bg-muted text-muted-foreground italic\",\n\t\t\t\ttool: \"bg-accent/15 text-accent-foreground border-l-2 border-accent\",\n\t\t\t},\n\t\t},\n\t\tdefaultVariants: {\n\t\t\trole: \"assistant\",\n\t\t},\n\t},\n);\n\n/**\n * Single chat message row. Renders content with role-specific styling and a\n * `data-role` attribute so consumers can target arbitrary roles via CSS.\n *\n * Headless: accepts any `children`. Pair with `Markdown` + `CodeBlock` for\n * assistant turns, with `ToolCall` for agent steps, or with plain strings.\n *\n * @example\n * <Message role=\"user\">What's the weather?</Message>\n * @example\n * <Message role=\"assistant\">\n * <Markdown>{streamingText}</Markdown>\n * <ToolCall name=\"getWeather\" state=\"result\" args={...} result={...} />\n * </Message>\n */\nexport interface MessageProps\n\textends Omit<React.HTMLAttributes<HTMLDivElement>, \"role\">,\n\t\tVariantProps<typeof messageVariants> {\n\t/** Speaker — drives variant styling and the `data-role` attribute. */\n\trole: Role;\n\tchildren: React.ReactNode;\n}\n\n/**\n * Renders a chat-message row scoped to one speaker.\n * @param props - role + content\n * @returns A styled div tagged with `data-role={role}`\n */\nfunction Message({ role, className, children, ...props }: MessageProps) {\n\treturn (\n\t\t<div data-role={role} className={cn(messageVariants({ role }), className)} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { Message, messageVariants };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/message/message.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACLA,IAAM,eAAA,GAAkB,GAAA;AAAA,EACvB;AAAA,IACC,qCAAA;AAAA,IACA;AAAA,GACD,CAAE,KAAK,GAAG,CAAA;AAAA,EACV;AAAA,IACC,QAAA,EAAU;AAAA,MACT,IAAA,EAAM;AAAA,QACL,IAAA,EAAM,iCAAA;AAAA,QACN,SAAA,EAAW,8BAAA;AAAA,QACX,MAAA,EAAQ,uCAAA;AAAA,QACR,IAAA,EAAM;AAAA;AACP,KACD;AAAA,IACA,eAAA,EAAiB;AAAA,MAChB,IAAA,EAAM;AAAA;AACP;AAEF;AA8BA,SAAS,QAAQ,EAAE,IAAA,EAAM,WAAW,QAAA,EAAU,GAAG,OAAM,EAAiB;AACvE,EAAA,uBACC,GAAA,CAAC,KAAA,EAAA,EAAI,WAAA,EAAW,IAAA,EAAM,WAAW,EAAA,CAAG,eAAA,CAAgB,EAAE,IAAA,EAAM,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,OAC7E,QAAA,EACF,CAAA;AAEF","file":"message.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport type { Role } from \"../types.js\";\n\nconst messageVariants = cva(\n\t[\n\t\t\"flex w-full gap-3 px-4 py-3 text-sm\",\n\t\t\"transition-colors duration-[var(--duration-normal,200ms)] ease-out\",\n\t].join(\" \"),\n\t{\n\t\tvariants: {\n\t\t\trole: {\n\t\t\t\tuser: \"bg-secondary/40 text-foreground\",\n\t\t\t\tassistant: \"bg-card text-card-foreground\",\n\t\t\t\tsystem: \"bg-muted text-muted-foreground italic\",\n\t\t\t\ttool: \"bg-accent/15 text-accent-foreground border-l-2 border-accent\",\n\t\t\t},\n\t\t},\n\t\tdefaultVariants: {\n\t\t\trole: \"assistant\",\n\t\t},\n\t},\n);\n\n/**\n * Single chat message row. Renders content with role-specific styling and a\n * `data-role` attribute so consumers can target arbitrary roles via CSS.\n *\n * Headless: accepts any `children`. Pair with `Markdown` + `CodeBlock` for\n * assistant turns, with `ToolCall` for agent steps, or with plain strings.\n *\n * @example\n * <Message role=\"user\">What's the weather?</Message>\n * @example\n * <Message role=\"assistant\">\n * <Markdown>{streamingText}</Markdown>\n * <ToolCall name=\"getWeather\" state=\"result\" args={...} result={...} />\n * </Message>\n */\nexport interface MessageProps\n\textends Omit<React.HTMLAttributes<HTMLDivElement>, \"role\">,\n\t\tVariantProps<typeof messageVariants> {\n\t/** Speaker — drives variant styling and the `data-role` attribute. */\n\trole: Role;\n\tchildren: React.ReactNode;\n}\n\n/**\n * Renders a chat-message row scoped to one speaker.\n * @param props - role + content\n * @returns A styled div tagged with `data-role={role}`\n */\nfunction Message({ role, className, children, ...props }: MessageProps) {\n\treturn (\n\t\t<div data-role={role} className={cn(messageVariants({ role }), className)} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { Message, messageVariants };\n"]}
|
package/dist/mind-map.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/mind-map/mind-map.tsx"],"names":["layoutRoot","nodes","links"],"mappings":"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","file":"mind-map.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Typed React MindMap. Pass a hierarchical `root` node and the component lays\n * the children out radially (or horizontally) using d3-hierarchy's tree\n * layout. No Mermaid string parsing — the data shape IS the API, so consumers\n * can build mind maps from typed application state instead of templating a\n * DSL.\n *\n * Heavy peer: requires `d3-hierarchy` (~3 KB gzip). The hex-core CLI's `add`\n * flow prompts before installing.\n *\n * @example\n * <MindMap\n * root={{\n * id: \"root\",\n * label: \"Project\",\n * children: [\n * { id: \"ui\", label: \"UI\", children: [{ id: \"btn\", label: \"Button\" }] },\n * { id: \"api\", label: \"API\" },\n * ],\n * }}\n * />\n */\nexport type MindMapNode = {\n\tid: string;\n\tlabel: string;\n\tchildren?: MindMapNode[];\n\tdata?: unknown;\n};\n\nexport interface MindMapProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n\t/** Root of the hierarchy. */\n\troot: MindMapNode;\n\t/** \"radial\" lays children around the root; \"horizontal\" runs left→right. Default \"radial\". */\n\torientation?: \"radial\" | \"horizontal\";\n\t/** Pixel width of the rendered SVG. Default 600. */\n\twidth?: number;\n\t/** Pixel height of the rendered SVG. Default 400. */\n\theight?: number;\n\t/** Fired when a node is clicked. */\n\tonNodeClick?: (node: MindMapNode) => void;\n}\n\ninterface LaidOutNode {\n\tnode: MindMapNode;\n\tx: number;\n\ty: number;\n\tdepth: number;\n}\n\ninterface LaidOutLink {\n\tsource: { x: number; y: number };\n\ttarget: { x: number; y: number };\n\tid: string;\n}\n\ntype D3HierarchyMod = typeof import(\"d3-hierarchy\");\n\nfunction MindMap({\n\troot,\n\torientation = \"radial\",\n\twidth = 600,\n\theight = 400,\n\tonNodeClick,\n\tclassName,\n\t...rest\n}: MindMapProps) {\n\tconst [d3h, setD3h] = React.useState<D3HierarchyMod | null>(null);\n\n\tReact.useEffect(() => {\n\t\tlet cancelled = false;\n\t\tvoid import(\"d3-hierarchy\").then((mod) => {\n\t\t\tif (!cancelled) setD3h(mod);\n\t\t});\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, []);\n\n\tif (!d3h) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tdata-hex-mind-map-loading\n\t\t\t\taria-busy=\"true\"\n\t\t\t\tclassName={cn(\"inline-block bg-muted/20\", className)}\n\t\t\t\tstyle={{ width, height }}\n\t\t\t/>\n\t\t);\n\t}\n\n\tconst { nodes, links, viewBox } = layout(d3h, root, orientation, width, height);\n\tconst nodeCount = nodes.length;\n\tconst desc = `Mind map with ${nodeCount} node${nodeCount === 1 ? \"\" : \"s\"}, rooted at \"${root.label}\"`;\n\n\treturn (\n\t\t<svg\n\t\t\t{...rest}\n\t\t\tdata-hex-mind-map\n\t\t\tdata-orientation={orientation}\n\t\t\trole=\"img\"\n\t\t\tviewBox={viewBox}\n\t\t\twidth={width}\n\t\t\theight={height}\n\t\t\tclassName={cn(\"block\", className)}\n\t\t>\n\t\t\t<title>Mind map</title>\n\t\t\t<desc>{desc}</desc>\n\t\t\t<g data-hex-mind-map-links>\n\t\t\t\t{links.map((l) => (\n\t\t\t\t\t<path\n\t\t\t\t\t\tkey={l.id}\n\t\t\t\t\t\td={linkPath(l, orientation)}\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"hsl(var(--muted-foreground))\"\n\t\t\t\t\t\tstrokeOpacity={0.7}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t<g data-hex-mind-map-nodes>\n\t\t\t\t{nodes.map((n) => (\n\t\t\t\t\t<g\n\t\t\t\t\t\tkey={n.node.id}\n\t\t\t\t\t\tdata-hex-mind-map-node\n\t\t\t\t\t\tdata-depth={n.depth}\n\t\t\t\t\t\ttransform={`translate(${n.x},${n.y})`}\n\t\t\t\t\t\tstyle={onNodeClick ? { cursor: \"pointer\" } : undefined}\n\t\t\t\t\t\tonClick={onNodeClick ? () => onNodeClick(n.node) : undefined}\n\t\t\t\t\t>\n\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\tr={4}\n\t\t\t\t\t\t\tfill=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\tstroke=\"hsl(var(--background))\"\n\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\tx={8}\n\t\t\t\t\t\t\ty={4}\n\t\t\t\t\t\t\tfontSize={12}\n\t\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\t\tstyle={{ paintOrder: \"stroke\" }}\n\t\t\t\t\t\t\tstroke=\"hsl(var(--background))\"\n\t\t\t\t\t\t\tstrokeWidth={3}\n\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{n.node.label}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t</g>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t</svg>\n\t);\n}\n\nfunction layout(\n\td3h: D3HierarchyMod,\n\troot: MindMapNode,\n\torientation: \"radial\" | \"horizontal\",\n\twidth: number,\n\theight: number,\n): { nodes: LaidOutNode[]; links: LaidOutLink[]; viewBox: string } {\n\tconst hierarchy = d3h.hierarchy<MindMapNode>(root);\n\n\tif (orientation === \"radial\") {\n\t\tconst radius = Math.min(width, height) / 2 - 16;\n\t\t// d3.tree(hierarchy) returns the layout-mutated root typed as\n\t\t// HierarchyPointNode<T> — its `x`/`y` are populated by the call.\n\t\tconst layoutRoot = d3h.tree<MindMapNode>().size([2 * Math.PI, radius])(hierarchy);\n\t\tconst nodes: LaidOutNode[] = [];\n\t\tconst links: LaidOutLink[] = [];\n\t\tlayoutRoot.each((d) => {\n\t\t\tconst point = polarToCartesian(d.x, d.y);\n\t\t\tnodes.push({ node: d.data, x: point.x, y: point.y, depth: d.depth });\n\t\t});\n\t\tlayoutRoot.links().forEach((link, i) => {\n\t\t\tconst sPt = polarToCartesian(link.source.x, link.source.y);\n\t\t\tconst tPt = polarToCartesian(link.target.x, link.target.y);\n\t\t\tlinks.push({ source: sPt, target: tPt, id: `l-${i}` });\n\t\t});\n\t\tconst half = Math.min(width, height) / 2;\n\t\treturn {\n\t\t\tnodes,\n\t\t\tlinks,\n\t\t\tviewBox: `${-half} ${-half} ${2 * half} ${2 * half}`,\n\t\t};\n\t}\n\n\tconst layoutRoot = d3h.tree<MindMapNode>().size([height - 32, width - 200])(hierarchy);\n\tconst nodes: LaidOutNode[] = [];\n\tconst links: LaidOutLink[] = [];\n\tlayoutRoot.each((d) => {\n\t\t// Horizontal: swap d3's (x, y) so depth runs along the SVG x-axis.\n\t\tnodes.push({ node: d.data, x: d.y, y: d.x, depth: d.depth });\n\t});\n\tlayoutRoot.links().forEach((link, i) => {\n\t\tlinks.push({\n\t\t\tsource: { x: link.source.y, y: link.source.x },\n\t\t\ttarget: { x: link.target.y, y: link.target.x },\n\t\t\tid: `l-${i}`,\n\t\t});\n\t});\n\treturn {\n\t\tnodes,\n\t\tlinks,\n\t\tviewBox: `0 0 ${width} ${height}`,\n\t};\n}\n\nfunction polarToCartesian(angle: number, radius: number): { x: number; y: number } {\n\treturn {\n\t\tx: radius * Math.cos(angle - Math.PI / 2),\n\t\ty: radius * Math.sin(angle - Math.PI / 2),\n\t};\n}\n\nfunction linkPath(link: LaidOutLink, orientation: \"radial\" | \"horizontal\"): string {\n\tconst { source: s, target: t } = link;\n\tif (orientation === \"horizontal\") {\n\t\tconst mx = (s.x + t.x) / 2;\n\t\treturn `M${s.x},${s.y} C${mx},${s.y} ${mx},${t.y} ${t.x},${t.y}`;\n\t}\n\treturn `M${s.x},${s.y} C${s.x},${(s.y + t.y) / 2} ${t.x},${(s.y + t.y) / 2} ${t.x},${t.y}`;\n}\n\nexport { MindMap };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/mind-map/mind-map.tsx"],"names":["layoutRoot","nodes","links"],"mappings":"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","file":"mind-map.js","sourcesContent":["import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge class names with Tailwind CSS conflict resolution.\n * @param inputs - Class values (strings, arrays, objects) to merge\n * @returns A single merged class string with Tailwind conflicts resolved\n */\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n\nconst SAFE_URL_SCHEMES = [\"http:\", \"https:\", \"mailto:\"] as const;\n\n/**\n * Allowlist a URL for use as an `<a href>` against untrusted input.\n *\n * Returns the raw string when it's `http(s):` / `mailto:` / a relative\n * URL (no scheme); returns `undefined` otherwise. Defends against\n * `javascript:` / `data:` / `vbscript:` injection from streamed model\n * output or third-party JSON payloads that flow into citation chips.\n *\n * Inside a Markdown render path, `rehype-sanitize` already strips\n * `javascript:` from inline-link hrefs — but it does NOT introspect\n * JSON nested inside attribute values (e.g. `<sources data='[…]'/>`),\n * so the components that consume that data must guard themselves.\n *\n * @param raw - The candidate URL, or `undefined` when none was supplied.\n * @returns The URL when safe to render, otherwise `undefined`.\n */\nexport function safeUrl(raw: string | undefined): string | undefined {\n\tif (raw === undefined || raw === \"\") return undefined;\n\t// Relative URLs have no scheme — `new URL(relative)` throws without a base,\n\t// so a thrown URL means either malformed input OR a relative path. Treat\n\t// \"throws + does not contain a colon\" as a relative path (safe).\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\treturn raw.includes(\":\") ? undefined : raw;\n\t}\n\treturn SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : undefined;\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Typed React MindMap. Pass a hierarchical `root` node and the component lays\n * the children out radially (or horizontally) using d3-hierarchy's tree\n * layout. No Mermaid string parsing — the data shape IS the API, so consumers\n * can build mind maps from typed application state instead of templating a\n * DSL.\n *\n * Heavy peer: requires `d3-hierarchy` (~3 KB gzip). The hex-core CLI's `add`\n * flow prompts before installing.\n *\n * @example\n * <MindMap\n * root={{\n * id: \"root\",\n * label: \"Project\",\n * children: [\n * { id: \"ui\", label: \"UI\", children: [{ id: \"btn\", label: \"Button\" }] },\n * { id: \"api\", label: \"API\" },\n * ],\n * }}\n * />\n */\nexport type MindMapNode = {\n\tid: string;\n\tlabel: string;\n\tchildren?: MindMapNode[];\n\tdata?: unknown;\n};\n\nexport interface MindMapProps extends Omit<React.SVGAttributes<SVGSVGElement>, \"children\"> {\n\t/** Root of the hierarchy. */\n\troot: MindMapNode;\n\t/** \"radial\" lays children around the root; \"horizontal\" runs left→right. Default \"radial\". */\n\torientation?: \"radial\" | \"horizontal\";\n\t/** Pixel width of the rendered SVG. Default 600. */\n\twidth?: number;\n\t/** Pixel height of the rendered SVG. Default 400. */\n\theight?: number;\n\t/** Fired when a node is clicked. */\n\tonNodeClick?: (node: MindMapNode) => void;\n}\n\ninterface LaidOutNode {\n\tnode: MindMapNode;\n\tx: number;\n\ty: number;\n\tdepth: number;\n}\n\ninterface LaidOutLink {\n\tsource: { x: number; y: number };\n\ttarget: { x: number; y: number };\n\tid: string;\n}\n\ntype D3HierarchyMod = typeof import(\"d3-hierarchy\");\n\nfunction MindMap({\n\troot,\n\torientation = \"radial\",\n\twidth = 600,\n\theight = 400,\n\tonNodeClick,\n\tclassName,\n\t...rest\n}: MindMapProps) {\n\tconst [d3h, setD3h] = React.useState<D3HierarchyMod | null>(null);\n\n\tReact.useEffect(() => {\n\t\tlet cancelled = false;\n\t\tvoid import(\"d3-hierarchy\").then((mod) => {\n\t\t\tif (!cancelled) setD3h(mod);\n\t\t});\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, []);\n\n\tif (!d3h) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tdata-hex-mind-map-loading\n\t\t\t\taria-busy=\"true\"\n\t\t\t\tclassName={cn(\"inline-block bg-muted/20\", className)}\n\t\t\t\tstyle={{ width, height }}\n\t\t\t/>\n\t\t);\n\t}\n\n\tconst { nodes, links, viewBox } = layout(d3h, root, orientation, width, height);\n\tconst nodeCount = nodes.length;\n\tconst desc = `Mind map with ${nodeCount} node${nodeCount === 1 ? \"\" : \"s\"}, rooted at \"${root.label}\"`;\n\n\treturn (\n\t\t<svg\n\t\t\t{...rest}\n\t\t\tdata-hex-mind-map\n\t\t\tdata-orientation={orientation}\n\t\t\trole=\"img\"\n\t\t\tviewBox={viewBox}\n\t\t\twidth={width}\n\t\t\theight={height}\n\t\t\tclassName={cn(\"block\", className)}\n\t\t>\n\t\t\t<title>Mind map</title>\n\t\t\t<desc>{desc}</desc>\n\t\t\t<g data-hex-mind-map-links>\n\t\t\t\t{links.map((l) => (\n\t\t\t\t\t<path\n\t\t\t\t\t\tkey={l.id}\n\t\t\t\t\t\td={linkPath(l, orientation)}\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"hsl(var(--muted-foreground))\"\n\t\t\t\t\t\tstrokeOpacity={0.7}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t\t<g data-hex-mind-map-nodes>\n\t\t\t\t{nodes.map((n) => (\n\t\t\t\t\t<g\n\t\t\t\t\t\tkey={n.node.id}\n\t\t\t\t\t\tdata-hex-mind-map-node\n\t\t\t\t\t\tdata-depth={n.depth}\n\t\t\t\t\t\ttransform={`translate(${n.x},${n.y})`}\n\t\t\t\t\t\tstyle={onNodeClick ? { cursor: \"pointer\" } : undefined}\n\t\t\t\t\t\tonClick={onNodeClick ? () => onNodeClick(n.node) : undefined}\n\t\t\t\t\t>\n\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\tr={4}\n\t\t\t\t\t\t\tfill=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\tstroke=\"hsl(var(--background))\"\n\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\tx={8}\n\t\t\t\t\t\t\ty={4}\n\t\t\t\t\t\t\tfontSize={12}\n\t\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\t\tstyle={{ paintOrder: \"stroke\" }}\n\t\t\t\t\t\t\tstroke=\"hsl(var(--background))\"\n\t\t\t\t\t\t\tstrokeWidth={3}\n\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{n.node.label}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t</g>\n\t\t\t\t))}\n\t\t\t</g>\n\t\t</svg>\n\t);\n}\n\nfunction layout(\n\td3h: D3HierarchyMod,\n\troot: MindMapNode,\n\torientation: \"radial\" | \"horizontal\",\n\twidth: number,\n\theight: number,\n): { nodes: LaidOutNode[]; links: LaidOutLink[]; viewBox: string } {\n\tconst hierarchy = d3h.hierarchy<MindMapNode>(root);\n\n\tif (orientation === \"radial\") {\n\t\tconst radius = Math.min(width, height) / 2 - 16;\n\t\t// d3.tree(hierarchy) returns the layout-mutated root typed as\n\t\t// HierarchyPointNode<T> — its `x`/`y` are populated by the call.\n\t\tconst layoutRoot = d3h.tree<MindMapNode>().size([2 * Math.PI, radius])(hierarchy);\n\t\tconst nodes: LaidOutNode[] = [];\n\t\tconst links: LaidOutLink[] = [];\n\t\tlayoutRoot.each((d) => {\n\t\t\tconst point = polarToCartesian(d.x, d.y);\n\t\t\tnodes.push({ node: d.data, x: point.x, y: point.y, depth: d.depth });\n\t\t});\n\t\tlayoutRoot.links().forEach((link, i) => {\n\t\t\tconst sPt = polarToCartesian(link.source.x, link.source.y);\n\t\t\tconst tPt = polarToCartesian(link.target.x, link.target.y);\n\t\t\tlinks.push({ source: sPt, target: tPt, id: `l-${i}` });\n\t\t});\n\t\tconst half = Math.min(width, height) / 2;\n\t\treturn {\n\t\t\tnodes,\n\t\t\tlinks,\n\t\t\tviewBox: `${-half} ${-half} ${2 * half} ${2 * half}`,\n\t\t};\n\t}\n\n\tconst layoutRoot = d3h.tree<MindMapNode>().size([height - 32, width - 200])(hierarchy);\n\tconst nodes: LaidOutNode[] = [];\n\tconst links: LaidOutLink[] = [];\n\tlayoutRoot.each((d) => {\n\t\t// Horizontal: swap d3's (x, y) so depth runs along the SVG x-axis.\n\t\tnodes.push({ node: d.data, x: d.y, y: d.x, depth: d.depth });\n\t});\n\tlayoutRoot.links().forEach((link, i) => {\n\t\tlinks.push({\n\t\t\tsource: { x: link.source.y, y: link.source.x },\n\t\t\ttarget: { x: link.target.y, y: link.target.x },\n\t\t\tid: `l-${i}`,\n\t\t});\n\t});\n\treturn {\n\t\tnodes,\n\t\tlinks,\n\t\tviewBox: `0 0 ${width} ${height}`,\n\t};\n}\n\nfunction polarToCartesian(angle: number, radius: number): { x: number; y: number } {\n\treturn {\n\t\tx: radius * Math.cos(angle - Math.PI / 2),\n\t\ty: radius * Math.sin(angle - Math.PI / 2),\n\t};\n}\n\nfunction linkPath(link: LaidOutLink, orientation: \"radial\" | \"horizontal\"): string {\n\tconst { source: s, target: t } = link;\n\tif (orientation === \"horizontal\") {\n\t\tconst mx = (s.x + t.x) / 2;\n\t\treturn `M${s.x},${s.y} C${mx},${s.y} ${mx},${t.y} ${t.x},${t.y}`;\n\t}\n\treturn `M${s.x},${s.y} C${s.x},${(s.y + t.y) / 2} ${t.x},${(s.y + t.y) / 2} ${t.x},${t.y}`;\n}\n\nexport { MindMap };\n"]}
|