@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/code-block.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/code-block/code-block.tsx"],"names":[],"mappings":"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","file":"code-block.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 { cache } from \"react\";\nimport { codeToHtml } from \"shiki\";\nimport { cn } from \"../../lib/utils.js\";\nimport { CodeBlockCopy } from \"./code-block-copy.js\";\n\n/**\n * Languages we surface in the prop type. Plain literal union of real\n * Shiki grammar IDs — kept literal (not `Extract<BundledLanguage, …>`)\n * because Shiki's full bundled-language union is 600+ literals, and\n * deriving from it forced the rollup-dts pass past a 4GB heap. The\n * literals here are all standard Shiki grammar IDs; if Shiki removes\n * one upstream, `codeToHtml` will throw at runtime — acceptable trade.\n */\nexport type SupportedLang =\n\t| \"bash\"\n\t| \"ts\"\n\t| \"tsx\"\n\t| \"js\"\n\t| \"jsx\"\n\t| \"json\"\n\t| \"css\"\n\t| \"html\"\n\t| \"md\"\n\t| \"py\"\n\t| \"text\";\n\nconst LABEL_TO_LANG: Record<string, SupportedLang> = {\n\tpnpm: \"bash\",\n\tnpm: \"bash\",\n\tyarn: \"bash\",\n\tbun: \"bash\",\n\tbash: \"bash\",\n\tsh: \"bash\",\n\tshell: \"bash\",\n\tzsh: \"bash\",\n\tts: \"ts\",\n\ttypescript: \"ts\",\n\ttsx: \"tsx\",\n\tjs: \"js\",\n\tjavascript: \"js\",\n\tjsx: \"jsx\",\n\tjson: \"json\",\n\tcss: \"css\",\n\thtml: \"html\",\n\tmd: \"md\",\n\tmarkdown: \"md\",\n\tpy: \"py\",\n\tpython: \"py\",\n\ttext: \"text\",\n\tprompt: \"text\",\n\tplain: \"text\",\n};\n\nconst DEFAULT_THEMES = { light: \"github-light-high-contrast\", dark: \"github-dark\" } as const;\n\n/**\n * Per-render-tree memoization of `codeToHtml`. React's `cache()` dedupes\n * identical (code, lang, theme) combos within a single RSC render pass —\n * useful when a page renders many copies of the same install snippet.\n * Shiki itself caches grammars/themes per process, so this layer only\n * eliminates duplicate parse + tokenize work within one request.\n */\nconst cachedCodeToHtml = cache(\n\tasync (code: string, lang: SupportedLang, themesKey: string, themes: { light: string; dark: string }) => {\n\t\tvoid themesKey;\n\t\treturn codeToHtml(code, { lang, themes, defaultColor: false });\n\t},\n);\n\nfunction resolveLang(label?: string, language?: SupportedLang): SupportedLang {\n\tif (language) return language;\n\tif (label) {\n\t\tconst fromLabel = LABEL_TO_LANG[label.toLowerCase()];\n\t\tif (fromLabel) return fromLabel;\n\t}\n\treturn \"text\";\n}\n\n/**\n * Syntax-highlighted code block with a language-label header and a copy\n * button. Highlighting runs server-side via Shiki using a dual-theme\n * (default: github-light / github-dark) so the same HTML flips on\n * `data-theme`/`prefers-color-scheme` without client-side rehydration.\n *\n * Async Server Component — render inside RSC trees or pre-render in\n * static contexts. For client-side streaming code blocks, plug Streamdown's\n * built-in code rendering via `Markdown components={{ pre: … }}` instead.\n *\n * @example\n * <CodeBlock label=\"pnpm\" code=\"pnpm add @hex-core/components\" />\n * @example\n * <CodeBlock language=\"tsx\" code={src} />\n */\nexport interface CodeBlockProps {\n\tcode: string;\n\t/** Optional header label (e.g. \"pnpm\", \"tsx\"). Inferred from `language` if omitted. */\n\tlabel?: string;\n\t/** Explicit Shiki grammar key. Overrides inference from `label`. */\n\tlanguage?: SupportedLang;\n\t/** Override the default github-light / github-dark theme pair. */\n\tthemes?: { light: string; dark: string };\n\tclassName?: string;\n}\n\n/**\n * Async Server Component that highlights `code` server-side and emits the\n * resulting HTML with a header + copy island.\n *\n * @param props - code, optional label/language/themes\n * @returns A bordered card wrapping the highlighted code\n */\nasync function CodeBlock({\n\tcode,\n\tlabel,\n\tlanguage,\n\tthemes = DEFAULT_THEMES,\n\tclassName,\n}: CodeBlockProps) {\n\tconst lang = resolveLang(label, language);\n\tconst themesKey = `${themes.light}|${themes.dark}`;\n\tconst html = await cachedCodeToHtml(code, lang, themesKey, themes);\n\tconst displayLabel = label ?? lang;\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"group relative overflow-hidden rounded-lg border bg-card text-card-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<div className=\"flex items-center justify-between border-b bg-muted/40 px-3 py-1.5\">\n\t\t\t\t<span className=\"font-mono text-xs font-medium text-muted-foreground\">{displayLabel}</span>\n\t\t\t\t<CodeBlockCopy code={code} />\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tdata-shiki=\"\"\n\t\t\t\tclassName=\"overflow-x-auto p-4 font-mono text-sm [&_pre]:!bg-transparent\"\n\t\t\t\t// biome-ignore lint/security/noDangerouslySetInnerHtml: Shiki output is trusted server-rendered HTML\n\t\t\t\tdangerouslySetInnerHTML={{ __html: html }}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\nexport { CodeBlock };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/code-block/code-block.tsx"],"names":[],"mappings":"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","file":"code-block.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 { cache } from \"react\";\nimport { codeToHtml } from \"shiki\";\nimport { cn } from \"../../lib/utils.js\";\nimport { CodeBlockCopy } from \"./code-block-copy.js\";\n\n/**\n * Languages we surface in the prop type. Plain literal union of real\n * Shiki grammar IDs — kept literal (not `Extract<BundledLanguage, …>`)\n * because Shiki's full bundled-language union is 600+ literals, and\n * deriving from it forced the rollup-dts pass past a 4GB heap. The\n * literals here are all standard Shiki grammar IDs; if Shiki removes\n * one upstream, `codeToHtml` will throw at runtime — acceptable trade.\n */\nexport type SupportedLang =\n\t| \"bash\"\n\t| \"ts\"\n\t| \"tsx\"\n\t| \"js\"\n\t| \"jsx\"\n\t| \"json\"\n\t| \"css\"\n\t| \"html\"\n\t| \"md\"\n\t| \"py\"\n\t| \"text\";\n\nconst LABEL_TO_LANG: Record<string, SupportedLang> = {\n\tpnpm: \"bash\",\n\tnpm: \"bash\",\n\tyarn: \"bash\",\n\tbun: \"bash\",\n\tbash: \"bash\",\n\tsh: \"bash\",\n\tshell: \"bash\",\n\tzsh: \"bash\",\n\tts: \"ts\",\n\ttypescript: \"ts\",\n\ttsx: \"tsx\",\n\tjs: \"js\",\n\tjavascript: \"js\",\n\tjsx: \"jsx\",\n\tjson: \"json\",\n\tcss: \"css\",\n\thtml: \"html\",\n\tmd: \"md\",\n\tmarkdown: \"md\",\n\tpy: \"py\",\n\tpython: \"py\",\n\ttext: \"text\",\n\tprompt: \"text\",\n\tplain: \"text\",\n};\n\nconst DEFAULT_THEMES = { light: \"github-light-high-contrast\", dark: \"github-dark\" } as const;\n\n/**\n * Per-render-tree memoization of `codeToHtml`. React's `cache()` dedupes\n * identical (code, lang, theme) combos within a single RSC render pass —\n * useful when a page renders many copies of the same install snippet.\n * Shiki itself caches grammars/themes per process, so this layer only\n * eliminates duplicate parse + tokenize work within one request.\n */\nconst cachedCodeToHtml = cache(\n\tasync (code: string, lang: SupportedLang, themesKey: string, themes: { light: string; dark: string }) => {\n\t\tvoid themesKey;\n\t\treturn codeToHtml(code, { lang, themes, defaultColor: false });\n\t},\n);\n\nfunction resolveLang(label?: string, language?: SupportedLang): SupportedLang {\n\tif (language) return language;\n\tif (label) {\n\t\tconst fromLabel = LABEL_TO_LANG[label.toLowerCase()];\n\t\tif (fromLabel) return fromLabel;\n\t}\n\treturn \"text\";\n}\n\n/**\n * Syntax-highlighted code block with a language-label header and a copy\n * button. Highlighting runs server-side via Shiki using a dual-theme\n * (default: github-light / github-dark) so the same HTML flips on\n * `data-theme`/`prefers-color-scheme` without client-side rehydration.\n *\n * Async Server Component — render inside RSC trees or pre-render in\n * static contexts. For client-side streaming code blocks, plug Streamdown's\n * built-in code rendering via `Markdown components={{ pre: … }}` instead.\n *\n * @example\n * <CodeBlock label=\"pnpm\" code=\"pnpm add @hex-core/components\" />\n * @example\n * <CodeBlock language=\"tsx\" code={src} />\n */\nexport interface CodeBlockProps {\n\tcode: string;\n\t/** Optional header label (e.g. \"pnpm\", \"tsx\"). Inferred from `language` if omitted. */\n\tlabel?: string;\n\t/** Explicit Shiki grammar key. Overrides inference from `label`. */\n\tlanguage?: SupportedLang;\n\t/** Override the default github-light / github-dark theme pair. */\n\tthemes?: { light: string; dark: string };\n\tclassName?: string;\n}\n\n/**\n * Async Server Component that highlights `code` server-side and emits the\n * resulting HTML with a header + copy island.\n *\n * @param props - code, optional label/language/themes\n * @returns A bordered card wrapping the highlighted code\n */\nasync function CodeBlock({\n\tcode,\n\tlabel,\n\tlanguage,\n\tthemes = DEFAULT_THEMES,\n\tclassName,\n}: CodeBlockProps) {\n\tconst lang = resolveLang(label, language);\n\tconst themesKey = `${themes.light}|${themes.dark}`;\n\tconst html = await cachedCodeToHtml(code, lang, themesKey, themes);\n\tconst displayLabel = label ?? lang;\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"group relative overflow-hidden rounded-lg border bg-card text-card-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<div className=\"flex items-center justify-between border-b bg-muted/40 px-3 py-1.5\">\n\t\t\t\t<span className=\"font-mono text-xs font-medium text-muted-foreground\">{displayLabel}</span>\n\t\t\t\t<CodeBlockCopy code={code} />\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tdata-shiki=\"\"\n\t\t\t\tclassName=\"overflow-x-auto p-4 font-mono text-sm [&_pre]:!bg-transparent\"\n\t\t\t\t// biome-ignore lint/security/noDangerouslySetInnerHtml: Shiki output is trusted server-rendered HTML\n\t\t\t\tdangerouslySetInnerHTML={{ __html: html }}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\nexport { CodeBlock };\n"]}
|
package/dist/color-picker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/lib/color.ts","../src/primitives/input/input.tsx","../src/primitives/label/label.tsx","../src/primitives/slider/slider.tsx","../src/components/popover/popover.tsx","../src/components/color-picker/color-picker.tsx"],"names":["React","React2","jsx","React3","React4","jsxs"],"mappings":"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","file":"color-picker.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","/**\n * Color conversion utilities for the HSL-triplet token format used across\n * `@hex-core/tokens` themes (`H S% L%`, e.g. `\"240 5.9% 10%\"` — no `hsl()`\n * wrapper, no commas).\n *\n * The triplet is the round-trip-safe serialization for Hex Core: tokens flow\n * triplet → CSS `hsl(var(--token))` → rendered color, and the ColorPicker\n * component edits triplets directly. Hex/RGB conversions are display\n * adapters, not the source of truth.\n */\n\n/** Parsed HSL components. `h` is degrees (0–360); `s` and `l` are percentages (0–100). */\nexport interface HslTriplet {\n\th: number;\n\ts: number;\n\tl: number;\n}\n\n/** Parsed RGB components. Each channel is 0–255. */\nexport interface RgbColor {\n\tr: number;\n\tg: number;\n\tb: number;\n}\n\n/**\n * Parse an HSL triplet string into numeric components.\n *\n * Note: malformed input silently coerces to `{0,0,0}` (pure black) rather than\n * returning an error signal. Callers that need to distinguish \"user typed\n * black\" from \"user typed garbage\" should validate the input format first.\n * `hexToHslTriplet` returns `null` for malformed hex; this asymmetry is\n * intentional — triplets feed CSS variables where any non-color value would\n * already break rendering.\n *\n * @param triplet - String in the form `\"<H> <S>% <L>%\"` (e.g. `\"240 5.9% 10%\"`).\n * @returns Numeric components, or `{0,0,0}` if the input is malformed.\n */\nexport function parseHslTriplet(triplet: string): HslTriplet {\n\tconst parts = triplet.trim().split(/\\s+/);\n\treturn {\n\t\th: Number.parseFloat(parts[0]) || 0,\n\t\ts: Number.parseFloat(parts[1]) || 0,\n\t\tl: Number.parseFloat(parts[2]) || 0,\n\t};\n}\n\n/**\n * Format HSL components into an HSL triplet string (the canonical token format).\n * @param hsl - Numeric components.\n * @returns Triplet in the form `\"<H> <S>% <L>%\"`.\n */\nexport function formatHslTriplet({ h, s, l }: HslTriplet): string {\n\t// Tolerant integer check: rgbToHsl can produce values like 5.0000000001 due\n\t// to float arithmetic; format those as \"5\" rather than \"5.0\".\n\tconst round = (n: number) =>\n\t\tMath.abs(n - Math.round(n)) < 1e-6 ? `${Math.round(n)}` : n.toFixed(1);\n\treturn `${Math.round(h)} ${round(s)}% ${round(l)}%`;\n}\n\n/**\n * Convert HSL components to RGB.\n * @param h - Hue (0–360).\n * @param s - Saturation (0–100).\n * @param l - Lightness (0–100).\n * @returns RGB channels (0–255, rounded).\n */\nexport function hslToRgb(h: number, s: number, l: number): RgbColor {\n\tconst sN = s / 100;\n\tconst lN = l / 100;\n\tconst k = (n: number) => (n + h / 30) % 12;\n\tconst a = sN * Math.min(lN, 1 - lN);\n\tconst f = (n: number) => lN - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1));\n\treturn {\n\t\tr: Math.round(255 * f(0)),\n\t\tg: Math.round(255 * f(8)),\n\t\tb: Math.round(255 * f(4)),\n\t};\n}\n\n/**\n * Convert RGB components to HSL.\n * @param r - Red (0–255).\n * @param g - Green (0–255).\n * @param b - Blue (0–255).\n * @returns HSL components (h: 0–360, s: 0–100, l: 0–100).\n */\nexport function rgbToHsl(r: number, g: number, b: number): HslTriplet {\n\tconst rN = r / 255;\n\tconst gN = g / 255;\n\tconst bN = b / 255;\n\tconst max = Math.max(rN, gN, bN);\n\tconst min = Math.min(rN, gN, bN);\n\tlet h = 0;\n\tlet s = 0;\n\tconst l = (max + min) / 2;\n\tif (max !== min) {\n\t\tconst d = max - min;\n\t\ts = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\t\tif (max === rN) h = (gN - bN) / d + (gN < bN ? 6 : 0);\n\t\telse if (max === gN) h = (bN - rN) / d + 2;\n\t\telse h = (rN - gN) / d + 4;\n\t\th /= 6;\n\t}\n\treturn { h: h * 360, s: s * 100, l: l * 100 };\n}\n\n/**\n * Convert an HSL triplet to a 6-digit hex string.\n * @param triplet - HSL triplet (e.g. `\"240 5.9% 10%\"`).\n * @returns Lowercase hex string with leading `#` (e.g. `\"#181a1f\"`).\n */\nexport function hslTripletToHex(triplet: string): string {\n\tconst { h, s, l } = parseHslTriplet(triplet);\n\tconst { r, g, b } = hslToRgb(h, s, l);\n\tconst toHex = (n: number) => n.toString(16).padStart(2, \"0\");\n\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n}\n\n/**\n * Convert a hex string to an HSL triplet.\n * Accepts 3-digit (`#abc`) or 6-digit (`#aabbcc`) hex with optional `#`.\n * @param hex - Hex color string.\n * @returns HSL triplet, or `null` if the input is malformed.\n */\nexport function hexToHslTriplet(hex: string): string | null {\n\tconst clean = hex.trim().replace(/^#/, \"\");\n\tlet normalized: string;\n\tif (/^[0-9a-fA-F]{3}$/.test(clean)) {\n\t\tnormalized = clean\n\t\t\t.split(\"\")\n\t\t\t.map((c) => c + c)\n\t\t\t.join(\"\");\n\t} else if (/^[0-9a-fA-F]{6}$/.test(clean)) {\n\t\tnormalized = clean;\n\t} else {\n\t\treturn null;\n\t}\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn formatHslTriplet(rgbToHsl(r, g, b));\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nexport type InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n\t({ className, type, ...props }, ref) => {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype={type}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex h-[var(--control-height-md,2.5rem)] w-full rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t// inset-ring gives a self-borne edge so the input field is visible on flat\n\t\t\t\t\t// surfaces (token border alone is too low-contrast on bg-background=white).\n\t\t\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\t\t\"file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground\",\n\t\t\t\t\t\"placeholder:text-muted-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\t\"focus-visible:shadow-md focus-visible:border-ring/50\",\n\t\t\t\t\t\"hover:border-ring/30 hover:shadow-md\",\n\t\t\t\t\t\"disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n","\"use client\";\n\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nconst labelVariants = cva(\n\t\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n);\n\nexport interface LabelProps\n\textends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>,\n\t\tVariantProps<typeof labelVariants> {}\n\nconst Label = React.forwardRef<React.ComponentRef<typeof LabelPrimitive.Root>, LabelProps>(\n\t({ className, ...props }, ref) => (\n\t\t<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />\n\t),\n);\nLabel.displayName = \"Label\";\n\nexport { Label };\n","\"use client\";\n\nimport * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n// Local ambient — components run in browsers where bundlers (Next, Vite, tsup)\n// replace `process.env.NODE_ENV` at build time. Avoids pulling @types/node into\n// the components package just for one dev-mode warning.\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\n\ninterface SliderProps\n\textends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {\n\t/**\n\t * Per-thumb accessible labels. When the slider has multiple thumbs, pass\n\t * one entry per thumb (e.g. [\"Minimum\", \"Maximum\"]). For a single-thumb\n\t * slider, the Root's `aria-label` / `aria-labelledby` is mirrored onto\n\t * the thumb automatically — pass `thumbLabels` only when those defaults\n\t * are insufficient.\n\t */\n\tthumbLabels?: string[];\n}\n\n/**\n * A range input with one or more draggable thumbs.\n * Built on Radix UI Slider with keyboard controls (arrows, Home, End, PageUp/Down).\n */\nconst Slider = React.forwardRef<\n\tReact.ComponentRef<typeof SliderPrimitive.Root>,\n\tSliderProps\n>(({ className, thumbLabels, ...props }, ref) => {\n\tconst values = props.value ?? props.defaultValue ?? [0];\n\tconst rootLabel = props[\"aria-label\"];\n\tconst rootLabelledBy = props[\"aria-labelledby\"];\n\n\tif (\n\t\ttypeof process !== \"undefined\" &&\n\t\tprocess.env?.NODE_ENV !== \"production\" &&\n\t\tthumbLabels &&\n\t\tthumbLabels.length !== values.length\n\t) {\n\t\tconsole.warn(\n\t\t\t`Slider: thumbLabels.length (${thumbLabels.length}) does not match value.length (${values.length}). ` +\n\t\t\t\t`Missing labels fall back to indexed names; extra labels are ignored.`,\n\t\t);\n\t}\n\n\treturn (\n\t\t<SliderPrimitive.Root\n\t\t\tref={ref}\n\t\t\tclassName={cn(\"relative flex w-full touch-none select-none items-center\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<SliderPrimitive.Track className=\"relative h-2 w-full grow overflow-hidden rounded-full border border-foreground/[0.08] bg-secondary\">\n\t\t\t\t<SliderPrimitive.Range className=\"absolute h-full bg-primary\" />\n\t\t\t</SliderPrimitive.Track>\n\t\t\t{values.map((_, i) => {\n\t\t\t\tconst explicit = thumbLabels?.[i];\n\t\t\t\tconst fallback =\n\t\t\t\t\tvalues.length === 1\n\t\t\t\t\t\t? rootLabel\n\t\t\t\t\t\t: rootLabel\n\t\t\t\t\t\t\t? `${rootLabel} (${i + 1} of ${values.length})`\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\treturn (\n\t\t\t\t\t<SliderPrimitive.Thumb\n\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: Radix renders one thumb per value by index\n\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\taria-label={explicit ?? fallback}\n\t\t\t\t\t\taria-labelledby={\n\t\t\t\t\t\t\texplicit || fallback ? undefined : rootLabelledBy\n\t\t\t\t\t\t}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"block h-5 w-5 rounded-full border-2 border-primary bg-background\",\n\t\t\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out shadow-md\",\n\t\t\t\t\t\t\t\"hover:shadow-lg hover:scale-110\",\n\t\t\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\t\t\t\"disabled:pointer-events-none disabled:opacity-50\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t);\n\t\t\t})}\n\t\t</SliderPrimitive.Root>\n\t);\n});\nSlider.displayName = \"Slider\";\n\nexport type { SliderProps };\n\nexport { Slider };\n","\"use client\";\n\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a popover. */\nconst Popover = PopoverPrimitive.Root;\n\n/** The element that anchors and opens the popover. */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** Helper to explicitly anchor the popover to a different element. */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/** The floating popover content panel. */\nconst PopoverContent = React.forwardRef<\n\tReact.ComponentRef<typeof PopoverPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => (\n\t<PopoverPrimitive.Portal>\n\t\t<PopoverPrimitive.Content\n\t\t\tref={ref}\n\t\t\talign={align}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 w-72 rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-4,1rem)] text-popover-foreground shadow-md outline-none\",\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\t\"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = \"PopoverContent\";\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport {\n\tformatHslTriplet,\n\thexToHslTriplet,\n\thslTripletToHex,\n\tparseHslTriplet,\n} from \"../../lib/color.js\";\nimport { Input } from \"../../primitives/input/input.js\";\nimport { Label } from \"../../primitives/label/label.js\";\nimport { Slider } from \"../../primitives/slider/slider.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../popover/popover.js\";\n\n/** Tolerance for treating a float as integer-valued (handles arithmetic drift in HSL roundtrips). */\nconst INTEGER_EPSILON = 1e-6;\n\nconst looksInteger = (n: number) => Math.abs(n - Math.round(n)) < INTEGER_EPSILON;\n\n/** Props for the ColorPicker component. */\nexport interface ColorPickerProps {\n\t/**\n\t * Current color as an HSL triplet string (`\"<H> <S>% <L>%\"`, e.g. `\"240 5.9% 10%\"`).\n\t * Match the format used by `@hex-core/tokens`; round-trip safe.\n\t */\n\tvalue: string;\n\t/**\n\t * Called with the next HSL triplet whenever the user drags a slider or commits a valid hex value.\n\t * Not called for invalid hex input — the picker keeps the prior value until the input parses cleanly.\n\t */\n\tonChange: (value: string) => void;\n\t/**\n\t * Disable interaction. Native `disabled` attribute is set on the trigger so the\n\t * popover doesn't open via mouse or keyboard activation. Tab focus still lands\n\t * on the trigger per browser defaults; if you want to fully remove it from the\n\t * tab order, wrap in a parent that handles `tabIndex` accordingly.\n\t */\n\tdisabled?: boolean;\n\t/** Accessible name for the trigger button (defaults to \"Pick color\"). */\n\t\"aria-label\"?: string;\n\t/** Additional class names merged onto the trigger. */\n\tclassName?: string;\n}\n\n/**\n * HSL-native color picker. Edits an HSL triplet directly via three sliders\n * (H/S/L), with a hex input as a display adapter.\n *\n * Round-trip safe: triplet → hex → triplet preserves the slider state because\n * sliders are the source of truth and hex updates them only when valid.\n *\n * @param props - Controlled component; `value` and `onChange` are required.\n * @returns A trigger button that opens a popover with H/S/L sliders + hex input.\n * @example\n * ```tsx\n * const [color, setColor] = React.useState(\"240 5.9% 10%\");\n * <ColorPicker value={color} onChange={setColor} aria-label=\"Primary color\" />\n * ```\n */\nfunction ColorPicker({\n\tvalue,\n\tonChange,\n\tdisabled,\n\t\"aria-label\": ariaLabel = \"Pick color\",\n\tclassName,\n}: ColorPickerProps) {\n\t// Memoize so the slider-row callbacks below are stable across renders with\n\t// the same `value`; downstream `Slider`s avoid spurious re-mounts.\n\tconst hsl = React.useMemo(() => parseHslTriplet(value), [value]);\n\tconst hex = React.useMemo(() => hslTripletToHex(value), [value]);\n\n\tconst update = React.useCallback(\n\t\t(patch: Partial<typeof hsl>) => {\n\t\t\tonChange(formatHslTriplet({ ...hsl, ...patch }));\n\t\t},\n\t\t[hsl, onChange],\n\t);\n\n\t// Hex input is locally controlled so the user can type intermediate states\n\t// (e.g. \"#1a\") without committing. Sync the buffer to the canonical hex\n\t// whenever the input is NOT focused — typing into a focused input must not\n\t// be clobbered by a parent re-render reflecting our own `onChange`.\n\tconst hexInputRef = React.useRef<HTMLInputElement>(null);\n\tconst [hexBuffer, setHexBuffer] = React.useState(hex);\n\tReact.useEffect(() => {\n\t\tif (\n\t\t\ttypeof document === \"undefined\" ||\n\t\t\tdocument.activeElement !== hexInputRef.current\n\t\t) {\n\t\t\tsetHexBuffer(hex);\n\t\t}\n\t}, [hex]);\n\n\tconst handleHexChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst next = e.target.value;\n\t\tsetHexBuffer(next);\n\t\tconst triplet = hexToHslTriplet(next);\n\t\tif (triplet !== null) onChange(triplet);\n\t};\n\n\tconst hexId = React.useId();\n\n\treturn (\n\t\t<Popover>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\taria-label={ariaLabel}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"inline-flex h-9 items-center gap-2 rounded-md border border-input bg-background px-3 text-sm shadow-sm\",\n\t\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\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\t\t\"hover:shadow-md disabled:pointer-events-none disabled:opacity-50\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclassName=\"h-5 w-5 rounded-sm border border-border\"\n\t\t\t\t\t\tstyle={{ backgroundColor: `hsl(${value})` }}\n\t\t\t\t\t/>\n\t\t\t\t\t<span className=\"font-mono text-xs uppercase\">{hex}</span>\n\t\t\t\t</button>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent className=\"w-72 p-4\" align=\"start\">\n\t\t\t\t<div className=\"space-y-4\">\n\t\t\t\t\t<SliderRow\n\t\t\t\t\t\tlabel=\"Hue\"\n\t\t\t\t\t\tsuffix=\"°\"\n\t\t\t\t\t\tvalue={hsl.h}\n\t\t\t\t\t\tmax={360}\n\t\t\t\t\t\tstep={1}\n\t\t\t\t\t\tonChange={(h) => update({ h })}\n\t\t\t\t\t/>\n\t\t\t\t\t<SliderRow\n\t\t\t\t\t\tlabel=\"Saturation\"\n\t\t\t\t\t\tsuffix=\"%\"\n\t\t\t\t\t\tvalue={hsl.s}\n\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\tstep={0.1}\n\t\t\t\t\t\tonChange={(s) => update({ s })}\n\t\t\t\t\t/>\n\t\t\t\t\t<SliderRow\n\t\t\t\t\t\tlabel=\"Lightness\"\n\t\t\t\t\t\tsuffix=\"%\"\n\t\t\t\t\t\tvalue={hsl.l}\n\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\tstep={0.1}\n\t\t\t\t\t\tonChange={(l) => update({ l })}\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"flex items-end gap-2\">\n\t\t\t\t\t\t<div className=\"flex-1 space-y-1\">\n\t\t\t\t\t\t\t<Label htmlFor={hexId} className=\"text-xs\">\n\t\t\t\t\t\t\t\tHex\n\t\t\t\t\t\t\t</Label>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid={hexId}\n\t\t\t\t\t\t\t\tref={hexInputRef}\n\t\t\t\t\t\t\t\tvalue={hexBuffer}\n\t\t\t\t\t\t\t\tonChange={handleHexChange}\n\t\t\t\t\t\t\t\tclassName=\"font-mono text-xs uppercase\"\n\t\t\t\t\t\t\t\tspellCheck={false}\n\t\t\t\t\t\t\t\tautoComplete=\"off\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tclassName=\"h-9 w-9 shrink-0 rounded-md border border-border\"\n\t\t\t\t\t\t\tstyle={{ backgroundColor: `hsl(${value})` }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\n\ninterface SliderRowProps {\n\tlabel: string;\n\tsuffix: string;\n\tvalue: number;\n\tmax: number;\n\tstep: number;\n\tonChange: (next: number) => void;\n}\n\n/**\n * One labeled slider row inside the ColorPicker popover. Internal helper —\n * not exported.\n * @param props - Slider config + value-change callback.\n */\nfunction SliderRow({ label, suffix, value, max, step, onChange }: SliderRowProps) {\n\tconst display = looksInteger(value) ? `${Math.round(value)}` : value.toFixed(1);\n\treturn (\n\t\t<div className=\"space-y-1.5\">\n\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t<Label className=\"text-xs\">{label}</Label>\n\t\t\t\t<span className=\"font-mono text-xs tabular-nums text-muted-foreground\">\n\t\t\t\t\t{display}\n\t\t\t\t\t{suffix}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<Slider\n\t\t\t\tvalue={[value]}\n\t\t\t\tmin={0}\n\t\t\t\tmax={max}\n\t\t\t\tstep={step}\n\t\t\t\taria-label={label}\n\t\t\t\tonValueChange={(values) => onChange(values[0] ?? 0)}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\nexport { ColorPicker };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/lib/color.ts","../src/primitives/input/input.tsx","../src/primitives/label/label.tsx","../src/primitives/slider/slider.tsx","../src/components/popover/popover.tsx","../src/components/color-picker/color-picker.tsx"],"names":["React","React2","jsx","React3","React4","jsxs"],"mappings":"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","file":"color-picker.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","/**\n * Color conversion utilities for the HSL-triplet token format used across\n * `@hex-core/tokens` themes (`H S% L%`, e.g. `\"240 5.9% 10%\"` — no `hsl()`\n * wrapper, no commas).\n *\n * The triplet is the round-trip-safe serialization for Hex Core: tokens flow\n * triplet → CSS `hsl(var(--token))` → rendered color, and the ColorPicker\n * component edits triplets directly. Hex/RGB conversions are display\n * adapters, not the source of truth.\n */\n\n/** Parsed HSL components. `h` is degrees (0–360); `s` and `l` are percentages (0–100). */\nexport interface HslTriplet {\n\th: number;\n\ts: number;\n\tl: number;\n}\n\n/** Parsed RGB components. Each channel is 0–255. */\nexport interface RgbColor {\n\tr: number;\n\tg: number;\n\tb: number;\n}\n\n/**\n * Parse an HSL triplet string into numeric components.\n *\n * Note: malformed input silently coerces to `{0,0,0}` (pure black) rather than\n * returning an error signal. Callers that need to distinguish \"user typed\n * black\" from \"user typed garbage\" should validate the input format first.\n * `hexToHslTriplet` returns `null` for malformed hex; this asymmetry is\n * intentional — triplets feed CSS variables where any non-color value would\n * already break rendering.\n *\n * @param triplet - String in the form `\"<H> <S>% <L>%\"` (e.g. `\"240 5.9% 10%\"`).\n * @returns Numeric components, or `{0,0,0}` if the input is malformed.\n */\nexport function parseHslTriplet(triplet: string): HslTriplet {\n\tconst parts = triplet.trim().split(/\\s+/);\n\treturn {\n\t\th: Number.parseFloat(parts[0]) || 0,\n\t\ts: Number.parseFloat(parts[1]) || 0,\n\t\tl: Number.parseFloat(parts[2]) || 0,\n\t};\n}\n\n/**\n * Format HSL components into an HSL triplet string (the canonical token format).\n * @param hsl - Numeric components.\n * @returns Triplet in the form `\"<H> <S>% <L>%\"`.\n */\nexport function formatHslTriplet({ h, s, l }: HslTriplet): string {\n\t// Tolerant integer check: rgbToHsl can produce values like 5.0000000001 due\n\t// to float arithmetic; format those as \"5\" rather than \"5.0\".\n\tconst round = (n: number) =>\n\t\tMath.abs(n - Math.round(n)) < 1e-6 ? `${Math.round(n)}` : n.toFixed(1);\n\treturn `${Math.round(h)} ${round(s)}% ${round(l)}%`;\n}\n\n/**\n * Convert HSL components to RGB.\n * @param h - Hue (0–360).\n * @param s - Saturation (0–100).\n * @param l - Lightness (0–100).\n * @returns RGB channels (0–255, rounded).\n */\nexport function hslToRgb(h: number, s: number, l: number): RgbColor {\n\tconst sN = s / 100;\n\tconst lN = l / 100;\n\tconst k = (n: number) => (n + h / 30) % 12;\n\tconst a = sN * Math.min(lN, 1 - lN);\n\tconst f = (n: number) => lN - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1));\n\treturn {\n\t\tr: Math.round(255 * f(0)),\n\t\tg: Math.round(255 * f(8)),\n\t\tb: Math.round(255 * f(4)),\n\t};\n}\n\n/**\n * Convert RGB components to HSL.\n * @param r - Red (0–255).\n * @param g - Green (0–255).\n * @param b - Blue (0–255).\n * @returns HSL components (h: 0–360, s: 0–100, l: 0–100).\n */\nexport function rgbToHsl(r: number, g: number, b: number): HslTriplet {\n\tconst rN = r / 255;\n\tconst gN = g / 255;\n\tconst bN = b / 255;\n\tconst max = Math.max(rN, gN, bN);\n\tconst min = Math.min(rN, gN, bN);\n\tlet h = 0;\n\tlet s = 0;\n\tconst l = (max + min) / 2;\n\tif (max !== min) {\n\t\tconst d = max - min;\n\t\ts = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\t\tif (max === rN) h = (gN - bN) / d + (gN < bN ? 6 : 0);\n\t\telse if (max === gN) h = (bN - rN) / d + 2;\n\t\telse h = (rN - gN) / d + 4;\n\t\th /= 6;\n\t}\n\treturn { h: h * 360, s: s * 100, l: l * 100 };\n}\n\n/**\n * Convert an HSL triplet to a 6-digit hex string.\n * @param triplet - HSL triplet (e.g. `\"240 5.9% 10%\"`).\n * @returns Lowercase hex string with leading `#` (e.g. `\"#181a1f\"`).\n */\nexport function hslTripletToHex(triplet: string): string {\n\tconst { h, s, l } = parseHslTriplet(triplet);\n\tconst { r, g, b } = hslToRgb(h, s, l);\n\tconst toHex = (n: number) => n.toString(16).padStart(2, \"0\");\n\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n}\n\n/**\n * Convert a hex string to an HSL triplet.\n * Accepts 3-digit (`#abc`) or 6-digit (`#aabbcc`) hex with optional `#`.\n * @param hex - Hex color string.\n * @returns HSL triplet, or `null` if the input is malformed.\n */\nexport function hexToHslTriplet(hex: string): string | null {\n\tconst clean = hex.trim().replace(/^#/, \"\");\n\tlet normalized: string;\n\tif (/^[0-9a-fA-F]{3}$/.test(clean)) {\n\t\tnormalized = clean\n\t\t\t.split(\"\")\n\t\t\t.map((c) => c + c)\n\t\t\t.join(\"\");\n\t} else if (/^[0-9a-fA-F]{6}$/.test(clean)) {\n\t\tnormalized = clean;\n\t} else {\n\t\treturn null;\n\t}\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn formatHslTriplet(rgbToHsl(r, g, b));\n}\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nexport type InputProps = React.InputHTMLAttributes<HTMLInputElement>;\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n\t({ className, type, ...props }, ref) => {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype={type}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex h-[var(--control-height-md,2.5rem)] w-full rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t// inset-ring gives a self-borne edge so the input field is visible on flat\n\t\t\t\t\t// surfaces (token border alone is too low-contrast on bg-background=white).\n\t\t\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\t\t\"file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground\",\n\t\t\t\t\t\"placeholder:text-muted-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\t\"focus-visible:shadow-md focus-visible:border-ring/50\",\n\t\t\t\t\t\"hover:border-ring/30 hover:shadow-md\",\n\t\t\t\t\t\"disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n","\"use client\";\n\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\nconst labelVariants = cva(\n\t\"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n);\n\nexport interface LabelProps\n\textends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>,\n\t\tVariantProps<typeof labelVariants> {}\n\nconst Label = React.forwardRef<React.ComponentRef<typeof LabelPrimitive.Root>, LabelProps>(\n\t({ className, ...props }, ref) => (\n\t\t<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />\n\t),\n);\nLabel.displayName = \"Label\";\n\nexport { Label };\n","\"use client\";\n\nimport * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n// Local ambient — components run in browsers where bundlers (Next, Vite, tsup)\n// replace `process.env.NODE_ENV` at build time. Avoids pulling @types/node into\n// the components package just for one dev-mode warning.\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\n\ninterface SliderProps\n\textends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {\n\t/**\n\t * Per-thumb accessible labels. When the slider has multiple thumbs, pass\n\t * one entry per thumb (e.g. [\"Minimum\", \"Maximum\"]). For a single-thumb\n\t * slider, the Root's `aria-label` / `aria-labelledby` is mirrored onto\n\t * the thumb automatically — pass `thumbLabels` only when those defaults\n\t * are insufficient.\n\t */\n\tthumbLabels?: string[];\n}\n\n/**\n * A range input with one or more draggable thumbs.\n * Built on Radix UI Slider with keyboard controls (arrows, Home, End, PageUp/Down).\n */\nconst Slider = React.forwardRef<\n\tReact.ComponentRef<typeof SliderPrimitive.Root>,\n\tSliderProps\n>(({ className, thumbLabels, ...props }, ref) => {\n\tconst values = props.value ?? props.defaultValue ?? [0];\n\tconst rootLabel = props[\"aria-label\"];\n\tconst rootLabelledBy = props[\"aria-labelledby\"];\n\n\tif (\n\t\ttypeof process !== \"undefined\" &&\n\t\tprocess.env?.NODE_ENV !== \"production\" &&\n\t\tthumbLabels &&\n\t\tthumbLabels.length !== values.length\n\t) {\n\t\tconsole.warn(\n\t\t\t`Slider: thumbLabels.length (${thumbLabels.length}) does not match value.length (${values.length}). ` +\n\t\t\t\t`Missing labels fall back to indexed names; extra labels are ignored.`,\n\t\t);\n\t}\n\n\treturn (\n\t\t<SliderPrimitive.Root\n\t\t\tref={ref}\n\t\t\tclassName={cn(\"relative flex w-full touch-none select-none items-center\", className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<SliderPrimitive.Track className=\"relative h-2 w-full grow overflow-hidden rounded-full border border-foreground/[0.08] bg-secondary\">\n\t\t\t\t<SliderPrimitive.Range className=\"absolute h-full bg-primary\" />\n\t\t\t</SliderPrimitive.Track>\n\t\t\t{values.map((_, i) => {\n\t\t\t\tconst explicit = thumbLabels?.[i];\n\t\t\t\tconst fallback =\n\t\t\t\t\tvalues.length === 1\n\t\t\t\t\t\t? rootLabel\n\t\t\t\t\t\t: rootLabel\n\t\t\t\t\t\t\t? `${rootLabel} (${i + 1} of ${values.length})`\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\treturn (\n\t\t\t\t\t<SliderPrimitive.Thumb\n\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: Radix renders one thumb per value by index\n\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\taria-label={explicit ?? fallback}\n\t\t\t\t\t\taria-labelledby={\n\t\t\t\t\t\t\texplicit || fallback ? undefined : rootLabelledBy\n\t\t\t\t\t\t}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"block h-5 w-5 rounded-full border-2 border-primary bg-background\",\n\t\t\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out shadow-md\",\n\t\t\t\t\t\t\t\"hover:shadow-lg hover:scale-110\",\n\t\t\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\t\t\t\"disabled:pointer-events-none disabled:opacity-50\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t);\n\t\t\t})}\n\t\t</SliderPrimitive.Root>\n\t);\n});\nSlider.displayName = \"Slider\";\n\nexport type { SliderProps };\n\nexport { Slider };\n","\"use client\";\n\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a popover. */\nconst Popover = PopoverPrimitive.Root;\n\n/** The element that anchors and opens the popover. */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** Helper to explicitly anchor the popover to a different element. */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/** The floating popover content panel. */\nconst PopoverContent = React.forwardRef<\n\tReact.ComponentRef<typeof PopoverPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => (\n\t<PopoverPrimitive.Portal>\n\t\t<PopoverPrimitive.Content\n\t\t\tref={ref}\n\t\t\talign={align}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 w-72 rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-4,1rem)] text-popover-foreground shadow-md outline-none\",\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\t\"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = \"PopoverContent\";\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport {\n\tformatHslTriplet,\n\thexToHslTriplet,\n\thslTripletToHex,\n\tparseHslTriplet,\n} from \"../../lib/color.js\";\nimport { Input } from \"../../primitives/input/input.js\";\nimport { Label } from \"../../primitives/label/label.js\";\nimport { Slider } from \"../../primitives/slider/slider.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../popover/popover.js\";\n\n/** Tolerance for treating a float as integer-valued (handles arithmetic drift in HSL roundtrips). */\nconst INTEGER_EPSILON = 1e-6;\n\nconst looksInteger = (n: number) => Math.abs(n - Math.round(n)) < INTEGER_EPSILON;\n\n/** Props for the ColorPicker component. */\nexport interface ColorPickerProps {\n\t/**\n\t * Current color as an HSL triplet string (`\"<H> <S>% <L>%\"`, e.g. `\"240 5.9% 10%\"`).\n\t * Match the format used by `@hex-core/tokens`; round-trip safe.\n\t */\n\tvalue: string;\n\t/**\n\t * Called with the next HSL triplet whenever the user drags a slider or commits a valid hex value.\n\t * Not called for invalid hex input — the picker keeps the prior value until the input parses cleanly.\n\t */\n\tonChange: (value: string) => void;\n\t/**\n\t * Disable interaction. Native `disabled` attribute is set on the trigger so the\n\t * popover doesn't open via mouse or keyboard activation. Tab focus still lands\n\t * on the trigger per browser defaults; if you want to fully remove it from the\n\t * tab order, wrap in a parent that handles `tabIndex` accordingly.\n\t */\n\tdisabled?: boolean;\n\t/** Accessible name for the trigger button (defaults to \"Pick color\"). */\n\t\"aria-label\"?: string;\n\t/** Additional class names merged onto the trigger. */\n\tclassName?: string;\n}\n\n/**\n * HSL-native color picker. Edits an HSL triplet directly via three sliders\n * (H/S/L), with a hex input as a display adapter.\n *\n * Round-trip safe: triplet → hex → triplet preserves the slider state because\n * sliders are the source of truth and hex updates them only when valid.\n *\n * @param props - Controlled component; `value` and `onChange` are required.\n * @returns A trigger button that opens a popover with H/S/L sliders + hex input.\n * @example\n * ```tsx\n * const [color, setColor] = React.useState(\"240 5.9% 10%\");\n * <ColorPicker value={color} onChange={setColor} aria-label=\"Primary color\" />\n * ```\n */\nfunction ColorPicker({\n\tvalue,\n\tonChange,\n\tdisabled,\n\t\"aria-label\": ariaLabel = \"Pick color\",\n\tclassName,\n}: ColorPickerProps) {\n\t// Memoize so the slider-row callbacks below are stable across renders with\n\t// the same `value`; downstream `Slider`s avoid spurious re-mounts.\n\tconst hsl = React.useMemo(() => parseHslTriplet(value), [value]);\n\tconst hex = React.useMemo(() => hslTripletToHex(value), [value]);\n\n\tconst update = React.useCallback(\n\t\t(patch: Partial<typeof hsl>) => {\n\t\t\tonChange(formatHslTriplet({ ...hsl, ...patch }));\n\t\t},\n\t\t[hsl, onChange],\n\t);\n\n\t// Hex input is locally controlled so the user can type intermediate states\n\t// (e.g. \"#1a\") without committing. Sync the buffer to the canonical hex\n\t// whenever the input is NOT focused — typing into a focused input must not\n\t// be clobbered by a parent re-render reflecting our own `onChange`.\n\tconst hexInputRef = React.useRef<HTMLInputElement>(null);\n\tconst [hexBuffer, setHexBuffer] = React.useState(hex);\n\tReact.useEffect(() => {\n\t\tif (\n\t\t\ttypeof document === \"undefined\" ||\n\t\t\tdocument.activeElement !== hexInputRef.current\n\t\t) {\n\t\t\tsetHexBuffer(hex);\n\t\t}\n\t}, [hex]);\n\n\tconst handleHexChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst next = e.target.value;\n\t\tsetHexBuffer(next);\n\t\tconst triplet = hexToHslTriplet(next);\n\t\tif (triplet !== null) onChange(triplet);\n\t};\n\n\tconst hexId = React.useId();\n\n\treturn (\n\t\t<Popover>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\taria-label={ariaLabel}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"inline-flex h-9 items-center gap-2 rounded-md border border-input bg-background px-3 text-sm shadow-sm\",\n\t\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\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\t\t\"hover:shadow-md disabled:pointer-events-none disabled:opacity-50\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclassName=\"h-5 w-5 rounded-sm border border-border\"\n\t\t\t\t\t\tstyle={{ backgroundColor: `hsl(${value})` }}\n\t\t\t\t\t/>\n\t\t\t\t\t<span className=\"font-mono text-xs uppercase\">{hex}</span>\n\t\t\t\t</button>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent className=\"w-72 p-4\" align=\"start\">\n\t\t\t\t<div className=\"space-y-4\">\n\t\t\t\t\t<SliderRow\n\t\t\t\t\t\tlabel=\"Hue\"\n\t\t\t\t\t\tsuffix=\"°\"\n\t\t\t\t\t\tvalue={hsl.h}\n\t\t\t\t\t\tmax={360}\n\t\t\t\t\t\tstep={1}\n\t\t\t\t\t\tonChange={(h) => update({ h })}\n\t\t\t\t\t/>\n\t\t\t\t\t<SliderRow\n\t\t\t\t\t\tlabel=\"Saturation\"\n\t\t\t\t\t\tsuffix=\"%\"\n\t\t\t\t\t\tvalue={hsl.s}\n\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\tstep={0.1}\n\t\t\t\t\t\tonChange={(s) => update({ s })}\n\t\t\t\t\t/>\n\t\t\t\t\t<SliderRow\n\t\t\t\t\t\tlabel=\"Lightness\"\n\t\t\t\t\t\tsuffix=\"%\"\n\t\t\t\t\t\tvalue={hsl.l}\n\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\tstep={0.1}\n\t\t\t\t\t\tonChange={(l) => update({ l })}\n\t\t\t\t\t/>\n\t\t\t\t\t<div className=\"flex items-end gap-2\">\n\t\t\t\t\t\t<div className=\"flex-1 space-y-1\">\n\t\t\t\t\t\t\t<Label htmlFor={hexId} className=\"text-xs\">\n\t\t\t\t\t\t\t\tHex\n\t\t\t\t\t\t\t</Label>\n\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\tid={hexId}\n\t\t\t\t\t\t\t\tref={hexInputRef}\n\t\t\t\t\t\t\t\tvalue={hexBuffer}\n\t\t\t\t\t\t\t\tonChange={handleHexChange}\n\t\t\t\t\t\t\t\tclassName=\"font-mono text-xs uppercase\"\n\t\t\t\t\t\t\t\tspellCheck={false}\n\t\t\t\t\t\t\t\tautoComplete=\"off\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tclassName=\"h-9 w-9 shrink-0 rounded-md border border-border\"\n\t\t\t\t\t\t\tstyle={{ backgroundColor: `hsl(${value})` }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\n\ninterface SliderRowProps {\n\tlabel: string;\n\tsuffix: string;\n\tvalue: number;\n\tmax: number;\n\tstep: number;\n\tonChange: (next: number) => void;\n}\n\n/**\n * One labeled slider row inside the ColorPicker popover. Internal helper —\n * not exported.\n * @param props - Slider config + value-change callback.\n */\nfunction SliderRow({ label, suffix, value, max, step, onChange }: SliderRowProps) {\n\tconst display = looksInteger(value) ? `${Math.round(value)}` : value.toFixed(1);\n\treturn (\n\t\t<div className=\"space-y-1.5\">\n\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t<Label className=\"text-xs\">{label}</Label>\n\t\t\t\t<span className=\"font-mono text-xs tabular-nums text-muted-foreground\">\n\t\t\t\t\t{display}\n\t\t\t\t\t{suffix}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<Slider\n\t\t\t\tvalue={[value]}\n\t\t\t\tmin={0}\n\t\t\t\tmax={max}\n\t\t\t\tstep={step}\n\t\t\t\taria-label={label}\n\t\t\t\tonValueChange={(values) => onChange(values[0] ?? 0)}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\nexport { ColorPicker };\n"]}
|
package/dist/combobox.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/command/command.tsx","../src/components/popover/popover.tsx","../src/components/combobox/combobox.tsx"],"names":["CommandPrimitive","React2","jsx","React3","jsxs"],"mappings":"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","file":"combobox.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 { Command as CommandPrimitive } from \"cmdk\";\nimport * as React from \"react\";\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n} from \"../dialog/dialog.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root Command container — drives search, filtering, and keyboard navigation over items. */\nconst Command = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommand.displayName = \"Command\";\n\ninterface CommandDialogProps extends React.ComponentPropsWithoutRef<typeof Dialog> {\n\t/** Command children (CommandInput + CommandList + CommandItem, etc.) */\n\tchildren: React.ReactNode;\n\t/** Accessible title for the dialog (screen-reader only by default). */\n\ttitle?: string;\n\t/** Accessible description for the dialog (screen-reader only by default). */\n\tdescription?: string;\n}\n\n/**\n * Command menu rendered inside a Dialog — a ⌘K-style launcher.\n * @param props - Forwarded to the underlying Dialog (open, onOpenChange, etc.)\n * @returns A Dialog containing a Command menu.\n */\nfunction CommandDialog({\n\ttitle = \"Command Palette\",\n\tdescription = \"Search for a command to run.\",\n\tchildren,\n\t...props\n}: CommandDialogProps) {\n\treturn (\n\t\t<Dialog {...props}>\n\t\t\t<DialogHeader className=\"sr-only\">\n\t\t\t\t<DialogTitle>{title}</DialogTitle>\n\t\t\t\t<DialogDescription>{description}</DialogDescription>\n\t\t\t</DialogHeader>\n\t\t\t<DialogContent className=\"overflow-hidden p-0\" scrollable={false}>\n\t\t\t\t<Command className=\"[&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-[var(--space-2,0.5rem)] [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-[var(--space-2,0.5rem)] [&_[cmdk-item]]:py-[var(--space-3,0.75rem)] [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n\t\t\t\t\t{children}\n\t\t\t\t</Command>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\n/** Search input for the Command menu. Fires onValueChange as the user types. */\nconst CommandInput = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Input>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>\n>(({ className, ...props }, ref) => (\n\t<div className=\"flex items-center border-b border-b-foreground/[0.08] px-[var(--space-3,0.75rem)]\" cmdk-input-wrapper=\"\">\n\t\t<svg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"mr-[var(--space-2,0.5rem)] h-4 w-4 shrink-0 opacity-50\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<circle cx=\"11\" cy=\"11\" r=\"8\" />\n\t\t\t<line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n\t\t</svg>\n\t\t<CommandPrimitive.Input\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"flex h-[var(--control-height-lg,2.75rem)] w-full rounded-md bg-transparent py-[var(--space-3,0.75rem)] text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</div>\n));\nCommandInput.displayName = \"CommandInput\";\n\n/** Scrollable list that contains CommandGroup / CommandItem / CommandEmpty. */\nconst CommandList = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.List>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.List>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.List\n\t\tref={ref}\n\t\tclassName={cn(\"max-h-[300px] overflow-y-auto overflow-x-hidden\", className)}\n\t\t{...props}\n\t/>\n));\nCommandList.displayName = \"CommandList\";\n\n/** Rendered when no items match the current search. */\nconst CommandEmpty = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Empty>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>\n>((props, ref) => (\n\t<CommandPrimitive.Empty ref={ref} className=\"py-[var(--space-6,1.5rem)] text-center text-sm\" {...props} />\n));\nCommandEmpty.displayName = \"CommandEmpty\";\n\n/** Logical group of items — renders a heading and filters as a unit. */\nconst CommandGroup = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Group>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.Group\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"overflow-hidden p-[var(--space-1,0.25rem)] text-foreground [&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommandGroup.displayName = \"CommandGroup\";\n\n/**\n * Horizontal rule between groups. Renders as a presentational `<div>` (no role)\n * so it can sit inside CommandList (role=listbox) without violating ARIA's\n * required-children rule for listbox. The line is purely decorative — cmdk's\n * built-in Separator hardcodes `role=\"separator\"`, which axe rejects in this\n * context, so we render the divider directly.\n *\n * The `data-cmdk-separator` attribute is preserved so existing CSS / test\n * selectors that target cmdk's separator continue to match.\n */\nconst CommandSeparator = React.forwardRef<\n\tHTMLDivElement,\n\tReact.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n\t<div\n\t\tref={ref}\n\t\trole=\"none\"\n\t\tdata-cmdk-separator=\"\"\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nCommandSeparator.displayName = \"CommandSeparator\";\n\n/** Selectable item. onSelect fires on Enter or click. */\nconst CommandItem = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.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 transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n\t\t\t\"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground\",\n\t\t\t\"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommandItem.displayName = \"CommandItem\";\n\n/**\n * Keyboard shortcut hint (e.g. '⌘K') aligned to the right of an item.\n * @returns A muted inline span rendered at the end of a CommandItem.\n */\nfunction CommandShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"ml-auto text-xs tracking-widest text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\nCommandShortcut.displayName = \"CommandShortcut\";\n\nexport {\n\tCommand,\n\tCommandDialog,\n\tCommandInput,\n\tCommandList,\n\tCommandEmpty,\n\tCommandGroup,\n\tCommandItem,\n\tCommandShortcut,\n\tCommandSeparator,\n};\n","\"use client\";\n\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a popover. */\nconst Popover = PopoverPrimitive.Root;\n\n/** The element that anchors and opens the popover. */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** Helper to explicitly anchor the popover to a different element. */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/** The floating popover content panel. */\nconst PopoverContent = React.forwardRef<\n\tReact.ComponentRef<typeof PopoverPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => (\n\t<PopoverPrimitive.Portal>\n\t\t<PopoverPrimitive.Content\n\t\t\tref={ref}\n\t\t\talign={align}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 w-72 rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-4,1rem)] text-popover-foreground shadow-md outline-none\",\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\t\"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = \"PopoverContent\";\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","\"use client\";\n\nimport * as React from \"react\";\nimport {\n\tCommand,\n\tCommandEmpty,\n\tCommandGroup,\n\tCommandInput,\n\tCommandItem,\n\tCommandList,\n} from \"../command/command.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../popover/popover.js\";\nimport { cn } from \"../../lib/utils.js\";\n\ninterface ComboboxOption {\n\t/** The value returned from onChange (stable, unique). */\n\tvalue: string;\n\t/** The display label shown in the list and the trigger. */\n\tlabel: string;\n\t/** Mark as non-selectable. */\n\tdisabled?: boolean;\n}\n\ninterface ComboboxProps {\n\t/** The list of selectable options. */\n\toptions: ComboboxOption[];\n\t/** Controlled selected value. */\n\tvalue?: string;\n\t/** Fired when the user picks an option: (value: string) => void */\n\tonChange?: (value: string) => void;\n\t/** Text shown on the trigger when nothing is selected. */\n\tplaceholder?: string;\n\t/** Input placeholder inside the popover list. */\n\tsearchPlaceholder?: string;\n\t/** Text shown when no options match the search. */\n\temptyText?: string;\n\t/** Disable the trigger. */\n\tdisabled?: boolean;\n\t/** Extra class names on the trigger button. */\n\tclassName?: string;\n\t/** Accessible label for the trigger (required when no adjacent visible label). */\n\t\"aria-label\"?: string;\n\t/** Id of an external visible label that names this combobox. */\n\t\"aria-labelledby\"?: string;\n}\n\n/**\n * Searchable select input built on Command + Popover.\n *\n * Pass `options` with `{ value, label }` shape. The selected label is shown on\n * the trigger; the popover contains a CommandInput and filtered CommandList.\n * @returns A trigger button that opens a filtered option list.\n */\nfunction Combobox({\n\toptions,\n\tvalue,\n\tonChange,\n\tplaceholder = \"Select…\",\n\tsearchPlaceholder = \"Search…\",\n\temptyText = \"No results found.\",\n\tdisabled,\n\tclassName,\n\t\"aria-label\": ariaLabel,\n\t\"aria-labelledby\": ariaLabelledBy,\n}: ComboboxProps) {\n\tconst [open, setOpen] = React.useState(false);\n\tconst listboxId = React.useId();\n\tconst selected = options.find((o) => o.value === value);\n\n\treturn (\n\t\t<Popover open={open} onOpenChange={setOpen}>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\trole=\"combobox\"\n\t\t\t\t\taria-expanded={open}\n\t\t\t\t\taria-haspopup=\"listbox\"\n\t\t\t\t\t/*\n\t\t\t\t\t * Only reference the listbox id when the popover is open.\n\t\t\t\t\t * The CommandList is portal-mounted by Radix Popover and\n\t\t\t\t\t * does not exist in the DOM while closed; pointing at a\n\t\t\t\t\t * missing id confuses some screen readers.\n\t\t\t\t\t */\n\t\t\t\t\taria-controls={open ? listboxId : undefined}\n\t\t\t\t\taria-label={ariaLabel}\n\t\t\t\t\taria-labelledby={ariaLabelledBy}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"inline-flex h-[var(--control-height-md,2.5rem)] w-[240px] items-center justify-between gap-[var(--gap-sm,0.5rem)] rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm font-normal transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\t\t\t\"hover:bg-accent hover:text-accent-foreground\",\n\t\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\t\t\"disabled:pointer-events-none disabled:opacity-50\",\n\t\t\t\t\t\t!selected && \"text-muted-foreground\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"truncate\">{selected ? selected.label : placeholder}</span>\n\t\t\t\t\t<svg\n\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\tclassName=\"h-4 w-4 shrink-0 opacity-50\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<polyline points=\"6 9 12 15 18 9\" />\n\t\t\t\t\t</svg>\n\t\t\t\t</button>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent className=\"w-[240px] p-0\" align=\"start\">\n\t\t\t\t<Command>\n\t\t\t\t\t<CommandInput placeholder={searchPlaceholder} />\n\t\t\t\t\t<CommandList id={listboxId}>\n\t\t\t\t\t\t<CommandEmpty>{emptyText}</CommandEmpty>\n\t\t\t\t\t\t<CommandGroup>\n\t\t\t\t\t\t\t{options.map((option) => (\n\t\t\t\t\t\t\t\t<CommandItem\n\t\t\t\t\t\t\t\t\tkey={option.value}\n\t\t\t\t\t\t\t\t\tvalue={option.label}\n\t\t\t\t\t\t\t\t\tdisabled={option.disabled}\n\t\t\t\t\t\t\t\t\tonSelect={() => {\n\t\t\t\t\t\t\t\t\t\tonChange?.(option.value);\n\t\t\t\t\t\t\t\t\t\tsetOpen(false);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"mr-[var(--space-2,0.5rem)] h-4 w-4\",\n\t\t\t\t\t\t\t\t\t\t\tvalue === option.value ? \"opacity-100\" : \"opacity-0\",\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t</CommandItem>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</CommandGroup>\n\t\t\t\t\t</CommandList>\n\t\t\t\t</Command>\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\nCombobox.displayName = \"Combobox\";\n\nexport { Combobox };\nexport type { ComboboxOption, ComboboxProps };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/command/command.tsx","../src/components/popover/popover.tsx","../src/components/combobox/combobox.tsx"],"names":["CommandPrimitive","React2","jsx","React3","jsxs"],"mappings":"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","file":"combobox.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 { Command as CommandPrimitive } from \"cmdk\";\nimport * as React from \"react\";\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n} from \"../dialog/dialog.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root Command container — drives search, filtering, and keyboard navigation over items. */\nconst Command = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommand.displayName = \"Command\";\n\ninterface CommandDialogProps extends React.ComponentPropsWithoutRef<typeof Dialog> {\n\t/** Command children (CommandInput + CommandList + CommandItem, etc.) */\n\tchildren: React.ReactNode;\n\t/** Accessible title for the dialog (screen-reader only by default). */\n\ttitle?: string;\n\t/** Accessible description for the dialog (screen-reader only by default). */\n\tdescription?: string;\n}\n\n/**\n * Command menu rendered inside a Dialog — a ⌘K-style launcher.\n * @param props - Forwarded to the underlying Dialog (open, onOpenChange, etc.)\n * @returns A Dialog containing a Command menu.\n */\nfunction CommandDialog({\n\ttitle = \"Command Palette\",\n\tdescription = \"Search for a command to run.\",\n\tchildren,\n\t...props\n}: CommandDialogProps) {\n\treturn (\n\t\t<Dialog {...props}>\n\t\t\t<DialogHeader className=\"sr-only\">\n\t\t\t\t<DialogTitle>{title}</DialogTitle>\n\t\t\t\t<DialogDescription>{description}</DialogDescription>\n\t\t\t</DialogHeader>\n\t\t\t<DialogContent className=\"overflow-hidden p-0\" scrollable={false}>\n\t\t\t\t<Command className=\"[&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-[var(--space-2,0.5rem)] [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-[var(--space-2,0.5rem)] [&_[cmdk-item]]:py-[var(--space-3,0.75rem)] [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n\t\t\t\t\t{children}\n\t\t\t\t</Command>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\n/** Search input for the Command menu. Fires onValueChange as the user types. */\nconst CommandInput = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Input>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>\n>(({ className, ...props }, ref) => (\n\t<div className=\"flex items-center border-b border-b-foreground/[0.08] px-[var(--space-3,0.75rem)]\" cmdk-input-wrapper=\"\">\n\t\t<svg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"mr-[var(--space-2,0.5rem)] h-4 w-4 shrink-0 opacity-50\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<circle cx=\"11\" cy=\"11\" r=\"8\" />\n\t\t\t<line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n\t\t</svg>\n\t\t<CommandPrimitive.Input\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"flex h-[var(--control-height-lg,2.75rem)] w-full rounded-md bg-transparent py-[var(--space-3,0.75rem)] text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</div>\n));\nCommandInput.displayName = \"CommandInput\";\n\n/** Scrollable list that contains CommandGroup / CommandItem / CommandEmpty. */\nconst CommandList = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.List>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.List>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.List\n\t\tref={ref}\n\t\tclassName={cn(\"max-h-[300px] overflow-y-auto overflow-x-hidden\", className)}\n\t\t{...props}\n\t/>\n));\nCommandList.displayName = \"CommandList\";\n\n/** Rendered when no items match the current search. */\nconst CommandEmpty = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Empty>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>\n>((props, ref) => (\n\t<CommandPrimitive.Empty ref={ref} className=\"py-[var(--space-6,1.5rem)] text-center text-sm\" {...props} />\n));\nCommandEmpty.displayName = \"CommandEmpty\";\n\n/** Logical group of items — renders a heading and filters as a unit. */\nconst CommandGroup = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Group>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.Group\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"overflow-hidden p-[var(--space-1,0.25rem)] text-foreground [&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommandGroup.displayName = \"CommandGroup\";\n\n/**\n * Horizontal rule between groups. Renders as a presentational `<div>` (no role)\n * so it can sit inside CommandList (role=listbox) without violating ARIA's\n * required-children rule for listbox. The line is purely decorative — cmdk's\n * built-in Separator hardcodes `role=\"separator\"`, which axe rejects in this\n * context, so we render the divider directly.\n *\n * The `data-cmdk-separator` attribute is preserved so existing CSS / test\n * selectors that target cmdk's separator continue to match.\n */\nconst CommandSeparator = React.forwardRef<\n\tHTMLDivElement,\n\tReact.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n\t<div\n\t\tref={ref}\n\t\trole=\"none\"\n\t\tdata-cmdk-separator=\"\"\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nCommandSeparator.displayName = \"CommandSeparator\";\n\n/** Selectable item. onSelect fires on Enter or click. */\nconst CommandItem = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.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 transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n\t\t\t\"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground\",\n\t\t\t\"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommandItem.displayName = \"CommandItem\";\n\n/**\n * Keyboard shortcut hint (e.g. '⌘K') aligned to the right of an item.\n * @returns A muted inline span rendered at the end of a CommandItem.\n */\nfunction CommandShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"ml-auto text-xs tracking-widest text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\nCommandShortcut.displayName = \"CommandShortcut\";\n\nexport {\n\tCommand,\n\tCommandDialog,\n\tCommandInput,\n\tCommandList,\n\tCommandEmpty,\n\tCommandGroup,\n\tCommandItem,\n\tCommandShortcut,\n\tCommandSeparator,\n};\n","\"use client\";\n\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a popover. */\nconst Popover = PopoverPrimitive.Root;\n\n/** The element that anchors and opens the popover. */\nconst PopoverTrigger = PopoverPrimitive.Trigger;\n\n/** Helper to explicitly anchor the popover to a different element. */\nconst PopoverAnchor = PopoverPrimitive.Anchor;\n\n/** The floating popover content panel. */\nconst PopoverContent = React.forwardRef<\n\tReact.ComponentRef<typeof PopoverPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => (\n\t<PopoverPrimitive.Portal>\n\t\t<PopoverPrimitive.Content\n\t\t\tref={ref}\n\t\t\talign={align}\n\t\t\tsideOffset={sideOffset}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 w-72 rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-4,1rem)] text-popover-foreground shadow-md outline-none\",\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\t\"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = \"PopoverContent\";\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };\n","\"use client\";\n\nimport * as React from \"react\";\nimport {\n\tCommand,\n\tCommandEmpty,\n\tCommandGroup,\n\tCommandInput,\n\tCommandItem,\n\tCommandList,\n} from \"../command/command.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../popover/popover.js\";\nimport { cn } from \"../../lib/utils.js\";\n\ninterface ComboboxOption {\n\t/** The value returned from onChange (stable, unique). */\n\tvalue: string;\n\t/** The display label shown in the list and the trigger. */\n\tlabel: string;\n\t/** Mark as non-selectable. */\n\tdisabled?: boolean;\n}\n\ninterface ComboboxProps {\n\t/** The list of selectable options. */\n\toptions: ComboboxOption[];\n\t/** Controlled selected value. */\n\tvalue?: string;\n\t/** Fired when the user picks an option: (value: string) => void */\n\tonChange?: (value: string) => void;\n\t/** Text shown on the trigger when nothing is selected. */\n\tplaceholder?: string;\n\t/** Input placeholder inside the popover list. */\n\tsearchPlaceholder?: string;\n\t/** Text shown when no options match the search. */\n\temptyText?: string;\n\t/** Disable the trigger. */\n\tdisabled?: boolean;\n\t/** Extra class names on the trigger button. */\n\tclassName?: string;\n\t/** Accessible label for the trigger (required when no adjacent visible label). */\n\t\"aria-label\"?: string;\n\t/** Id of an external visible label that names this combobox. */\n\t\"aria-labelledby\"?: string;\n}\n\n/**\n * Searchable select input built on Command + Popover.\n *\n * Pass `options` with `{ value, label }` shape. The selected label is shown on\n * the trigger; the popover contains a CommandInput and filtered CommandList.\n * @returns A trigger button that opens a filtered option list.\n */\nfunction Combobox({\n\toptions,\n\tvalue,\n\tonChange,\n\tplaceholder = \"Select…\",\n\tsearchPlaceholder = \"Search…\",\n\temptyText = \"No results found.\",\n\tdisabled,\n\tclassName,\n\t\"aria-label\": ariaLabel,\n\t\"aria-labelledby\": ariaLabelledBy,\n}: ComboboxProps) {\n\tconst [open, setOpen] = React.useState(false);\n\tconst listboxId = React.useId();\n\tconst selected = options.find((o) => o.value === value);\n\n\treturn (\n\t\t<Popover open={open} onOpenChange={setOpen}>\n\t\t\t<PopoverTrigger asChild>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\trole=\"combobox\"\n\t\t\t\t\taria-expanded={open}\n\t\t\t\t\taria-haspopup=\"listbox\"\n\t\t\t\t\t/*\n\t\t\t\t\t * Only reference the listbox id when the popover is open.\n\t\t\t\t\t * The CommandList is portal-mounted by Radix Popover and\n\t\t\t\t\t * does not exist in the DOM while closed; pointing at a\n\t\t\t\t\t * missing id confuses some screen readers.\n\t\t\t\t\t */\n\t\t\t\t\taria-controls={open ? listboxId : undefined}\n\t\t\t\t\taria-label={ariaLabel}\n\t\t\t\t\taria-labelledby={ariaLabelledBy}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"inline-flex h-[var(--control-height-md,2.5rem)] w-[240px] items-center justify-between gap-[var(--gap-sm,0.5rem)] rounded-md border border-input bg-background px-[var(--space-3,0.75rem)] py-[var(--space-2,0.5rem)] text-sm font-normal transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\t\"shadow-sm inset-ring-1 inset-ring-foreground/[0.06]\",\n\t\t\t\t\t\t\"hover:bg-accent hover:text-accent-foreground\",\n\t\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\t\t\"disabled:pointer-events-none disabled:opacity-50\",\n\t\t\t\t\t\t!selected && \"text-muted-foreground\",\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<span className=\"truncate\">{selected ? selected.label : placeholder}</span>\n\t\t\t\t\t<svg\n\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\tclassName=\"h-4 w-4 shrink-0 opacity-50\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<polyline points=\"6 9 12 15 18 9\" />\n\t\t\t\t\t</svg>\n\t\t\t\t</button>\n\t\t\t</PopoverTrigger>\n\t\t\t<PopoverContent className=\"w-[240px] p-0\" align=\"start\">\n\t\t\t\t<Command>\n\t\t\t\t\t<CommandInput placeholder={searchPlaceholder} />\n\t\t\t\t\t<CommandList id={listboxId}>\n\t\t\t\t\t\t<CommandEmpty>{emptyText}</CommandEmpty>\n\t\t\t\t\t\t<CommandGroup>\n\t\t\t\t\t\t\t{options.map((option) => (\n\t\t\t\t\t\t\t\t<CommandItem\n\t\t\t\t\t\t\t\t\tkey={option.value}\n\t\t\t\t\t\t\t\t\tvalue={option.label}\n\t\t\t\t\t\t\t\t\tdisabled={option.disabled}\n\t\t\t\t\t\t\t\t\tonSelect={() => {\n\t\t\t\t\t\t\t\t\t\tonChange?.(option.value);\n\t\t\t\t\t\t\t\t\t\tsetOpen(false);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\"mr-[var(--space-2,0.5rem)] h-4 w-4\",\n\t\t\t\t\t\t\t\t\t\t\tvalue === option.value ? \"opacity-100\" : \"opacity-0\",\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t</CommandItem>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</CommandGroup>\n\t\t\t\t\t</CommandList>\n\t\t\t\t</Command>\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\nCombobox.displayName = \"Combobox\";\n\nexport { Combobox };\nexport type { ComboboxOption, ComboboxProps };\n"]}
|
package/dist/command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/dialog/dialog.tsx","../src/components/command/command.tsx"],"names":["React","jsx","CommandPrimitive","jsxs"],"mappings":"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","file":"command.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 DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container controlling open state of a modal dialog. */\nconst Dialog = DialogPrimitive.Root;\n\n/** The element (usually a button) that opens the dialog when clicked. */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** Portals the dialog overlay and content into the body. */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** Closes the dialog when rendered inside DialogContent. */\nconst DialogClose = DialogPrimitive.Close;\n\n/** Dimmed backdrop rendered behind the dialog content. */\nconst DialogOverlay = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Overlay>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Overlay\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm\",\n\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\ninterface DialogContentProps\n\textends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n\t/**\n\t * When `true` (the default), DialogContent caps its height at viewport-2rem\n\t * and renders children inside a padded inner scroll container. The Close\n\t * button stays anchored to the (non-scrolling) outer panel so it remains\n\t * visible even when the user scrolls long content.\n\t *\n\t * Pass `scrollable={false}` to opt out — useful when the consumer manages\n\t * its own scroll surface (e.g. CommandDialog defers scroll to cmdk's\n\t * internal CommandList).\n\t */\n\tscrollable?: boolean;\n}\n\n/** The dialog content panel, centered on the overlay. Includes a close button by default. */\nconst DialogContent = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Content>,\n\tDialogContentProps\n>(({ className, children, scrollable = true, ...props }, ref) => (\n\t<DialogPortal>\n\t\t<DialogOverlay />\n\t\t<DialogPrimitive.Content\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]\",\n\t\t\t\tscrollable\n\t\t\t\t\t? \"max-h-[calc(100vh-2rem)] border border-foreground/[0.08] bg-background shadow-lg rounded-lg\"\n\t\t\t\t\t: \"gap-[var(--gap-md,1rem)] border border-foreground/[0.08] bg-background p-[var(--space-6,1.5rem)] shadow-lg rounded-lg\",\n\t\t\t\t\"duration-[var(--duration-normal,200ms)] 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\t\t{scrollable ? (\n\t\t\t\t<div className=\"grid gap-[var(--gap-md,1rem)] overflow-y-auto p-[var(--space-6,1.5rem)]\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\tchildren\n\t\t\t)}\n\t\t\t<DialogPrimitive.Close\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"absolute right-4 top-4 z-10 rounded-sm opacity-70 ring-offset-background bg-background/80 backdrop-blur-sm\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100\",\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\t\"disabled:pointer-events-none\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<svg\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t<path d=\"M18 6 6 18\" />\n\t\t\t\t\t<path d=\"m6 6 12 12\" />\n\t\t\t\t</svg>\n\t\t\t\t<span className=\"sr-only\">Close</span>\n\t\t\t</DialogPrimitive.Close>\n\t\t</DialogPrimitive.Content>\n\t</DialogPortal>\n));\nDialogContent.displayName = \"DialogContent\";\n\nexport type { DialogContentProps };\n\n/**\n * Header container inside DialogContent; stacks title and description.\n * @returns A div wrapping title/description with vertical rhythm\n */\nfunction DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"flex flex-col space-y-1.5 text-center sm:text-left\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Footer container inside DialogContent; aligns action buttons.\n * @returns A div that stacks buttons on mobile and right-aligns on desktop\n */\nfunction DialogFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/** Accessible dialog title; Radix wires it to aria-labelledby automatically. */\nconst DialogTitle = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Title>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Title\n\t\tref={ref}\n\t\tclassName={cn(\"text-lg font-semibold leading-none tracking-tight\", className)}\n\t\t{...props}\n\t/>\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Accessible dialog description; Radix wires it to aria-describedby automatically. */\nconst DialogDescription = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Description>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Description\n\t\tref={ref}\n\t\tclassName={cn(\"text-sm text-muted-foreground\", className)}\n\t\t{...props}\n\t/>\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport {\n\tDialog,\n\tDialogPortal,\n\tDialogOverlay,\n\tDialogTrigger,\n\tDialogClose,\n\tDialogContent,\n\tDialogHeader,\n\tDialogFooter,\n\tDialogTitle,\n\tDialogDescription,\n};\n","\"use client\";\n\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport * as React from \"react\";\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n} from \"../dialog/dialog.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root Command container — drives search, filtering, and keyboard navigation over items. */\nconst Command = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommand.displayName = \"Command\";\n\ninterface CommandDialogProps extends React.ComponentPropsWithoutRef<typeof Dialog> {\n\t/** Command children (CommandInput + CommandList + CommandItem, etc.) */\n\tchildren: React.ReactNode;\n\t/** Accessible title for the dialog (screen-reader only by default). */\n\ttitle?: string;\n\t/** Accessible description for the dialog (screen-reader only by default). */\n\tdescription?: string;\n}\n\n/**\n * Command menu rendered inside a Dialog — a ⌘K-style launcher.\n * @param props - Forwarded to the underlying Dialog (open, onOpenChange, etc.)\n * @returns A Dialog containing a Command menu.\n */\nfunction CommandDialog({\n\ttitle = \"Command Palette\",\n\tdescription = \"Search for a command to run.\",\n\tchildren,\n\t...props\n}: CommandDialogProps) {\n\treturn (\n\t\t<Dialog {...props}>\n\t\t\t<DialogHeader className=\"sr-only\">\n\t\t\t\t<DialogTitle>{title}</DialogTitle>\n\t\t\t\t<DialogDescription>{description}</DialogDescription>\n\t\t\t</DialogHeader>\n\t\t\t<DialogContent className=\"overflow-hidden p-0\" scrollable={false}>\n\t\t\t\t<Command className=\"[&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-[var(--space-2,0.5rem)] [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-[var(--space-2,0.5rem)] [&_[cmdk-item]]:py-[var(--space-3,0.75rem)] [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n\t\t\t\t\t{children}\n\t\t\t\t</Command>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\n/** Search input for the Command menu. Fires onValueChange as the user types. */\nconst CommandInput = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Input>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>\n>(({ className, ...props }, ref) => (\n\t<div className=\"flex items-center border-b border-b-foreground/[0.08] px-[var(--space-3,0.75rem)]\" cmdk-input-wrapper=\"\">\n\t\t<svg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"mr-[var(--space-2,0.5rem)] h-4 w-4 shrink-0 opacity-50\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<circle cx=\"11\" cy=\"11\" r=\"8\" />\n\t\t\t<line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n\t\t</svg>\n\t\t<CommandPrimitive.Input\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"flex h-[var(--control-height-lg,2.75rem)] w-full rounded-md bg-transparent py-[var(--space-3,0.75rem)] text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</div>\n));\nCommandInput.displayName = \"CommandInput\";\n\n/** Scrollable list that contains CommandGroup / CommandItem / CommandEmpty. */\nconst CommandList = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.List>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.List>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.List\n\t\tref={ref}\n\t\tclassName={cn(\"max-h-[300px] overflow-y-auto overflow-x-hidden\", className)}\n\t\t{...props}\n\t/>\n));\nCommandList.displayName = \"CommandList\";\n\n/** Rendered when no items match the current search. */\nconst CommandEmpty = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Empty>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>\n>((props, ref) => (\n\t<CommandPrimitive.Empty ref={ref} className=\"py-[var(--space-6,1.5rem)] text-center text-sm\" {...props} />\n));\nCommandEmpty.displayName = \"CommandEmpty\";\n\n/** Logical group of items — renders a heading and filters as a unit. */\nconst CommandGroup = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Group>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.Group\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"overflow-hidden p-[var(--space-1,0.25rem)] text-foreground [&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommandGroup.displayName = \"CommandGroup\";\n\n/**\n * Horizontal rule between groups. Renders as a presentational `<div>` (no role)\n * so it can sit inside CommandList (role=listbox) without violating ARIA's\n * required-children rule for listbox. The line is purely decorative — cmdk's\n * built-in Separator hardcodes `role=\"separator\"`, which axe rejects in this\n * context, so we render the divider directly.\n *\n * The `data-cmdk-separator` attribute is preserved so existing CSS / test\n * selectors that target cmdk's separator continue to match.\n */\nconst CommandSeparator = React.forwardRef<\n\tHTMLDivElement,\n\tReact.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n\t<div\n\t\tref={ref}\n\t\trole=\"none\"\n\t\tdata-cmdk-separator=\"\"\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nCommandSeparator.displayName = \"CommandSeparator\";\n\n/** Selectable item. onSelect fires on Enter or click. */\nconst CommandItem = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.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 transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n\t\t\t\"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground\",\n\t\t\t\"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommandItem.displayName = \"CommandItem\";\n\n/**\n * Keyboard shortcut hint (e.g. '⌘K') aligned to the right of an item.\n * @returns A muted inline span rendered at the end of a CommandItem.\n */\nfunction CommandShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"ml-auto text-xs tracking-widest text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\nCommandShortcut.displayName = \"CommandShortcut\";\n\nexport {\n\tCommand,\n\tCommandDialog,\n\tCommandInput,\n\tCommandList,\n\tCommandEmpty,\n\tCommandGroup,\n\tCommandItem,\n\tCommandShortcut,\n\tCommandSeparator,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/dialog/dialog.tsx","../src/components/command/command.tsx"],"names":["React","jsx","CommandPrimitive","jsxs"],"mappings":"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","file":"command.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 DialogPrimitive from \"@radix-ui/react-dialog\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container controlling open state of a modal dialog. */\nconst Dialog = DialogPrimitive.Root;\n\n/** The element (usually a button) that opens the dialog when clicked. */\nconst DialogTrigger = DialogPrimitive.Trigger;\n\n/** Portals the dialog overlay and content into the body. */\nconst DialogPortal = DialogPrimitive.Portal;\n\n/** Closes the dialog when rendered inside DialogContent. */\nconst DialogClose = DialogPrimitive.Close;\n\n/** Dimmed backdrop rendered behind the dialog content. */\nconst DialogOverlay = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Overlay>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Overlay\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm\",\n\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\ninterface DialogContentProps\n\textends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n\t/**\n\t * When `true` (the default), DialogContent caps its height at viewport-2rem\n\t * and renders children inside a padded inner scroll container. The Close\n\t * button stays anchored to the (non-scrolling) outer panel so it remains\n\t * visible even when the user scrolls long content.\n\t *\n\t * Pass `scrollable={false}` to opt out — useful when the consumer manages\n\t * its own scroll surface (e.g. CommandDialog defers scroll to cmdk's\n\t * internal CommandList).\n\t */\n\tscrollable?: boolean;\n}\n\n/** The dialog content panel, centered on the overlay. Includes a close button by default. */\nconst DialogContent = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Content>,\n\tDialogContentProps\n>(({ className, children, scrollable = true, ...props }, ref) => (\n\t<DialogPortal>\n\t\t<DialogOverlay />\n\t\t<DialogPrimitive.Content\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]\",\n\t\t\t\tscrollable\n\t\t\t\t\t? \"max-h-[calc(100vh-2rem)] border border-foreground/[0.08] bg-background shadow-lg rounded-lg\"\n\t\t\t\t\t: \"gap-[var(--gap-md,1rem)] border border-foreground/[0.08] bg-background p-[var(--space-6,1.5rem)] shadow-lg rounded-lg\",\n\t\t\t\t\"duration-[var(--duration-normal,200ms)] 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\t\t{scrollable ? (\n\t\t\t\t<div className=\"grid gap-[var(--gap-md,1rem)] overflow-y-auto p-[var(--space-6,1.5rem)]\">\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t) : (\n\t\t\t\tchildren\n\t\t\t)}\n\t\t\t<DialogPrimitive.Close\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"absolute right-4 top-4 z-10 rounded-sm opacity-70 ring-offset-background bg-background/80 backdrop-blur-sm\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out hover:opacity-100\",\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\t\"disabled:pointer-events-none\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<svg\n\t\t\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\tclassName=\"h-4 w-4\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t<path d=\"M18 6 6 18\" />\n\t\t\t\t\t<path d=\"m6 6 12 12\" />\n\t\t\t\t</svg>\n\t\t\t\t<span className=\"sr-only\">Close</span>\n\t\t\t</DialogPrimitive.Close>\n\t\t</DialogPrimitive.Content>\n\t</DialogPortal>\n));\nDialogContent.displayName = \"DialogContent\";\n\nexport type { DialogContentProps };\n\n/**\n * Header container inside DialogContent; stacks title and description.\n * @returns A div wrapping title/description with vertical rhythm\n */\nfunction DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\"flex flex-col space-y-1.5 text-center sm:text-left\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/**\n * Footer container inside DialogContent; aligns action buttons.\n * @returns A div that stacks buttons on mobile and right-aligns on desktop\n */\nfunction DialogFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\n/** Accessible dialog title; Radix wires it to aria-labelledby automatically. */\nconst DialogTitle = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Title>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Title\n\t\tref={ref}\n\t\tclassName={cn(\"text-lg font-semibold leading-none tracking-tight\", className)}\n\t\t{...props}\n\t/>\n));\nDialogTitle.displayName = \"DialogTitle\";\n\n/** Accessible dialog description; Radix wires it to aria-describedby automatically. */\nconst DialogDescription = React.forwardRef<\n\tReact.ComponentRef<typeof DialogPrimitive.Description>,\n\tReact.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n\t<DialogPrimitive.Description\n\t\tref={ref}\n\t\tclassName={cn(\"text-sm text-muted-foreground\", className)}\n\t\t{...props}\n\t/>\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport {\n\tDialog,\n\tDialogPortal,\n\tDialogOverlay,\n\tDialogTrigger,\n\tDialogClose,\n\tDialogContent,\n\tDialogHeader,\n\tDialogFooter,\n\tDialogTitle,\n\tDialogDescription,\n};\n","\"use client\";\n\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport * as React from \"react\";\nimport {\n\tDialog,\n\tDialogContent,\n\tDialogDescription,\n\tDialogHeader,\n\tDialogTitle,\n} from \"../dialog/dialog.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root Command container — drives search, filtering, and keyboard navigation over items. */\nconst Command = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommand.displayName = \"Command\";\n\ninterface CommandDialogProps extends React.ComponentPropsWithoutRef<typeof Dialog> {\n\t/** Command children (CommandInput + CommandList + CommandItem, etc.) */\n\tchildren: React.ReactNode;\n\t/** Accessible title for the dialog (screen-reader only by default). */\n\ttitle?: string;\n\t/** Accessible description for the dialog (screen-reader only by default). */\n\tdescription?: string;\n}\n\n/**\n * Command menu rendered inside a Dialog — a ⌘K-style launcher.\n * @param props - Forwarded to the underlying Dialog (open, onOpenChange, etc.)\n * @returns A Dialog containing a Command menu.\n */\nfunction CommandDialog({\n\ttitle = \"Command Palette\",\n\tdescription = \"Search for a command to run.\",\n\tchildren,\n\t...props\n}: CommandDialogProps) {\n\treturn (\n\t\t<Dialog {...props}>\n\t\t\t<DialogHeader className=\"sr-only\">\n\t\t\t\t<DialogTitle>{title}</DialogTitle>\n\t\t\t\t<DialogDescription>{description}</DialogDescription>\n\t\t\t</DialogHeader>\n\t\t\t<DialogContent className=\"overflow-hidden p-0\" scrollable={false}>\n\t\t\t\t<Command className=\"[&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-[var(--space-2,0.5rem)] [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-[var(--space-2,0.5rem)] [&_[cmdk-item]]:py-[var(--space-3,0.75rem)] [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n\t\t\t\t\t{children}\n\t\t\t\t</Command>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\n/** Search input for the Command menu. Fires onValueChange as the user types. */\nconst CommandInput = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Input>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>\n>(({ className, ...props }, ref) => (\n\t<div className=\"flex items-center border-b border-b-foreground/[0.08] px-[var(--space-3,0.75rem)]\" cmdk-input-wrapper=\"\">\n\t\t<svg\n\t\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"mr-[var(--space-2,0.5rem)] h-4 w-4 shrink-0 opacity-50\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<circle cx=\"11\" cy=\"11\" r=\"8\" />\n\t\t\t<line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n\t\t</svg>\n\t\t<CommandPrimitive.Input\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"flex h-[var(--control-height-lg,2.75rem)] w-full rounded-md bg-transparent py-[var(--space-3,0.75rem)] text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</div>\n));\nCommandInput.displayName = \"CommandInput\";\n\n/** Scrollable list that contains CommandGroup / CommandItem / CommandEmpty. */\nconst CommandList = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.List>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.List>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.List\n\t\tref={ref}\n\t\tclassName={cn(\"max-h-[300px] overflow-y-auto overflow-x-hidden\", className)}\n\t\t{...props}\n\t/>\n));\nCommandList.displayName = \"CommandList\";\n\n/** Rendered when no items match the current search. */\nconst CommandEmpty = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Empty>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>\n>((props, ref) => (\n\t<CommandPrimitive.Empty ref={ref} className=\"py-[var(--space-6,1.5rem)] text-center text-sm\" {...props} />\n));\nCommandEmpty.displayName = \"CommandEmpty\";\n\n/** Logical group of items — renders a heading and filters as a unit. */\nconst CommandGroup = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Group>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.Group\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"overflow-hidden p-[var(--space-1,0.25rem)] text-foreground [&_[cmdk-group-heading]]:px-[var(--space-2,0.5rem)] [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommandGroup.displayName = \"CommandGroup\";\n\n/**\n * Horizontal rule between groups. Renders as a presentational `<div>` (no role)\n * so it can sit inside CommandList (role=listbox) without violating ARIA's\n * required-children rule for listbox. The line is purely decorative — cmdk's\n * built-in Separator hardcodes `role=\"separator\"`, which axe rejects in this\n * context, so we render the divider directly.\n *\n * The `data-cmdk-separator` attribute is preserved so existing CSS / test\n * selectors that target cmdk's separator continue to match.\n */\nconst CommandSeparator = React.forwardRef<\n\tHTMLDivElement,\n\tReact.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => (\n\t<div\n\t\tref={ref}\n\t\trole=\"none\"\n\t\tdata-cmdk-separator=\"\"\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nCommandSeparator.displayName = \"CommandSeparator\";\n\n/** Selectable item. onSelect fires on Enter or click. */\nconst CommandItem = React.forwardRef<\n\tReact.ComponentRef<typeof CommandPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>\n>(({ className, ...props }, ref) => (\n\t<CommandPrimitive.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 transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50\",\n\t\t\t\"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground\",\n\t\t\t\"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nCommandItem.displayName = \"CommandItem\";\n\n/**\n * Keyboard shortcut hint (e.g. '⌘K') aligned to the right of an item.\n * @returns A muted inline span rendered at the end of a CommandItem.\n */\nfunction CommandShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\n\t\t\t\t\"ml-auto text-xs tracking-widest text-muted-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\nCommandShortcut.displayName = \"CommandShortcut\";\n\nexport {\n\tCommand,\n\tCommandDialog,\n\tCommandInput,\n\tCommandList,\n\tCommandEmpty,\n\tCommandGroup,\n\tCommandItem,\n\tCommandShortcut,\n\tCommandSeparator,\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/compare-table/compare-table.tsx"],"names":[],"mappings":"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","file":"compare-table.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 * Side-by-side comparison table. Subjects are columns; attributes are\n * rows; cells render the per-subject value for that attribute. With\n * `highlightDifferences`, cells whose value differs from the row's\n * first non-empty cell get a subtle accent — handy for vocab pairs\n * (term ↔ translation), feature matrices (Linux vs Mac vs Windows),\n * before/after comparisons. Pure HTML; no heavy peer.\n *\n * @example\n * <CompareTable\n * subjects={[\n * { id: \"linux\", label: \"Linux\" },\n * { id: \"mac\", label: \"Mac\" },\n * { id: \"win\", label: \"Windows\" },\n * ]}\n * attributes={[\n * { id: \"kernel\", label: \"Kernel\", values: { linux: \"Linux\", mac: \"Darwin\", win: \"NT\" } },\n * { id: \"fs\", label: \"Default FS\", values: { linux: \"ext4\", mac: \"APFS\", win: \"NTFS\" } },\n * ]}\n * />\n */\nexport type CompareSubject = {\n\tid: string;\n\tlabel: React.ReactNode;\n};\n\nexport type CompareAttribute = {\n\tid: string;\n\tlabel: React.ReactNode;\n\t/** Map of subjectId → cell content. Missing keys render as \"—\". */\n\tvalues: Record<string, React.ReactNode>;\n};\n\nexport interface CompareTableProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n\t/** Columns. */\n\tsubjects: CompareSubject[];\n\t/** Rows. */\n\tattributes: CompareAttribute[];\n\t/** When true, cells whose value differs from the row's first non-empty cell get a subtle accent. */\n\thighlightDifferences?: boolean;\n\t/** Fired when a body cell is clicked. */\n\tonCellClick?: (subjectId: string, attributeId: string) => void;\n}\n\nconst EMPTY_PLACEHOLDER = \"—\";\n\nfunction CompareTable({\n\tsubjects,\n\tattributes,\n\thighlightDifferences = false,\n\tonCellClick,\n\tclassName,\n\t...rest\n}: CompareTableProps) {\n\t// Surface a developer-facing console.warn when an attribute references a\n\t// subjectId that isn't actually in `subjects` — easy mistake when the\n\t// consumer rebuilds rows from a different source than columns.\n\tconst warnedRef = React.useRef(false);\n\tconst nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV;\n\tif (nodeEnv !== \"production\" && !warnedRef.current) {\n\t\tconst subjectIds = new Set(subjects.map((s) => s.id));\n\t\tfor (const attr of attributes) {\n\t\t\tfor (const valueId of Object.keys(attr.values)) {\n\t\t\t\tif (!subjectIds.has(valueId)) {\n\t\t\t\t\twarnedRef.current = true;\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[hex-core/CompareTable] Attribute \"${attr.id}\" has a value for subjectId \"${valueId}\" that isn't in the subjects array. The cell will not render.`,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (warnedRef.current) break;\n\t\t}\n\t}\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-compare-table\n\t\t\tclassName={cn(\"overflow-x-auto rounded-lg border\", className)}\n\t\t>\n\t\t\t<table className=\"w-full border-collapse text-sm\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr data-hex-compare-table-header>\n\t\t\t\t\t\t<th\n\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 border-b bg-card px-3 py-2 text-left text-xs font-medium text-muted-foreground\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{/* Empty corner — attribute labels live here per row */}\n\t\t\t\t\t\t</th>\n\t\t\t\t\t\t{subjects.map((subject) => (\n\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\tkey={subject.id}\n\t\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\t\tdata-hex-compare-table-subject\n\t\t\t\t\t\t\t\tdata-subject-id={subject.id}\n\t\t\t\t\t\t\t\tclassName=\"border-b bg-card px-3 py-2 text-left font-semibold\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{subject.label}\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t{attributes.map((attr) => {\n\t\t\t\t\t\t// Find the row's reference value (first non-empty cell among the\n\t\t\t\t\t\t// subjects we're rendering, preserving display order).\n\t\t\t\t\t\tconst reference = highlightDifferences\n\t\t\t\t\t\t\t? subjects.map((s) => attr.values[s.id]).find((v) => v != null && v !== \"\")\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<tr key={attr.id} data-hex-compare-table-row data-attribute-id={attr.id}>\n\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\tscope=\"row\"\n\t\t\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 border-b bg-card px-3 py-2 text-left font-medium\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{attr.label}\n\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t{subjects.map((subject) => {\n\t\t\t\t\t\t\t\t\tconst raw = attr.values[subject.id];\n\t\t\t\t\t\t\t\t\tconst isEmpty = raw == null || raw === \"\";\n\t\t\t\t\t\t\t\t\tconst displayValue = isEmpty ? EMPTY_PLACEHOLDER : raw;\n\t\t\t\t\t\t\t\t\t// Skip diff for non-primitive values: ReactElements stringify\n\t\t\t\t\t\t\t\t\t// to \"[object Object]\" and would all flag as different. Only\n\t\t\t\t\t\t\t\t\t// run the comparison when both raw + reference are scalar.\n\t\t\t\t\t\t\t\t\tconst isComparable =\n\t\t\t\t\t\t\t\t\t\t(typeof raw === \"string\" || typeof raw === \"number\" || typeof raw === \"boolean\") &&\n\t\t\t\t\t\t\t\t\t\t(typeof reference === \"string\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof reference === \"number\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof reference === \"boolean\");\n\t\t\t\t\t\t\t\t\tconst differs =\n\t\t\t\t\t\t\t\t\t\thighlightDifferences &&\n\t\t\t\t\t\t\t\t\t\t!isEmpty &&\n\t\t\t\t\t\t\t\t\t\treference !== undefined &&\n\t\t\t\t\t\t\t\t\t\tisComparable &&\n\t\t\t\t\t\t\t\t\t\tString(raw) !== String(reference);\n\t\t\t\t\t\t\t\t\tconst interactive = Boolean(onCellClick);\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\tkey={subject.id}\n\t\t\t\t\t\t\t\t\t\t\tdata-hex-compare-table-cell\n\t\t\t\t\t\t\t\t\t\t\tdata-subject-id={subject.id}\n\t\t\t\t\t\t\t\t\t\t\tdata-attribute-id={attr.id}\n\t\t\t\t\t\t\t\t\t\t\tdata-differs={differs}\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\"border-b px-3 py-2 align-top\",\n\t\t\t\t\t\t\t\t\t\t\t\tdiffers && \"bg-accent/30 text-accent-foreground\",\n\t\t\t\t\t\t\t\t\t\t\t\tisEmpty && \"text-muted-foreground\",\n\t\t\t\t\t\t\t\t\t\t\t\tinteractive && \"cursor-pointer hover:bg-muted/40\",\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\tonClick={interactive ? () => onCellClick?.(subject.id, attr.id) : undefined}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{displayValue}\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nexport { CompareTable };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/artifacts/compare-table/compare-table.tsx"],"names":[],"mappings":"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","file":"compare-table.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 * Side-by-side comparison table. Subjects are columns; attributes are\n * rows; cells render the per-subject value for that attribute. With\n * `highlightDifferences`, cells whose value differs from the row's\n * first non-empty cell get a subtle accent — handy for vocab pairs\n * (term ↔ translation), feature matrices (Linux vs Mac vs Windows),\n * before/after comparisons. Pure HTML; no heavy peer.\n *\n * @example\n * <CompareTable\n * subjects={[\n * { id: \"linux\", label: \"Linux\" },\n * { id: \"mac\", label: \"Mac\" },\n * { id: \"win\", label: \"Windows\" },\n * ]}\n * attributes={[\n * { id: \"kernel\", label: \"Kernel\", values: { linux: \"Linux\", mac: \"Darwin\", win: \"NT\" } },\n * { id: \"fs\", label: \"Default FS\", values: { linux: \"ext4\", mac: \"APFS\", win: \"NTFS\" } },\n * ]}\n * />\n */\nexport type CompareSubject = {\n\tid: string;\n\tlabel: React.ReactNode;\n};\n\nexport type CompareAttribute = {\n\tid: string;\n\tlabel: React.ReactNode;\n\t/** Map of subjectId → cell content. Missing keys render as \"—\". */\n\tvalues: Record<string, React.ReactNode>;\n};\n\nexport interface CompareTableProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"children\"> {\n\t/** Columns. */\n\tsubjects: CompareSubject[];\n\t/** Rows. */\n\tattributes: CompareAttribute[];\n\t/** When true, cells whose value differs from the row's first non-empty cell get a subtle accent. */\n\thighlightDifferences?: boolean;\n\t/** Fired when a body cell is clicked. */\n\tonCellClick?: (subjectId: string, attributeId: string) => void;\n}\n\nconst EMPTY_PLACEHOLDER = \"—\";\n\nfunction CompareTable({\n\tsubjects,\n\tattributes,\n\thighlightDifferences = false,\n\tonCellClick,\n\tclassName,\n\t...rest\n}: CompareTableProps) {\n\t// Surface a developer-facing console.warn when an attribute references a\n\t// subjectId that isn't actually in `subjects` — easy mistake when the\n\t// consumer rebuilds rows from a different source than columns.\n\tconst warnedRef = React.useRef(false);\n\tconst nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV;\n\tif (nodeEnv !== \"production\" && !warnedRef.current) {\n\t\tconst subjectIds = new Set(subjects.map((s) => s.id));\n\t\tfor (const attr of attributes) {\n\t\t\tfor (const valueId of Object.keys(attr.values)) {\n\t\t\t\tif (!subjectIds.has(valueId)) {\n\t\t\t\t\twarnedRef.current = true;\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[hex-core/CompareTable] Attribute \"${attr.id}\" has a value for subjectId \"${valueId}\" that isn't in the subjects array. The cell will not render.`,\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (warnedRef.current) break;\n\t\t}\n\t}\n\n\treturn (\n\t\t<div\n\t\t\t{...rest}\n\t\t\tdata-hex-compare-table\n\t\t\tclassName={cn(\"overflow-x-auto rounded-lg border\", className)}\n\t\t>\n\t\t\t<table className=\"w-full border-collapse text-sm\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr data-hex-compare-table-header>\n\t\t\t\t\t\t<th\n\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 border-b bg-card px-3 py-2 text-left text-xs font-medium text-muted-foreground\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{/* Empty corner — attribute labels live here per row */}\n\t\t\t\t\t\t</th>\n\t\t\t\t\t\t{subjects.map((subject) => (\n\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\tkey={subject.id}\n\t\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\t\tdata-hex-compare-table-subject\n\t\t\t\t\t\t\t\tdata-subject-id={subject.id}\n\t\t\t\t\t\t\t\tclassName=\"border-b bg-card px-3 py-2 text-left font-semibold\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{subject.label}\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t{attributes.map((attr) => {\n\t\t\t\t\t\t// Find the row's reference value (first non-empty cell among the\n\t\t\t\t\t\t// subjects we're rendering, preserving display order).\n\t\t\t\t\t\tconst reference = highlightDifferences\n\t\t\t\t\t\t\t? subjects.map((s) => attr.values[s.id]).find((v) => v != null && v !== \"\")\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<tr key={attr.id} data-hex-compare-table-row data-attribute-id={attr.id}>\n\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\tscope=\"row\"\n\t\t\t\t\t\t\t\t\tclassName=\"sticky left-0 z-10 border-b bg-card px-3 py-2 text-left font-medium\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{attr.label}\n\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t\t{subjects.map((subject) => {\n\t\t\t\t\t\t\t\t\tconst raw = attr.values[subject.id];\n\t\t\t\t\t\t\t\t\tconst isEmpty = raw == null || raw === \"\";\n\t\t\t\t\t\t\t\t\tconst displayValue = isEmpty ? EMPTY_PLACEHOLDER : raw;\n\t\t\t\t\t\t\t\t\t// Skip diff for non-primitive values: ReactElements stringify\n\t\t\t\t\t\t\t\t\t// to \"[object Object]\" and would all flag as different. Only\n\t\t\t\t\t\t\t\t\t// run the comparison when both raw + reference are scalar.\n\t\t\t\t\t\t\t\t\tconst isComparable =\n\t\t\t\t\t\t\t\t\t\t(typeof raw === \"string\" || typeof raw === \"number\" || typeof raw === \"boolean\") &&\n\t\t\t\t\t\t\t\t\t\t(typeof reference === \"string\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof reference === \"number\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof reference === \"boolean\");\n\t\t\t\t\t\t\t\t\tconst differs =\n\t\t\t\t\t\t\t\t\t\thighlightDifferences &&\n\t\t\t\t\t\t\t\t\t\t!isEmpty &&\n\t\t\t\t\t\t\t\t\t\treference !== undefined &&\n\t\t\t\t\t\t\t\t\t\tisComparable &&\n\t\t\t\t\t\t\t\t\t\tString(raw) !== String(reference);\n\t\t\t\t\t\t\t\t\tconst interactive = Boolean(onCellClick);\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\t\tkey={subject.id}\n\t\t\t\t\t\t\t\t\t\t\tdata-hex-compare-table-cell\n\t\t\t\t\t\t\t\t\t\t\tdata-subject-id={subject.id}\n\t\t\t\t\t\t\t\t\t\t\tdata-attribute-id={attr.id}\n\t\t\t\t\t\t\t\t\t\t\tdata-differs={differs}\n\t\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t\t\"border-b px-3 py-2 align-top\",\n\t\t\t\t\t\t\t\t\t\t\t\tdiffers && \"bg-accent/30 text-accent-foreground\",\n\t\t\t\t\t\t\t\t\t\t\t\tisEmpty && \"text-muted-foreground\",\n\t\t\t\t\t\t\t\t\t\t\t\tinteractive && \"cursor-pointer hover:bg-muted/40\",\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\tonClick={interactive ? () => onCellClick?.(subject.id, attr.id) : undefined}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{displayValue}\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nexport { CompareTable };\n"]}
|
package/dist/composer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/composer/composer.tsx"],"names":[],"mappings":";;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACoCA,SAAS,QAAA,CAAS;AAAA,EACjB,KAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA,GAAgB,IAAA;AAAA,EAChB,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACJ,CAAA,EAAkB;AACjB,EAAA,SAAS,SAAA,GAAY;AACpB,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,IAAI,CAAC,WAAW,QAAA,EAAU;AAC1B,IAAA,QAAA,CAAS,OAAO,CAAA;AAAA,EACjB;AAEA,EAAA,SAAS,cAAc,KAAA,EAAiD;AACvE,IAAA,IAAI,CAAC,aAAA,EAAe;AACpB,IAAA,IAAI,KAAA,CAAM,QAAQ,OAAA,IAAW,CAAC,MAAM,QAAA,IAAY,CAAC,KAAA,CAAM,WAAA,CAAY,WAAA,EAAa;AAC/E,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,SAAA,EAAU;AAAA,IACX;AAAA,EACD;AAEA,EAAA,SAAS,aAAa,KAAA,EAAyC;AAC9D,IAAA,KAAA,CAAM,cAAA,EAAe;AACrB,IAAA,SAAA,EAAU;AAAA,EACX;AAEA,EAAA,uBACC,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,GAAG,IAAA;AAAA,MACJ,QAAA,EAAU,YAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACV,0DAAA;AAAA,QACA,uEAAA;AAAA,QACA,iEAAA;AAAA,QACA;AAAA,OACD;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACA,KAAA;AAAA,YACA,UAAU,CAAC,KAAA,KAAU,aAAA,CAAc,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,YACrD,SAAA,EAAW,aAAA;AAAA,YACX,QAAA;AAAA,YACA,WAAA;AAAA,YACA,YAAA,EAAY,qBAAqB,WAAA,IAAe,SAAA;AAAA,YAChD,IAAA,EAAM,CAAA;AAAA,YACN,SAAA,EAAW,EAAA;AAAA,cACV,iEAAA;AAAA,cACA,sDAAA;AAAA,cACA,iDAAA;AAAA,cACA;AAAA;AACD;AAAA,SACD;AAAA,QACC;AAAA;AAAA;AAAA,GACF;AAEF","file":"composer.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 * Multi-line text input + submission shell for chat composers. Headless on\n * data flow — `value`/`onValueChange` are required so the consumer keeps\n * input state wherever fits (a `useChat` hook, a parent form, local state).\n *\n * Submits on Enter (without Shift). Children render after the textarea —\n * the canonical place for attachment buttons + a send button.\n *\n * Spreads remaining props onto the underlying `<form>`, so consumers can\n * pass `aria-label`, `id`, `name`, `data-*`, and similar attributes.\n *\n * @example\n * <Composer\n * value={input}\n * onValueChange={setInput}\n * onSubmit={(v) => sendMessage(v)}\n * placeholder=\"Ask anything…\"\n * >\n * <Button type=\"submit\">Send</Button>\n * </Composer>\n */\nexport interface ComposerProps\n\textends Omit<React.FormHTMLAttributes<HTMLFormElement>, \"onSubmit\" | \"children\"> {\n\tvalue: string;\n\tonValueChange: (value: string) => void;\n\tonSubmit: (value: string) => void;\n\tdisabled?: boolean;\n\tplaceholder?: string;\n\t/** Submit on Enter without Shift. Default true. */\n\tsubmitOnEnter?: boolean;\n\t/** Accessible name for the textarea. Defaults to `placeholder` when set, else \"Message\". */\n\ttextareaAriaLabel?: string;\n\t/** Trailing slot — attachment buttons, send button, etc. */\n\tchildren?: React.ReactNode;\n}\n\n/**\n * Renders a chat composer with a textarea + slot for action buttons.\n * @param props - controlled value/handlers + slot children\n * @returns A form element with a textarea and trailing slot\n */\nfunction Composer({\n\tvalue,\n\tonValueChange,\n\tonSubmit,\n\tdisabled,\n\tplaceholder,\n\tsubmitOnEnter = true,\n\ttextareaAriaLabel,\n\tchildren,\n\tclassName,\n\t...rest\n}: ComposerProps) {\n\tfunction trySubmit() {\n\t\tconst trimmed = value.trim();\n\t\tif (!trimmed || disabled) return;\n\t\tonSubmit(trimmed);\n\t}\n\n\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLTextAreaElement>) {\n\t\tif (!submitOnEnter) return;\n\t\tif (event.key === \"Enter\" && !event.shiftKey && !event.nativeEvent.isComposing) {\n\t\t\tevent.preventDefault();\n\t\t\ttrySubmit();\n\t\t}\n\t}\n\n\tfunction handleSubmit(event: React.FormEvent<HTMLFormElement>) {\n\t\tevent.preventDefault();\n\t\ttrySubmit();\n\t}\n\n\treturn (\n\t\t<form\n\t\t\t{...rest}\n\t\t\tonSubmit={handleSubmit}\n\t\t\tclassName={cn(\n\t\t\t\t\"flex items-end gap-2 rounded-lg border bg-background p-2\",\n\t\t\t\t\"focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2\",\n\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<textarea\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(event) => onValueChange(event.target.value)}\n\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tplaceholder={placeholder}\n\t\t\t\taria-label={textareaAriaLabel ?? placeholder ?? \"Message\"}\n\t\t\t\trows={1}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex-1 resize-none bg-transparent px-2 py-1.5 text-sm leading-6\",\n\t\t\t\t\t\"placeholder:text-muted-foreground focus:outline-none\",\n\t\t\t\t\t\"disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\t\"max-h-48 min-h-[2.25rem] overflow-y-auto\",\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t{children}\n\t\t</form>\n\t);\n}\n\nexport { Composer };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/composer/composer.tsx"],"names":[],"mappings":";;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACoCA,SAAS,QAAA,CAAS;AAAA,EACjB,KAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA,GAAgB,IAAA;AAAA,EAChB,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACJ,CAAA,EAAkB;AACjB,EAAA,SAAS,SAAA,GAAY;AACpB,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,IAAI,CAAC,WAAW,QAAA,EAAU;AAC1B,IAAA,QAAA,CAAS,OAAO,CAAA;AAAA,EACjB;AAEA,EAAA,SAAS,cAAc,KAAA,EAAiD;AACvE,IAAA,IAAI,CAAC,aAAA,EAAe;AACpB,IAAA,IAAI,KAAA,CAAM,QAAQ,OAAA,IAAW,CAAC,MAAM,QAAA,IAAY,CAAC,KAAA,CAAM,WAAA,CAAY,WAAA,EAAa;AAC/E,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,SAAA,EAAU;AAAA,IACX;AAAA,EACD;AAEA,EAAA,SAAS,aAAa,KAAA,EAAyC;AAC9D,IAAA,KAAA,CAAM,cAAA,EAAe;AACrB,IAAA,SAAA,EAAU;AAAA,EACX;AAEA,EAAA,uBACC,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,GAAG,IAAA;AAAA,MACJ,QAAA,EAAU,YAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACV,0DAAA;AAAA,QACA,uEAAA;AAAA,QACA,iEAAA;AAAA,QACA;AAAA,OACD;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACA,KAAA;AAAA,YACA,UAAU,CAAC,KAAA,KAAU,aAAA,CAAc,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,YACrD,SAAA,EAAW,aAAA;AAAA,YACX,QAAA;AAAA,YACA,WAAA;AAAA,YACA,YAAA,EAAY,qBAAqB,WAAA,IAAe,SAAA;AAAA,YAChD,IAAA,EAAM,CAAA;AAAA,YACN,SAAA,EAAW,EAAA;AAAA,cACV,iEAAA;AAAA,cACA,sDAAA;AAAA,cACA,iDAAA;AAAA,cACA;AAAA;AACD;AAAA,SACD;AAAA,QACC;AAAA;AAAA;AAAA,GACF;AAEF","file":"composer.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 * Multi-line text input + submission shell for chat composers. Headless on\n * data flow — `value`/`onValueChange` are required so the consumer keeps\n * input state wherever fits (a `useChat` hook, a parent form, local state).\n *\n * Submits on Enter (without Shift). Children render after the textarea —\n * the canonical place for attachment buttons + a send button.\n *\n * Spreads remaining props onto the underlying `<form>`, so consumers can\n * pass `aria-label`, `id`, `name`, `data-*`, and similar attributes.\n *\n * @example\n * <Composer\n * value={input}\n * onValueChange={setInput}\n * onSubmit={(v) => sendMessage(v)}\n * placeholder=\"Ask anything…\"\n * >\n * <Button type=\"submit\">Send</Button>\n * </Composer>\n */\nexport interface ComposerProps\n\textends Omit<React.FormHTMLAttributes<HTMLFormElement>, \"onSubmit\" | \"children\"> {\n\tvalue: string;\n\tonValueChange: (value: string) => void;\n\tonSubmit: (value: string) => void;\n\tdisabled?: boolean;\n\tplaceholder?: string;\n\t/** Submit on Enter without Shift. Default true. */\n\tsubmitOnEnter?: boolean;\n\t/** Accessible name for the textarea. Defaults to `placeholder` when set, else \"Message\". */\n\ttextareaAriaLabel?: string;\n\t/** Trailing slot — attachment buttons, send button, etc. */\n\tchildren?: React.ReactNode;\n}\n\n/**\n * Renders a chat composer with a textarea + slot for action buttons.\n * @param props - controlled value/handlers + slot children\n * @returns A form element with a textarea and trailing slot\n */\nfunction Composer({\n\tvalue,\n\tonValueChange,\n\tonSubmit,\n\tdisabled,\n\tplaceholder,\n\tsubmitOnEnter = true,\n\ttextareaAriaLabel,\n\tchildren,\n\tclassName,\n\t...rest\n}: ComposerProps) {\n\tfunction trySubmit() {\n\t\tconst trimmed = value.trim();\n\t\tif (!trimmed || disabled) return;\n\t\tonSubmit(trimmed);\n\t}\n\n\tfunction handleKeyDown(event: React.KeyboardEvent<HTMLTextAreaElement>) {\n\t\tif (!submitOnEnter) return;\n\t\tif (event.key === \"Enter\" && !event.shiftKey && !event.nativeEvent.isComposing) {\n\t\t\tevent.preventDefault();\n\t\t\ttrySubmit();\n\t\t}\n\t}\n\n\tfunction handleSubmit(event: React.FormEvent<HTMLFormElement>) {\n\t\tevent.preventDefault();\n\t\ttrySubmit();\n\t}\n\n\treturn (\n\t\t<form\n\t\t\t{...rest}\n\t\t\tonSubmit={handleSubmit}\n\t\t\tclassName={cn(\n\t\t\t\t\"flex items-end gap-2 rounded-lg border bg-background p-2\",\n\t\t\t\t\"focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2\",\n\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<textarea\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(event) => onValueChange(event.target.value)}\n\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tplaceholder={placeholder}\n\t\t\t\taria-label={textareaAriaLabel ?? placeholder ?? \"Message\"}\n\t\t\t\trows={1}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex-1 resize-none bg-transparent px-2 py-1.5 text-sm leading-6\",\n\t\t\t\t\t\"placeholder:text-muted-foreground focus:outline-none\",\n\t\t\t\t\t\"disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\t\t\t\"max-h-48 min-h-[2.25rem] overflow-y-auto\",\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t{children}\n\t\t</form>\n\t);\n}\n\nexport { Composer };\n"]}
|
package/dist/container.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/primitives/container/container.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACEA,IAAM,iBAAA,GAAoB,IAAI,gBAAA,EAAkB;AAAA,EAC/C,QAAA,EAAU;AAAA,IACT,IAAA,EAAM;AAAA,MACL,EAAA,EAAI,mCAAA;AAAA,MACJ,EAAA,EAAI,mCAAA;AAAA,MACJ,EAAA,EAAI,mCAAA;AAAA,MACJ,EAAA,EAAI,mCAAA;AAAA,MACJ,IAAA,EAAM;AAAA,KACP;AAAA,IACA,OAAA,EAAS;AAAA,MACR,IAAA,EAAM,EAAA;AAAA,MACN,EAAA,EAAI,6BAAA;AAAA,MACJ,EAAA,EAAI,0BAAA;AAAA,MACJ,EAAA,EAAI;AAAA;AACL,GACD;AAAA,EACA,eAAA,EAAiB;AAAA,IAChB,IAAA,EAAM,IAAA;AAAA,IACN,OAAA,EAAS;AAAA;AAEX,CAAC;AA6BD,SAAS,SAAA,CAAU,EAAE,SAAA,EAAW,IAAA,EAAM,SAAS,OAAA,GAAU,KAAA,EAAO,GAAG,KAAA,EAAM,EAAmB;AAC3F,EAAA,MAAM,IAAA,GAAO,UAAU,IAAA,GAAO,KAAA;AAC9B,EAAA,uBAAO,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAW,EAAA,CAAG,iBAAA,CAAkB,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AACzF","file":"container.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 { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * CVA variants for Container — max-width wrapper bound to `--container-*` tokens.\n * Variant names match token names (`sm`/`md`/`lg`/`xl`/`full`); `full` removes the clamp.\n * Padding maps to `--space-*` tokens.\n */\nconst containerVariants = cva(\"mx-auto w-full\", {\n\tvariants: {\n\t\tsize: {\n\t\t\tsm: \"max-w-[var(--container-sm,33rem)]\",\n\t\t\tmd: \"max-w-[var(--container-md,40rem)]\",\n\t\t\tlg: \"max-w-[var(--container-lg,50rem)]\",\n\t\t\txl: \"max-w-[var(--container-xl,66rem)]\",\n\t\t\tfull: \"max-w-full\",\n\t\t},\n\t\tpadding: {\n\t\t\tnone: \"\",\n\t\t\tsm: \"px-[var(--space-3,0.75rem)]\",\n\t\t\tmd: \"px-[var(--space-4,1rem)]\",\n\t\t\tlg: \"px-[var(--space-8,2rem)]\",\n\t\t},\n\t},\n\tdefaultVariants: {\n\t\tsize: \"lg\",\n\t\tpadding: \"md\",\n\t},\n});\n\n/** Props for the Container component. */\nexport interface ContainerProps\n\textends React.HTMLAttributes<HTMLDivElement>,\n\t\tVariantProps<typeof containerVariants> {\n\t/**\n\t * Render as a different element via Radix `Slot`. Pass `<Container asChild><main>...</main></Container>`\n\t * to render the layout as a `<main>` (or `<section>`, `<article>`, etc.) and inherit landmark semantics.\n\t */\n\tasChild?: boolean;\n}\n\n/**\n * A centered max-width wrapper for page content. Use to constrain reading-width sections.\n * Pass `asChild` to render as a semantic landmark (`<main>`, `<section>`, etc.) instead of a plain `<div>`.\n *\n * @param props - Container props including `size`, `padding`, and optional `asChild`.\n * @returns A wrapper element with `mx-auto`, max-width clamp, and optional horizontal padding.\n * @example\n * ```tsx\n * <Container size=\"lg\" padding=\"md\" asChild>\n * <main>\n * <h1>Article title</h1>\n * <p>Reading-width content...</p>\n * </main>\n * </Container>\n * ```\n */\nfunction Container({ className, size, padding, asChild = false, ...props }: ContainerProps) {\n\tconst Comp = asChild ? Slot : \"div\";\n\treturn <Comp className={cn(containerVariants({ size, padding }), className)} {...props} />;\n}\n\nexport { Container, containerVariants };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/primitives/container/container.tsx"],"names":[],"mappings":";;;;;;AAQO,SAAS,MAAM,MAAA,EAAsB;AAC3C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC5B;ACEA,IAAM,iBAAA,GAAoB,IAAI,gBAAA,EAAkB;AAAA,EAC/C,QAAA,EAAU;AAAA,IACT,IAAA,EAAM;AAAA,MACL,EAAA,EAAI,mCAAA;AAAA,MACJ,EAAA,EAAI,mCAAA;AAAA,MACJ,EAAA,EAAI,mCAAA;AAAA,MACJ,EAAA,EAAI,mCAAA;AAAA,MACJ,IAAA,EAAM;AAAA,KACP;AAAA,IACA,OAAA,EAAS;AAAA,MACR,IAAA,EAAM,EAAA;AAAA,MACN,EAAA,EAAI,6BAAA;AAAA,MACJ,EAAA,EAAI,0BAAA;AAAA,MACJ,EAAA,EAAI;AAAA;AACL,GACD;AAAA,EACA,eAAA,EAAiB;AAAA,IAChB,IAAA,EAAM,IAAA;AAAA,IACN,OAAA,EAAS;AAAA;AAEX,CAAC;AA6BD,SAAS,SAAA,CAAU,EAAE,SAAA,EAAW,IAAA,EAAM,SAAS,OAAA,GAAU,KAAA,EAAO,GAAG,KAAA,EAAM,EAAmB;AAC3F,EAAA,MAAM,IAAA,GAAO,UAAU,IAAA,GAAO,KAAA;AAC9B,EAAA,uBAAO,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAW,EAAA,CAAG,iBAAA,CAAkB,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA,EAAG,SAAS,CAAA,EAAI,GAAG,KAAA,EAAO,CAAA;AACzF","file":"container.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 { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * CVA variants for Container — max-width wrapper bound to `--container-*` tokens.\n * Variant names match token names (`sm`/`md`/`lg`/`xl`/`full`); `full` removes the clamp.\n * Padding maps to `--space-*` tokens.\n */\nconst containerVariants = cva(\"mx-auto w-full\", {\n\tvariants: {\n\t\tsize: {\n\t\t\tsm: \"max-w-[var(--container-sm,33rem)]\",\n\t\t\tmd: \"max-w-[var(--container-md,40rem)]\",\n\t\t\tlg: \"max-w-[var(--container-lg,50rem)]\",\n\t\t\txl: \"max-w-[var(--container-xl,66rem)]\",\n\t\t\tfull: \"max-w-full\",\n\t\t},\n\t\tpadding: {\n\t\t\tnone: \"\",\n\t\t\tsm: \"px-[var(--space-3,0.75rem)]\",\n\t\t\tmd: \"px-[var(--space-4,1rem)]\",\n\t\t\tlg: \"px-[var(--space-8,2rem)]\",\n\t\t},\n\t},\n\tdefaultVariants: {\n\t\tsize: \"lg\",\n\t\tpadding: \"md\",\n\t},\n});\n\n/** Props for the Container component. */\nexport interface ContainerProps\n\textends React.HTMLAttributes<HTMLDivElement>,\n\t\tVariantProps<typeof containerVariants> {\n\t/**\n\t * Render as a different element via Radix `Slot`. Pass `<Container asChild><main>...</main></Container>`\n\t * to render the layout as a `<main>` (or `<section>`, `<article>`, etc.) and inherit landmark semantics.\n\t */\n\tasChild?: boolean;\n}\n\n/**\n * A centered max-width wrapper for page content. Use to constrain reading-width sections.\n * Pass `asChild` to render as a semantic landmark (`<main>`, `<section>`, etc.) instead of a plain `<div>`.\n *\n * @param props - Container props including `size`, `padding`, and optional `asChild`.\n * @returns A wrapper element with `mx-auto`, max-width clamp, and optional horizontal padding.\n * @example\n * ```tsx\n * <Container size=\"lg\" padding=\"md\" asChild>\n * <main>\n * <h1>Article title</h1>\n * <p>Reading-width content...</p>\n * </main>\n * </Container>\n * ```\n */\nfunction Container({ className, size, padding, asChild = false, ...props }: ContainerProps) {\n\tconst Comp = asChild ? Slot : \"div\";\n\treturn <Comp className={cn(containerVariants({ size, padding }), className)} {...props} />;\n}\n\nexport { Container, containerVariants };\n"]}
|