@hex-core/components 1.8.1 → 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 +855 -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.d.ts +2 -0
- package/dist/auth-forgot-password.js +400 -0
- package/dist/auth-forgot-password.js.map +1 -0
- package/dist/auth-reset-password.d.ts +2 -0
- package/dist/auth-reset-password.js +323 -0
- package/dist/auth-reset-password.js.map +1 -0
- package/dist/auth-sign-in-split.d.ts +3 -0
- package/dist/auth-sign-in-split.js +443 -0
- package/dist/auth-sign-in-split.js.map +1 -0
- package/dist/auth-sign-up-card.d.ts +3 -0
- package/dist/auth-sign-up-card.js +590 -0
- package/dist/auth-sign-up-card.js.map +1 -0
- package/dist/auth-verify-email.d.ts +2 -0
- package/dist/auth-verify-email.js +339 -0
- package/dist/auth-verify-email.js.map +1 -0
- package/dist/auth-verify-otp.d.ts +2 -0
- package/dist/auth-verify-otp.js +349 -0
- package/dist/auth-verify-otp.js.map +1 -0
- 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 +40 -0
- package/dist/index.js +4839 -2813
- 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 +9 -4
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"]}
|
package/dist/context-menu.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/context-menu/context-menu.tsx"],"names":[],"mappings":"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","file":"context-menu.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 ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a context menu (right-click menu). */\nconst ContextMenu = ContextMenuPrimitive.Root;\n\n/** The element that triggers the context menu on right-click. */\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\n\n/** Groups related items for a11y. */\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\n\n/** Portals content into the body. */\nconst ContextMenuPortal = ContextMenuPrimitive.Portal;\n\n/** Group for checkable radio items. */\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\n\n/** The menu panel shown when the trigger is right-clicked. */\nconst ContextMenuContent = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\n>(({ className, ...props }, ref) => (\n\t<ContextMenuPrimitive.Portal>\n\t\t<ContextMenuPrimitive.Content\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 min-w-[8rem] overflow-hidden rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-1,0.25rem)] text-popover-foreground shadow-md\",\n\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</ContextMenuPrimitive.Portal>\n));\nContextMenuContent.displayName = \"ContextMenuContent\";\n\n/** A clickable menu item. */\nconst ContextMenuItem = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<ContextMenuPrimitive.Item\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center gap-[var(--gap-sm,0.5rem)] rounded-sm px-[var(--space-2,0.5rem)] py-1.5 text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tinset && \"pl-[var(--space-8,2rem)]\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nContextMenuItem.displayName = \"ContextMenuItem\";\n\n/** A checkable menu item. */\nconst ContextMenuCheckboxItem = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.CheckboxItem>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n\t<ContextMenuPrimitive.CheckboxItem\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-[var(--space-8,2rem)] pr-[var(--space-2,0.5rem)] text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tclassName,\n\t\t)}\n\t\tchecked={checked}\n\t\t{...props}\n\t>\n\t\t<span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t<ContextMenuPrimitive.ItemIndicator>\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=\"3\"\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<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t\t</svg>\n\t\t\t</ContextMenuPrimitive.ItemIndicator>\n\t\t</span>\n\t\t{children}\n\t</ContextMenuPrimitive.CheckboxItem>\n));\nContextMenuCheckboxItem.displayName = \"ContextMenuCheckboxItem\";\n\n/** A radio menu item. */\nconst ContextMenuRadioItem = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.RadioItem>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n\t<ContextMenuPrimitive.RadioItem\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-[var(--space-8,2rem)] pr-[var(--space-2,0.5rem)] text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t>\n\t\t<span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t<ContextMenuPrimitive.ItemIndicator>\n\t\t\t\t<svg viewBox=\"0 0 24 24\" className=\"h-2 w-2 fill-current\" aria-hidden=\"true\">\n\t\t\t\t\t<circle cx=\"12\" cy=\"12\" r=\"10\" />\n\t\t\t\t</svg>\n\t\t\t</ContextMenuPrimitive.ItemIndicator>\n\t\t</span>\n\t\t{children}\n\t</ContextMenuPrimitive.RadioItem>\n));\nContextMenuRadioItem.displayName = \"ContextMenuRadioItem\";\n\n/** A non-interactive heading label. */\nconst ContextMenuLabel = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.Label>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<ContextMenuPrimitive.Label\n\t\tref={ref}\n\t\tclassName={cn(\"px-[var(--space-2,0.5rem)] py-1.5 text-sm font-semibold text-foreground\", inset && \"pl-[var(--space-8,2rem)]\", className)}\n\t\t{...props}\n\t/>\n));\nContextMenuLabel.displayName = \"ContextMenuLabel\";\n\n/** Horizontal divider. */\nconst ContextMenuSeparator = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.Separator>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n\t<ContextMenuPrimitive.Separator\n\t\tref={ref}\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] my-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nContextMenuSeparator.displayName = \"ContextMenuSeparator\";\n\n/**\n * Right-aligned shortcut text (e.g. ⌘⇧N).\n * @returns A span with muted typography\n */\nfunction ContextMenuShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport {\n\tContextMenu,\n\tContextMenuTrigger,\n\tContextMenuContent,\n\tContextMenuItem,\n\tContextMenuCheckboxItem,\n\tContextMenuRadioItem,\n\tContextMenuLabel,\n\tContextMenuSeparator,\n\tContextMenuShortcut,\n\tContextMenuGroup,\n\tContextMenuPortal,\n\tContextMenuRadioGroup,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/context-menu/context-menu.tsx"],"names":[],"mappings":"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","file":"context-menu.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 ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** Root container for a context menu (right-click menu). */\nconst ContextMenu = ContextMenuPrimitive.Root;\n\n/** The element that triggers the context menu on right-click. */\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\n\n/** Groups related items for a11y. */\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\n\n/** Portals content into the body. */\nconst ContextMenuPortal = ContextMenuPrimitive.Portal;\n\n/** Group for checkable radio items. */\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\n\n/** The menu panel shown when the trigger is right-clicked. */\nconst ContextMenuContent = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.Content>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\n>(({ className, ...props }, ref) => (\n\t<ContextMenuPrimitive.Portal>\n\t\t<ContextMenuPrimitive.Content\n\t\t\tref={ref}\n\t\t\tclassName={cn(\n\t\t\t\t\"z-50 min-w-[8rem] overflow-hidden rounded-md border border-foreground/[0.08] bg-popover p-[var(--space-1,0.25rem)] text-popover-foreground shadow-md\",\n\t\t\t\t\"data-[state=open]:animate-in data-[state=closed]:animate-out\",\n\t\t\t\t\"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n\t\t\t\t\"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t</ContextMenuPrimitive.Portal>\n));\nContextMenuContent.displayName = \"ContextMenuContent\";\n\n/** A clickable menu item. */\nconst ContextMenuItem = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.Item>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<ContextMenuPrimitive.Item\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center gap-[var(--gap-sm,0.5rem)] rounded-sm px-[var(--space-2,0.5rem)] py-1.5 text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tinset && \"pl-[var(--space-8,2rem)]\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nContextMenuItem.displayName = \"ContextMenuItem\";\n\n/** A checkable menu item. */\nconst ContextMenuCheckboxItem = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.CheckboxItem>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n\t<ContextMenuPrimitive.CheckboxItem\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-[var(--space-8,2rem)] pr-[var(--space-2,0.5rem)] text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tclassName,\n\t\t)}\n\t\tchecked={checked}\n\t\t{...props}\n\t>\n\t\t<span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t<ContextMenuPrimitive.ItemIndicator>\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=\"3\"\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<polyline points=\"20 6 9 17 4 12\" />\n\t\t\t\t</svg>\n\t\t\t</ContextMenuPrimitive.ItemIndicator>\n\t\t</span>\n\t\t{children}\n\t</ContextMenuPrimitive.CheckboxItem>\n));\nContextMenuCheckboxItem.displayName = \"ContextMenuCheckboxItem\";\n\n/** A radio menu item. */\nconst ContextMenuRadioItem = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.RadioItem>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n\t<ContextMenuPrimitive.RadioItem\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-[var(--space-8,2rem)] pr-[var(--space-2,0.5rem)] text-sm outline-none\",\n\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\"focus:bg-accent focus:text-accent-foreground\",\n\t\t\t\"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t>\n\t\t<span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n\t\t\t<ContextMenuPrimitive.ItemIndicator>\n\t\t\t\t<svg viewBox=\"0 0 24 24\" className=\"h-2 w-2 fill-current\" aria-hidden=\"true\">\n\t\t\t\t\t<circle cx=\"12\" cy=\"12\" r=\"10\" />\n\t\t\t\t</svg>\n\t\t\t</ContextMenuPrimitive.ItemIndicator>\n\t\t</span>\n\t\t{children}\n\t</ContextMenuPrimitive.RadioItem>\n));\nContextMenuRadioItem.displayName = \"ContextMenuRadioItem\";\n\n/** A non-interactive heading label. */\nconst ContextMenuLabel = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.Label>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n\t<ContextMenuPrimitive.Label\n\t\tref={ref}\n\t\tclassName={cn(\"px-[var(--space-2,0.5rem)] py-1.5 text-sm font-semibold text-foreground\", inset && \"pl-[var(--space-8,2rem)]\", className)}\n\t\t{...props}\n\t/>\n));\nContextMenuLabel.displayName = \"ContextMenuLabel\";\n\n/** Horizontal divider. */\nconst ContextMenuSeparator = React.forwardRef<\n\tReact.ComponentRef<typeof ContextMenuPrimitive.Separator>,\n\tReact.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n\t<ContextMenuPrimitive.Separator\n\t\tref={ref}\n\t\tclassName={cn(\"-mx-[var(--space-1,0.25rem)] my-[var(--space-1,0.25rem)] h-px bg-foreground/[0.12]\", className)}\n\t\t{...props}\n\t/>\n));\nContextMenuSeparator.displayName = \"ContextMenuSeparator\";\n\n/**\n * Right-aligned shortcut text (e.g. ⌘⇧N).\n * @returns A span with muted typography\n */\nfunction ContextMenuShortcut({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport {\n\tContextMenu,\n\tContextMenuTrigger,\n\tContextMenuContent,\n\tContextMenuItem,\n\tContextMenuCheckboxItem,\n\tContextMenuRadioItem,\n\tContextMenuLabel,\n\tContextMenuSeparator,\n\tContextMenuShortcut,\n\tContextMenuGroup,\n\tContextMenuPortal,\n\tContextMenuRadioGroup,\n};\n"]}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { clsx } from 'clsx';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
6
|
+
import { cva } from 'class-variance-authority';
|
|
7
|
+
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
|
|
8
|
+
|
|
9
|
+
function cn(...inputs) {
|
|
10
|
+
return twMerge(clsx(inputs));
|
|
11
|
+
}
|
|
12
|
+
var SAFE_URL_SCHEMES = ["http:", "https:", "mailto:"];
|
|
13
|
+
function safeUrl(raw) {
|
|
14
|
+
if (raw === void 0 || raw === "") return void 0;
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = new URL(raw);
|
|
18
|
+
} catch {
|
|
19
|
+
return raw.includes(":") ? void 0 : raw;
|
|
20
|
+
}
|
|
21
|
+
return SAFE_URL_SCHEMES.some((scheme) => scheme === parsed.protocol) ? raw : void 0;
|
|
22
|
+
}
|
|
23
|
+
function Composer({
|
|
24
|
+
value,
|
|
25
|
+
onValueChange,
|
|
26
|
+
onSubmit,
|
|
27
|
+
disabled,
|
|
28
|
+
placeholder,
|
|
29
|
+
submitOnEnter = true,
|
|
30
|
+
textareaAriaLabel,
|
|
31
|
+
children,
|
|
32
|
+
className,
|
|
33
|
+
...rest
|
|
34
|
+
}) {
|
|
35
|
+
function trySubmit() {
|
|
36
|
+
const trimmed = value.trim();
|
|
37
|
+
if (!trimmed || disabled) return;
|
|
38
|
+
onSubmit(trimmed);
|
|
39
|
+
}
|
|
40
|
+
function handleKeyDown(event) {
|
|
41
|
+
if (!submitOnEnter) return;
|
|
42
|
+
if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
trySubmit();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function handleSubmit(event) {
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
trySubmit();
|
|
50
|
+
}
|
|
51
|
+
return /* @__PURE__ */ jsxs(
|
|
52
|
+
"form",
|
|
53
|
+
{
|
|
54
|
+
...rest,
|
|
55
|
+
onSubmit: handleSubmit,
|
|
56
|
+
className: cn(
|
|
57
|
+
"flex items-end gap-2 rounded-lg border bg-background p-2",
|
|
58
|
+
"focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
|
|
59
|
+
"transition-all duration-[var(--duration-normal,200ms)] ease-out",
|
|
60
|
+
className
|
|
61
|
+
),
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ jsx(
|
|
64
|
+
"textarea",
|
|
65
|
+
{
|
|
66
|
+
value,
|
|
67
|
+
onChange: (event) => onValueChange(event.target.value),
|
|
68
|
+
onKeyDown: handleKeyDown,
|
|
69
|
+
disabled,
|
|
70
|
+
placeholder,
|
|
71
|
+
"aria-label": textareaAriaLabel ?? placeholder ?? "Message",
|
|
72
|
+
rows: 1,
|
|
73
|
+
className: cn(
|
|
74
|
+
"flex-1 resize-none bg-transparent px-2 py-1.5 text-sm leading-6",
|
|
75
|
+
"placeholder:text-muted-foreground focus:outline-none",
|
|
76
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
77
|
+
"max-h-48 min-h-[2.25rem] overflow-y-auto"
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
children
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
var messageVariants = cva(
|
|
87
|
+
[
|
|
88
|
+
"flex w-full gap-3 px-4 py-3 text-sm",
|
|
89
|
+
"transition-colors duration-[var(--duration-normal,200ms)] ease-out"
|
|
90
|
+
].join(" "),
|
|
91
|
+
{
|
|
92
|
+
variants: {
|
|
93
|
+
role: {
|
|
94
|
+
user: "bg-secondary/40 text-foreground",
|
|
95
|
+
assistant: "bg-card text-card-foreground",
|
|
96
|
+
system: "bg-muted text-muted-foreground italic",
|
|
97
|
+
tool: "bg-accent/15 text-accent-foreground border-l-2 border-accent"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
defaultVariants: {
|
|
101
|
+
role: "assistant"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
function Message({ role, className, children, ...props }) {
|
|
106
|
+
return /* @__PURE__ */ jsx("div", { "data-role": role, className: cn(messageVariants({ role }), className), ...props, children });
|
|
107
|
+
}
|
|
108
|
+
var NEAR_BOTTOM_THRESHOLD_PX = 80;
|
|
109
|
+
function MessageList({
|
|
110
|
+
autoScroll = true,
|
|
111
|
+
className,
|
|
112
|
+
children,
|
|
113
|
+
...props
|
|
114
|
+
}) {
|
|
115
|
+
const ref = React.useRef(null);
|
|
116
|
+
const stickToBottomRef = React.useRef(true);
|
|
117
|
+
React.useEffect(() => {
|
|
118
|
+
const el = ref.current;
|
|
119
|
+
if (!el || !autoScroll) return;
|
|
120
|
+
if (stickToBottomRef.current) {
|
|
121
|
+
el.scrollTop = el.scrollHeight;
|
|
122
|
+
}
|
|
123
|
+
}, [autoScroll, children]);
|
|
124
|
+
function handleScroll(event) {
|
|
125
|
+
const el = event.currentTarget;
|
|
126
|
+
const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
127
|
+
stickToBottomRef.current = distance < NEAR_BOTTOM_THRESHOLD_PX;
|
|
128
|
+
props.onScroll?.(event);
|
|
129
|
+
}
|
|
130
|
+
return /* @__PURE__ */ jsx(
|
|
131
|
+
"div",
|
|
132
|
+
{
|
|
133
|
+
ref,
|
|
134
|
+
role: "log",
|
|
135
|
+
"aria-live": "polite",
|
|
136
|
+
"aria-relevant": "additions",
|
|
137
|
+
className: cn("flex flex-col overflow-y-auto", className),
|
|
138
|
+
...props,
|
|
139
|
+
onScroll: handleScroll,
|
|
140
|
+
children
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
function Shimmer({
|
|
145
|
+
width = "100%",
|
|
146
|
+
height = "1.5rem",
|
|
147
|
+
durationMs = 1500,
|
|
148
|
+
label = "Loading\u2026",
|
|
149
|
+
className
|
|
150
|
+
}) {
|
|
151
|
+
return /* @__PURE__ */ jsx(
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
role: "status",
|
|
155
|
+
"aria-label": label,
|
|
156
|
+
"aria-live": "polite",
|
|
157
|
+
className: cn(
|
|
158
|
+
// `motion-safe:` gates the pulse on `prefers-reduced-motion: no-preference` —
|
|
159
|
+
// users with reduce-motion get a static bar.
|
|
160
|
+
"motion-safe:animate-pulse rounded-md border border-foreground/[0.06] bg-muted",
|
|
161
|
+
className
|
|
162
|
+
),
|
|
163
|
+
style: {
|
|
164
|
+
width,
|
|
165
|
+
height,
|
|
166
|
+
animationDuration: `${durationMs}ms`
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
function Citation({ title, url, page, index, className, children }) {
|
|
172
|
+
const baseClasses = cn(
|
|
173
|
+
"inline-flex items-center gap-1.5 rounded-md border border-foreground/15 bg-card px-2 py-0.5 text-xs",
|
|
174
|
+
"transition-all duration-[var(--duration-normal,200ms)] ease-out",
|
|
175
|
+
className
|
|
176
|
+
);
|
|
177
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
178
|
+
typeof index === "number" ? /* @__PURE__ */ jsxs("span", { className: "font-mono text-[10px] font-semibold text-muted-foreground", children: [
|
|
179
|
+
"[",
|
|
180
|
+
index,
|
|
181
|
+
"]"
|
|
182
|
+
] }) : /* @__PURE__ */ jsx(DocGlyph, {}),
|
|
183
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: title }),
|
|
184
|
+
typeof page === "number" ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
185
|
+
"p.",
|
|
186
|
+
page
|
|
187
|
+
] }) : null,
|
|
188
|
+
children
|
|
189
|
+
] });
|
|
190
|
+
if (url) {
|
|
191
|
+
return /* @__PURE__ */ jsx(
|
|
192
|
+
"a",
|
|
193
|
+
{
|
|
194
|
+
href: url,
|
|
195
|
+
target: "_blank",
|
|
196
|
+
rel: "noreferrer noopener",
|
|
197
|
+
className: cn(
|
|
198
|
+
baseClasses,
|
|
199
|
+
"hover:border-foreground/30 hover:bg-secondary/40 hover:shadow-sm",
|
|
200
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
201
|
+
),
|
|
202
|
+
children: body
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
return /* @__PURE__ */ jsx("span", { className: baseClasses, children: body });
|
|
207
|
+
}
|
|
208
|
+
function DocGlyph() {
|
|
209
|
+
return /* @__PURE__ */ jsxs(
|
|
210
|
+
"svg",
|
|
211
|
+
{
|
|
212
|
+
"aria-hidden": true,
|
|
213
|
+
viewBox: "0 0 16 16",
|
|
214
|
+
width: "11",
|
|
215
|
+
height: "11",
|
|
216
|
+
fill: "none",
|
|
217
|
+
stroke: "currentColor",
|
|
218
|
+
strokeWidth: "1.5",
|
|
219
|
+
strokeLinecap: "round",
|
|
220
|
+
strokeLinejoin: "round",
|
|
221
|
+
className: "shrink-0 text-muted-foreground",
|
|
222
|
+
children: [
|
|
223
|
+
/* @__PURE__ */ jsx("path", { d: "M9 1.5H4.5A1.5 1.5 0 0 0 3 3v10a1.5 1.5 0 0 0 1.5 1.5h7A1.5 1.5 0 0 0 13 13V5.5L9 1.5z" }),
|
|
224
|
+
/* @__PURE__ */ jsx("path", { d: "M9 1.5V5.5h4" })
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
function Sources({ sources, defaultOpen = true, className }) {
|
|
230
|
+
if (sources.length === 0) return null;
|
|
231
|
+
const count = sources.length;
|
|
232
|
+
const headerLabel = count === 1 ? "1 source" : `${count} sources`;
|
|
233
|
+
return /* @__PURE__ */ jsxs(
|
|
234
|
+
CollapsiblePrimitive.Root,
|
|
235
|
+
{
|
|
236
|
+
defaultOpen,
|
|
237
|
+
className: cn(
|
|
238
|
+
"overflow-hidden rounded-md border border-border bg-card text-card-foreground",
|
|
239
|
+
className
|
|
240
|
+
),
|
|
241
|
+
children: [
|
|
242
|
+
/* @__PURE__ */ jsxs(
|
|
243
|
+
CollapsiblePrimitive.Trigger,
|
|
244
|
+
{
|
|
245
|
+
className: cn(
|
|
246
|
+
"group flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-muted-foreground",
|
|
247
|
+
"transition-all duration-[var(--duration-normal,200ms)] ease-out",
|
|
248
|
+
"hover:text-foreground",
|
|
249
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
250
|
+
),
|
|
251
|
+
children: [
|
|
252
|
+
/* @__PURE__ */ jsx(DocStackGlyph, {}),
|
|
253
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: headerLabel }),
|
|
254
|
+
/* @__PURE__ */ jsx(Chevron, {})
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
),
|
|
258
|
+
/* @__PURE__ */ jsx(CollapsiblePrimitive.Content, { className: "overflow-hidden border-t border-foreground/[0.06]", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-1.5 p-2", children: sources.map((s, i) => /* @__PURE__ */ jsx(
|
|
259
|
+
Citation,
|
|
260
|
+
{
|
|
261
|
+
title: s.title,
|
|
262
|
+
url: safeUrl(s.url),
|
|
263
|
+
page: s.page,
|
|
264
|
+
index: s.index ?? i + 1
|
|
265
|
+
},
|
|
266
|
+
`${s.url ?? s.title}-${i}`
|
|
267
|
+
)) }) })
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
function DocStackGlyph() {
|
|
273
|
+
return /* @__PURE__ */ jsxs(
|
|
274
|
+
"svg",
|
|
275
|
+
{
|
|
276
|
+
"aria-hidden": true,
|
|
277
|
+
viewBox: "0 0 16 16",
|
|
278
|
+
width: "12",
|
|
279
|
+
height: "12",
|
|
280
|
+
fill: "none",
|
|
281
|
+
stroke: "currentColor",
|
|
282
|
+
strokeWidth: "1.5",
|
|
283
|
+
strokeLinecap: "round",
|
|
284
|
+
strokeLinejoin: "round",
|
|
285
|
+
className: "shrink-0",
|
|
286
|
+
children: [
|
|
287
|
+
/* @__PURE__ */ jsx("path", { d: "M5 3h7l1.5 1.5V13H5V3z" }),
|
|
288
|
+
/* @__PURE__ */ jsx("path", { d: "M3 5v8.5L4.5 15H11" })
|
|
289
|
+
]
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
function Chevron() {
|
|
294
|
+
return /* @__PURE__ */ jsx(
|
|
295
|
+
"svg",
|
|
296
|
+
{
|
|
297
|
+
"aria-hidden": true,
|
|
298
|
+
viewBox: "0 0 16 16",
|
|
299
|
+
width: "12",
|
|
300
|
+
height: "12",
|
|
301
|
+
fill: "none",
|
|
302
|
+
stroke: "currentColor",
|
|
303
|
+
strokeWidth: "1.5",
|
|
304
|
+
strokeLinecap: "round",
|
|
305
|
+
strokeLinejoin: "round",
|
|
306
|
+
className: "ml-auto shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180",
|
|
307
|
+
children: /* @__PURE__ */ jsx("path", { d: "M4 6l4 4 4-4" })
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
function Conversation({
|
|
312
|
+
messages,
|
|
313
|
+
onSubmit,
|
|
314
|
+
placeholder = "Ask anything\u2026",
|
|
315
|
+
value: valueProp,
|
|
316
|
+
onValueChange: onValueChangeProp,
|
|
317
|
+
isStreaming = false,
|
|
318
|
+
sources,
|
|
319
|
+
disabled = false,
|
|
320
|
+
composerActions,
|
|
321
|
+
className
|
|
322
|
+
}) {
|
|
323
|
+
const [internalValue, setInternalValue] = React.useState("");
|
|
324
|
+
const isControlled = valueProp !== void 0;
|
|
325
|
+
const value = isControlled ? valueProp : internalValue;
|
|
326
|
+
const setValue = isControlled ? (next) => onValueChangeProp?.(next) : setInternalValue;
|
|
327
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production" && isControlled && typeof onValueChangeProp !== "function") {
|
|
328
|
+
console.warn(
|
|
329
|
+
"<Conversation>: `value` was passed without `onValueChange`. The composer will be read-only \u2014 pass both props together for controlled mode, or omit both to let the component manage state internally."
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
function handleSubmit(text) {
|
|
333
|
+
onSubmit(text);
|
|
334
|
+
setValue("");
|
|
335
|
+
}
|
|
336
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 flex-col gap-3", className), children: [
|
|
337
|
+
/* @__PURE__ */ jsxs(MessageList, { className: "min-h-0 flex-1", children: [
|
|
338
|
+
messages.map((m) => /* @__PURE__ */ jsx(Message, { role: m.role, children: m.content }, m.id)),
|
|
339
|
+
isStreaming ? /* @__PURE__ */ jsx(Message, { role: "assistant", children: /* @__PURE__ */ jsx(Shimmer, { width: "60%" }) }) : null
|
|
340
|
+
] }),
|
|
341
|
+
sources && sources.length > 0 ? /* @__PURE__ */ jsx(Sources, { sources }) : null,
|
|
342
|
+
/* @__PURE__ */ jsx(
|
|
343
|
+
Composer,
|
|
344
|
+
{
|
|
345
|
+
value,
|
|
346
|
+
onValueChange: setValue,
|
|
347
|
+
onSubmit: handleSubmit,
|
|
348
|
+
disabled,
|
|
349
|
+
placeholder,
|
|
350
|
+
children: composerActions
|
|
351
|
+
}
|
|
352
|
+
)
|
|
353
|
+
] });
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export { Conversation };
|
|
357
|
+
//# sourceMappingURL=conversation.js.map
|
|
358
|
+
//# sourceMappingURL=conversation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/ai/composer/composer.tsx","../src/ai/message/message.tsx","../src/ai/message-list/message-list.tsx","../src/ai/shimmer/shimmer.tsx","../src/ai/citation/citation.tsx","../src/ai/sources/sources.tsx","../src/ai/conversation/conversation.tsx"],"names":["jsx","jsxs","React2"],"mappings":"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","file":"conversation.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","import { type VariantProps, cva } from \"class-variance-authority\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\nimport type { Role } from \"../types.js\";\n\nconst messageVariants = cva(\n\t[\n\t\t\"flex w-full gap-3 px-4 py-3 text-sm\",\n\t\t\"transition-colors duration-[var(--duration-normal,200ms)] ease-out\",\n\t].join(\" \"),\n\t{\n\t\tvariants: {\n\t\t\trole: {\n\t\t\t\tuser: \"bg-secondary/40 text-foreground\",\n\t\t\t\tassistant: \"bg-card text-card-foreground\",\n\t\t\t\tsystem: \"bg-muted text-muted-foreground italic\",\n\t\t\t\ttool: \"bg-accent/15 text-accent-foreground border-l-2 border-accent\",\n\t\t\t},\n\t\t},\n\t\tdefaultVariants: {\n\t\t\trole: \"assistant\",\n\t\t},\n\t},\n);\n\n/**\n * Single chat message row. Renders content with role-specific styling and a\n * `data-role` attribute so consumers can target arbitrary roles via CSS.\n *\n * Headless: accepts any `children`. Pair with `Markdown` + `CodeBlock` for\n * assistant turns, with `ToolCall` for agent steps, or with plain strings.\n *\n * @example\n * <Message role=\"user\">What's the weather?</Message>\n * @example\n * <Message role=\"assistant\">\n * <Markdown>{streamingText}</Markdown>\n * <ToolCall name=\"getWeather\" state=\"result\" args={...} result={...} />\n * </Message>\n */\nexport interface MessageProps\n\textends Omit<React.HTMLAttributes<HTMLDivElement>, \"role\">,\n\t\tVariantProps<typeof messageVariants> {\n\t/** Speaker — drives variant styling and the `data-role` attribute. */\n\trole: Role;\n\tchildren: React.ReactNode;\n}\n\n/**\n * Renders a chat-message row scoped to one speaker.\n * @param props - role + content\n * @returns A styled div tagged with `data-role={role}`\n */\nfunction Message({ role, className, children, ...props }: MessageProps) {\n\treturn (\n\t\t<div data-role={role} className={cn(messageVariants({ role }), className)} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { Message, messageVariants };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Auto-scrolling viewport for a stream of chat messages. When `autoScroll`\n * is true (default), the container pins to the bottom whenever its content\n * changes — including during streaming token updates. Detects whether the\n * user has scrolled away from the bottom and pauses auto-scroll until they\n * scroll back, so reading earlier turns doesn't fight the stream.\n *\n * @example\n * <MessageList>\n * {messages.map((m) => <Message key={m.id} role={m.role}>{m.content}</Message>)}\n * </MessageList>\n */\nexport interface MessageListProps extends React.HTMLAttributes<HTMLDivElement> {\n\t/** Auto-scroll to bottom on content change (when user is already near the bottom). Default: true. */\n\tautoScroll?: boolean;\n\tchildren: React.ReactNode;\n}\n\nconst NEAR_BOTTOM_THRESHOLD_PX = 80;\n\n/**\n * Renders the scrolling message viewport.\n * @param props - children + autoScroll toggle\n * @returns A scrollable div that auto-pins to bottom when streaming\n */\nfunction MessageList({\n\tautoScroll = true,\n\tclassName,\n\tchildren,\n\t...props\n}: MessageListProps) {\n\tconst ref = React.useRef<HTMLDivElement>(null);\n\tconst stickToBottomRef = React.useRef(true);\n\n\tReact.useEffect(() => {\n\t\tconst el = ref.current;\n\t\tif (!el || !autoScroll) return;\n\t\tif (stickToBottomRef.current) {\n\t\t\tel.scrollTop = el.scrollHeight;\n\t\t}\n\t}, [autoScroll, children]);\n\n\tfunction handleScroll(event: React.UIEvent<HTMLDivElement>) {\n\t\tconst el = event.currentTarget;\n\t\tconst distance = el.scrollHeight - el.scrollTop - el.clientHeight;\n\t\tstickToBottomRef.current = distance < NEAR_BOTTOM_THRESHOLD_PX;\n\t\tprops.onScroll?.(event);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\trole=\"log\"\n\t\t\taria-live=\"polite\"\n\t\t\taria-relevant=\"additions\"\n\t\t\tclassName={cn(\"flex flex-col overflow-y-auto\", className)}\n\t\t\t{...props}\n\t\t\tonScroll={handleScroll}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n\nexport { MessageList };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Single-line streaming placeholder. Used during the dead-time between\n * a user submitting a prompt and the first stream token arriving — a\n * gradient sweep across a flat bar that signals \"the model is thinking\n * but hasn't started speaking yet.\"\n *\n * Wider than `<Loading>` (which is a multi-row skeleton) and narrower\n * than `<Skeleton>` (which is a sized placeholder block); use Shimmer\n * for the conversation pane, Loading for whole-screen states, Skeleton\n * for arbitrary placeholder shapes.\n *\n * @example\n * {isStreaming && <Shimmer width=\"80%\" />}\n */\nexport interface ShimmerProps {\n\t/** CSS width — accepts any width value (e.g. `\"60%\"`, `\"24rem\"`). Defaults to full width. */\n\twidth?: string;\n\t/** Override the default 1.5rem height for taller streaming bars. */\n\theight?: string;\n\t/** Sweep duration in ms. Defaults to 1500. */\n\tdurationMs?: number;\n\t/** Accessible label announced to screen readers. */\n\tlabel?: string;\n\tclassName?: string;\n}\n\n/**\n * Render a streaming placeholder bar.\n *\n * Uses Tailwind's `animate-pulse` for the loading effect — same\n * approach as `<Skeleton>` so consumers don't need extra global CSS or\n * keyframes. The `durationMs` prop scales the pulse cycle via a CSS\n * variable so the animation stays in pulse's vertical-opacity family\n * rather than introducing a custom sweep keyframe (which would\n * conflict with React 19's stricter style-tag handling).\n *\n * @param props - Optional sizing + duration + label overrides.\n * @returns A pulsing placeholder bar.\n */\nfunction Shimmer({\n\twidth = \"100%\",\n\theight = \"1.5rem\",\n\tdurationMs = 1500,\n\tlabel = \"Loading…\",\n\tclassName,\n}: ShimmerProps) {\n\treturn (\n\t\t<div\n\t\t\trole=\"status\"\n\t\t\taria-label={label}\n\t\t\taria-live=\"polite\"\n\t\t\tclassName={cn(\n\t\t\t\t// `motion-safe:` gates the pulse on `prefers-reduced-motion: no-preference` —\n\t\t\t\t// users with reduce-motion get a static bar.\n\t\t\t\t\"motion-safe:animate-pulse rounded-md border border-foreground/[0.06] bg-muted\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tstyle={{\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tanimationDuration: `${durationMs}ms`,\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nexport { Shimmer };\n","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Source attribution chip — renders a citation for a RAG hit, search\n * result, or any external reference the assistant pulled from. Becomes a\n * clickable anchor when `url` is provided; otherwise a static span.\n *\n * @example\n * <Citation title=\"auth-overview.md\" url={src.url} page={3} />\n * @example\n * <Cluster gap=\"xs\">\n * {sources.map((s, i) => (\n * <Citation key={s.id} title={s.title} url={s.url} index={i + 1} />\n * ))}\n * </Cluster>\n */\nexport interface CitationProps {\n\ttitle: string;\n\turl?: string;\n\tpage?: number;\n\t/** Numeric index for inline footnote-style display (e.g. \"[1] auth.md\"). */\n\tindex?: number;\n\tclassName?: string;\n\tchildren?: React.ReactNode;\n}\n\n/**\n * Renders a source citation chip. Uses an `<a>` when `url` is set so the\n * chip is keyboard-focusable + opens in a new tab; falls back to a\n * non-interactive span otherwise.\n *\n * @param props - title + optional url, page, index\n * @returns An anchor or span styled as a chip\n */\nfunction Citation({ title, url, page, index, className, children }: CitationProps) {\n\tconst baseClasses = cn(\n\t\t\"inline-flex items-center gap-1.5 rounded-md border border-foreground/15 bg-card px-2 py-0.5 text-xs\",\n\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\tclassName,\n\t);\n\n\tconst body = (\n\t\t<>\n\t\t\t{typeof index === \"number\" ? (\n\t\t\t\t<span className=\"font-mono text-[10px] font-semibold text-muted-foreground\">[{index}]</span>\n\t\t\t) : (\n\t\t\t\t<DocGlyph />\n\t\t\t)}\n\t\t\t<span className=\"truncate text-foreground\">{title}</span>\n\t\t\t{typeof page === \"number\" ? (\n\t\t\t\t<span className=\"text-muted-foreground\">p.{page}</span>\n\t\t\t) : null}\n\t\t\t{children}\n\t\t</>\n\t);\n\n\tif (url) {\n\t\treturn (\n\t\t\t<a\n\t\t\t\thref={url}\n\t\t\t\ttarget=\"_blank\"\n\t\t\t\trel=\"noreferrer noopener\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\tbaseClasses,\n\t\t\t\t\t\"hover:border-foreground/30 hover:bg-secondary/40 hover:shadow-sm\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{body}\n\t\t\t</a>\n\t\t);\n\t}\n\n\treturn <span className={baseClasses}>{body}</span>;\n}\n\nfunction DocGlyph() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"11\"\n\t\t\theight=\"11\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"shrink-0 text-muted-foreground\"\n\t\t>\n\t\t\t<path d=\"M9 1.5H4.5A1.5 1.5 0 0 0 3 3v10a1.5 1.5 0 0 0 1.5 1.5h7A1.5 1.5 0 0 0 13 13V5.5L9 1.5z\" />\n\t\t\t<path d=\"M9 1.5V5.5h4\" />\n\t\t</svg>\n\t);\n}\n\nexport { Citation };\n","\"use client\";\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\nimport * as React from \"react\";\nimport { cn, safeUrl } from \"../../lib/utils.js\";\nimport { Citation } from \"../citation/citation.js\";\n\n/**\n * Bordered card listing 1–N citation chips for a RAG response.\n *\n * Header reads \"N sources\" and is a clickable Radix Collapsible trigger;\n * body renders one `<Citation>` per source (re-using the in-house chip).\n * Defaults to open so consumers don't have to expand to see what was\n * cited.\n *\n * @example\n * <Sources\n * sources={[\n * { title: \"Auth research\", url: \"https://example.com/auth\", page: 3 },\n * { title: \"OAuth 2.1 spec\", url: \"https://oauth.net/2.1\" },\n * ]}\n * />\n */\nexport interface SourcesProps {\n\t/** Citation rows. Each becomes a `<Citation>` chip. */\n\tsources: SourceRef[];\n\t/** Whether the list is expanded by default. */\n\tdefaultOpen?: boolean;\n\tclassName?: string;\n}\n\n/** Per-source data passed to a Citation chip. */\nexport interface SourceRef {\n\ttitle: string;\n\turl?: string;\n\tpage?: number;\n\t/** Optional 1-based index. Falls back to array position. Use to keep\n\t * the inline `<InlineCitation>` index aligned with the panel row when\n\t * the model emits non-1-based numbering. */\n\tindex?: number;\n}\n\n/**\n * Render a sources panel for an LLM response. Returns null when the\n * sources array is empty — consumers don't get a \"0 sources\" empty\n * card; they just don't render the panel at all.\n *\n * @param props - The list of sources + open-state default.\n * @returns A Collapsible wrapping a Citation cluster, or null if empty.\n */\nfunction Sources({ sources, defaultOpen = true, className }: SourcesProps) {\n\tif (sources.length === 0) return null;\n\tconst count = sources.length;\n\tconst headerLabel = count === 1 ? \"1 source\" : `${count} sources`;\n\n\treturn (\n\t\t<CollapsiblePrimitive.Root\n\t\t\tdefaultOpen={defaultOpen}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-hidden rounded-md border border-border bg-card text-card-foreground\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<CollapsiblePrimitive.Trigger\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"group flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-muted-foreground\",\n\t\t\t\t\t\"transition-all duration-[var(--duration-normal,200ms)] ease-out\",\n\t\t\t\t\t\"hover:text-foreground\",\n\t\t\t\t\t\"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<DocStackGlyph />\n\t\t\t\t<span className=\"font-medium\">{headerLabel}</span>\n\t\t\t\t<Chevron />\n\t\t\t</CollapsiblePrimitive.Trigger>\n\t\t\t<CollapsiblePrimitive.Content className=\"overflow-hidden border-t border-foreground/[0.06]\">\n\t\t\t\t<div className=\"flex flex-wrap items-center gap-1.5 p-2\">\n\t\t\t\t\t{sources.map((s, i) => (\n\t\t\t\t\t\t<Citation\n\t\t\t\t\t\t\tkey={`${s.url ?? s.title}-${i}`}\n\t\t\t\t\t\t\ttitle={s.title}\n\t\t\t\t\t\t\t// Gate the URL even though markdown-path callers already\n\t\t\t\t\t\t\t// route through `safeUrl` — direct-JSX consumers can hand\n\t\t\t\t\t\t\t// us anything.\n\t\t\t\t\t\t\turl={safeUrl(s.url)}\n\t\t\t\t\t\t\tpage={s.page}\n\t\t\t\t\t\t\tindex={s.index ?? i + 1}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</CollapsiblePrimitive.Content>\n\t\t</CollapsiblePrimitive.Root>\n\t);\n}\n\nfunction DocStackGlyph() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"12\"\n\t\t\theight=\"12\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"shrink-0\"\n\t\t>\n\t\t\t<path d=\"M5 3h7l1.5 1.5V13H5V3z\" />\n\t\t\t<path d=\"M3 5v8.5L4.5 15H11\" />\n\t\t</svg>\n\t);\n}\n\nfunction Chevron() {\n\treturn (\n\t\t<svg\n\t\t\taria-hidden\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\twidth=\"12\"\n\t\t\theight=\"12\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tclassName=\"ml-auto shrink-0 transition-transform duration-200 group-data-[state=open]:rotate-180\"\n\t\t>\n\t\t\t<path d=\"M4 6l4 4 4-4\" />\n\t\t</svg>\n\t);\n}\n\nexport { Sources };\n","\"use client\";\n\nimport * as React from \"react\";\nimport { Composer } from \"../composer/composer.js\";\nimport { Message } from \"../message/message.js\";\nimport { MessageList } from \"../message-list/message-list.js\";\nimport { Shimmer } from \"../shimmer/shimmer.js\";\nimport { Sources, type SourceRef } from \"../sources/sources.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n// Local ambient — bundlers (Next, Vite, tsup) replace `process.env.NODE_ENV`\n// at build time. Avoids pulling @types/node into the components package just\n// for the controlled-mode dev-warning. Same pattern as slider.tsx.\ndeclare const process: { env?: { NODE_ENV?: string } } | undefined;\n\n/**\n * Speaker of a message. Mirrors the canonical `Role` union from\n * `@hex-core/components` exactly — kept inline (rather than imported\n * from `../types.js`) so the registry CLI distribution path (`npx hex\n * add conversation`) ships a self-contained file. Same precedent as\n * `task.tsx`'s inlined `ToolCallState`. The build-registry script\n * doesn't bundle `types.ts`, so importing from it would leave consumer\n * TS strict-mode unable to resolve the type at the install location.\n */\ntype Role = \"user\" | \"assistant\" | \"system\" | \"tool\";\n\n/**\n * High-level chat shell. Composes `<MessageList>` over `messages`, an\n * optional `<Sources>` panel beneath the latest assistant turn, an\n * optional `<Shimmer>` placeholder for the in-flight assistant response,\n * and a `<Composer>` row at the bottom.\n *\n * Presentational: the consumer owns the `messages` array and the\n * `onSubmit` handler. The composer's text state is internal by default\n * so simple consumers don't thread input plumbing; pass `value` +\n * `onValueChange` together to take full control (suggested-prompt\n * injection, voice transcription, form-library integration).\n *\n * @example\n * <Conversation\n * messages={messages}\n * onSubmit={(text) => sendMessage(text)}\n * isStreaming={isWaitingForFirstToken}\n * sources={lastResponse.sources}\n * placeholder=\"Ask anything…\"\n * />\n */\nexport interface ConversationProps {\n\t/** Ordered chat history. Each item renders as one `<Message>`. */\n\tmessages: ConversationMessage[];\n\t/** Called with the trimmed text when the user submits the composer. */\n\tonSubmit: (text: string) => void;\n\t/** Composer placeholder. */\n\tplaceholder?: string;\n\t/** Controlled composer text. Pass with `onValueChange` to take control of the input — useful for suggested prompts, voice transcripts, or form-library integration. */\n\tvalue?: string;\n\t/** Called whenever the composer text changes. Required when `value` is set. */\n\tonValueChange?: (value: string) => void;\n\t/** When true, render a `<Shimmer>` placeholder above the composer (use during the dead time before the first stream token). */\n\tisStreaming?: boolean;\n\t/** Optional citations rendered as a `<Sources>` panel beneath the message stream. */\n\tsources?: SourceRef[];\n\t/** Disable the composer (e.g. while waiting on a tool call). */\n\tdisabled?: boolean;\n\t/** Trailing slot inside the composer — typically a Send button. */\n\tcomposerActions?: React.ReactNode;\n\tclassName?: string;\n}\n\n/** A single message in a `<Conversation>`. */\nexport interface ConversationMessage {\n\t/** Stable identifier — used for the React key. */\n\tid: string;\n\t/** Speaker. */\n\trole: Role;\n\t/** Message content. Pass a string for plain text or a node (e.g. `<Markdown>`) for formatted output. */\n\tcontent: React.ReactNode;\n}\n\n/**\n * Render a chat conversation shell.\n * @param props - messages + submit handler + optional streaming/sources state\n * @returns A flex column with a scrolling message list, optional sources/shimmer, and a composer row\n */\nfunction Conversation({\n\tmessages,\n\tonSubmit,\n\tplaceholder = \"Ask anything…\",\n\tvalue: valueProp,\n\tonValueChange: onValueChangeProp,\n\tisStreaming = false,\n\tsources,\n\tdisabled = false,\n\tcomposerActions,\n\tclassName,\n}: ConversationProps) {\n\tconst [internalValue, setInternalValue] = React.useState(\"\");\n\tconst isControlled = valueProp !== undefined;\n\tconst value = isControlled ? valueProp : internalValue;\n\tconst setValue = isControlled\n\t\t? (next: string) => onValueChangeProp?.(next)\n\t\t: setInternalValue;\n\n\tif (\n\t\ttypeof process !== \"undefined\" &&\n\t\tprocess.env?.NODE_ENV !== \"production\" &&\n\t\tisControlled &&\n\t\ttypeof onValueChangeProp !== \"function\"\n\t) {\n\t\t// Surface the controlled-mode contract at runtime — `value` without\n\t\t// `onValueChange` makes the textarea silently read-only, which is a\n\t\t// frustrating debug. Schema commonMistakes flags it too, but a console\n\t\t// nudge catches it in the dev loop.\n\t\tconsole.warn(\n\t\t\t\"<Conversation>: `value` was passed without `onValueChange`. The composer will be read-only — pass both props together for controlled mode, or omit both to let the component manage state internally.\",\n\t\t);\n\t}\n\n\tfunction handleSubmit(text: string) {\n\t\tonSubmit(text);\n\t\tsetValue(\"\");\n\t}\n\n\treturn (\n\t\t<div className={cn(\"flex h-full min-h-0 flex-col gap-3\", className)}>\n\t\t\t<MessageList className=\"min-h-0 flex-1\">\n\t\t\t\t{messages.map((m) => (\n\t\t\t\t\t<Message key={m.id} role={m.role}>\n\t\t\t\t\t\t{m.content}\n\t\t\t\t\t</Message>\n\t\t\t\t))}\n\t\t\t\t{isStreaming ? (\n\t\t\t\t\t<Message role=\"assistant\">\n\t\t\t\t\t\t<Shimmer width=\"60%\" />\n\t\t\t\t\t</Message>\n\t\t\t\t) : null}\n\t\t\t</MessageList>\n\t\t\t{sources && sources.length > 0 ? <Sources sources={sources} /> : null}\n\t\t\t<Composer\n\t\t\t\tvalue={value}\n\t\t\t\tonValueChange={setValue}\n\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\tdisabled={disabled}\n\t\t\t\tplaceholder={placeholder}\n\t\t\t>\n\t\t\t\t{composerActions}\n\t\t\t</Composer>\n\t\t</div>\n\t);\n}\n\nexport { Conversation };\n"]}
|
package/dist/data-table.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/table/table.tsx","../src/components/data-table/data-table.tsx"],"names":["jsx"],"mappings":"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","file":"data-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","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** A responsive container + styled HTML table. */\nconst Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(\n\t({ className, ...props }, ref) => (\n\t\t<div className=\"relative w-full overflow-auto\">\n\t\t\t<table\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\"w-full caption-bottom text-sm\", className)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</div>\n\t),\n);\nTable.displayName = \"Table\";\n\n/** `<thead>` wrapper with bottom border. */\nconst TableHeader = React.forwardRef<\n\tHTMLTableSectionElement,\n\tReact.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n\t<thead ref={ref} className={cn(\"[&_tr]:border-b [&_tr]:border-b-foreground/[0.08]\", className)} {...props} />\n));\nTableHeader.displayName = \"TableHeader\";\n\n/** `<tbody>` wrapper removing bottom border on last row. */\nconst TableBody = React.forwardRef<\n\tHTMLTableSectionElement,\n\tReact.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n\t<tbody ref={ref} className={cn(\"[&_tr:last-child]:border-0\", className)} {...props} />\n));\nTableBody.displayName = \"TableBody\";\n\n/** `<tfoot>` wrapper with muted background. */\nconst TableFooter = React.forwardRef<\n\tHTMLTableSectionElement,\n\tReact.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n\t<tfoot\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"border-t border-t-foreground/[0.08] bg-muted/50 font-medium [&>tr]:last:border-b-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTableFooter.displayName = \"TableFooter\";\n\n/** `<tr>` with hover + selected states. */\nconst TableRow = React.forwardRef<\n\tHTMLTableRowElement,\n\tReact.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n\t<tr\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"border-b border-b-foreground/[0.08] transition-all duration-[var(--duration-normal,200ms)] ease-out hover:bg-muted/50 data-[state=selected]:bg-muted\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTableRow.displayName = \"TableRow\";\n\n/** `<th>` with left-aligned muted text. */\nconst TableHead = React.forwardRef<\n\tHTMLTableCellElement,\n\tReact.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n\t<th\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"h-[var(--control-height-md,2.5rem)] px-[var(--space-4,1rem)] text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTableHead.displayName = \"TableHead\";\n\n/** `<td>` with consistent padding. */\nconst TableCell = React.forwardRef<\n\tHTMLTableCellElement,\n\tReact.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n\t<td\n\t\tref={ref}\n\t\tclassName={cn(\"p-[var(--space-4,1rem)] align-middle [&:has([role=checkbox])]:pr-0\", className)}\n\t\t{...props}\n\t/>\n));\nTableCell.displayName = \"TableCell\";\n\n/**\n * Visible `<caption>` rendered below the table. The parent `<Table>` sets\n * `caption-bottom`, so the caption is announced first by screen readers when\n * entering the table, then visually placed below the rows.\n */\nconst TableCaption = React.forwardRef<\n\tHTMLTableCaptionElement,\n\tReact.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n\t<caption\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"caption-bottom mt-[var(--space-4,1rem)] text-sm text-muted-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTableCaption.displayName = \"TableCaption\";\n\nexport {\n\tTable,\n\tTableHeader,\n\tTableBody,\n\tTableFooter,\n\tTableHead,\n\tTableRow,\n\tTableCell,\n\tTableCaption,\n};\n","\"use client\";\n\nimport * as React from \"react\";\nimport {\n\ttype ColumnDef,\n\tflexRender,\n\tgetCoreRowModel,\n\tuseReactTable,\n} from \"@tanstack/react-table\";\nimport {\n\tTable,\n\tTableBody,\n\tTableCaption,\n\tTableCell,\n\tTableHead,\n\tTableHeader,\n\tTableRow,\n} from \"../table/table.js\";\n\n/**\n * Generic DataTable wrapper that renders a TanStack Table model using Hex Core's\n * Table primitives. Pass columns + data; use TanStack hooks for sorting,\n * filtering, pagination, row-selection as needed.\n * @template TData - Row data type. Cell value types are inferred per column by TanStack.\n */\nexport interface DataTableProps<TData> {\n\tcolumns: ColumnDef<TData, unknown>[];\n\tdata: TData[];\n\t/**\n\t * Visible caption rendered below the table. Announced by screen readers\n\t * when the user enters the table. Provide either `caption` or `aria-label`.\n\t */\n\tcaption?: React.ReactNode;\n\t/**\n\t * Accessible label for the table when no visible caption is shown.\n\t * Forwarded as `aria-label` on the underlying `<table>` element. Kebab-case\n\t * to match the canonical ARIA prop convention used elsewhere in Hex Core.\n\t */\n\t\"aria-label\"?: string;\n}\n\n/**\n * Render a data-driven table from TanStack column definitions.\n * @param props - Columns, data, and optional accessible labelling (`caption` or `aria-label`)\n * @returns A styled Table rendered from the TanStack row model\n */\nexport function DataTable<TData>({\n\tcolumns,\n\tdata,\n\tcaption,\n\t\"aria-label\": ariaLabel,\n}: DataTableProps<TData>) {\n\tconst table = useReactTable({\n\t\tdata,\n\t\tcolumns,\n\t\tgetCoreRowModel: getCoreRowModel(),\n\t});\n\n\treturn (\n\t\t<div className=\"rounded-md border border-foreground/[0.08]\">\n\t\t\t<Table aria-label={ariaLabel}>\n\t\t\t\t{caption ? <TableCaption>{caption}</TableCaption> : null}\n\t\t\t\t<TableHeader>\n\t\t\t\t\t{table.getHeaderGroups().map((headerGroup) => (\n\t\t\t\t\t\t<TableRow key={headerGroup.id}>\n\t\t\t\t\t\t\t{headerGroup.headers.map((header) => (\n\t\t\t\t\t\t\t\t<TableHead key={header.id}>\n\t\t\t\t\t\t\t\t\t{header.isPlaceholder\n\t\t\t\t\t\t\t\t\t\t? null\n\t\t\t\t\t\t\t\t\t\t: flexRender(header.column.columnDef.header, header.getContext())}\n\t\t\t\t\t\t\t\t</TableHead>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t))}\n\t\t\t\t</TableHeader>\n\t\t\t\t<TableBody>\n\t\t\t\t\t{table.getRowModel().rows?.length ? (\n\t\t\t\t\t\ttable.getRowModel().rows.map((row) => (\n\t\t\t\t\t\t\t<TableRow key={row.id} data-state={row.getIsSelected() && \"selected\"}>\n\t\t\t\t\t\t\t\t{row.getVisibleCells().map((cell) => (\n\t\t\t\t\t\t\t\t\t<TableCell key={cell.id}>\n\t\t\t\t\t\t\t\t\t\t{flexRender(cell.column.columnDef.cell, cell.getContext())}\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t))\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t<TableCell colSpan={columns.length} className=\"h-24 text-center\">\n\t\t\t\t\t\t\t\tNo results.\n\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t)}\n\t\t\t\t</TableBody>\n\t\t\t</Table>\n\t\t</div>\n\t);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/table/table.tsx","../src/components/data-table/data-table.tsx"],"names":["jsx"],"mappings":"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","file":"data-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","import * as React from \"react\";\nimport { cn } from \"../../lib/utils.js\";\n\n/** A responsive container + styled HTML table. */\nconst Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(\n\t({ className, ...props }, ref) => (\n\t\t<div className=\"relative w-full overflow-auto\">\n\t\t\t<table\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\"w-full caption-bottom text-sm\", className)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</div>\n\t),\n);\nTable.displayName = \"Table\";\n\n/** `<thead>` wrapper with bottom border. */\nconst TableHeader = React.forwardRef<\n\tHTMLTableSectionElement,\n\tReact.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n\t<thead ref={ref} className={cn(\"[&_tr]:border-b [&_tr]:border-b-foreground/[0.08]\", className)} {...props} />\n));\nTableHeader.displayName = \"TableHeader\";\n\n/** `<tbody>` wrapper removing bottom border on last row. */\nconst TableBody = React.forwardRef<\n\tHTMLTableSectionElement,\n\tReact.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n\t<tbody ref={ref} className={cn(\"[&_tr:last-child]:border-0\", className)} {...props} />\n));\nTableBody.displayName = \"TableBody\";\n\n/** `<tfoot>` wrapper with muted background. */\nconst TableFooter = React.forwardRef<\n\tHTMLTableSectionElement,\n\tReact.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n\t<tfoot\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"border-t border-t-foreground/[0.08] bg-muted/50 font-medium [&>tr]:last:border-b-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTableFooter.displayName = \"TableFooter\";\n\n/** `<tr>` with hover + selected states. */\nconst TableRow = React.forwardRef<\n\tHTMLTableRowElement,\n\tReact.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n\t<tr\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"border-b border-b-foreground/[0.08] transition-all duration-[var(--duration-normal,200ms)] ease-out hover:bg-muted/50 data-[state=selected]:bg-muted\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTableRow.displayName = \"TableRow\";\n\n/** `<th>` with left-aligned muted text. */\nconst TableHead = React.forwardRef<\n\tHTMLTableCellElement,\n\tReact.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n\t<th\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"h-[var(--control-height-md,2.5rem)] px-[var(--space-4,1rem)] text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTableHead.displayName = \"TableHead\";\n\n/** `<td>` with consistent padding. */\nconst TableCell = React.forwardRef<\n\tHTMLTableCellElement,\n\tReact.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n\t<td\n\t\tref={ref}\n\t\tclassName={cn(\"p-[var(--space-4,1rem)] align-middle [&:has([role=checkbox])]:pr-0\", className)}\n\t\t{...props}\n\t/>\n));\nTableCell.displayName = \"TableCell\";\n\n/**\n * Visible `<caption>` rendered below the table. The parent `<Table>` sets\n * `caption-bottom`, so the caption is announced first by screen readers when\n * entering the table, then visually placed below the rows.\n */\nconst TableCaption = React.forwardRef<\n\tHTMLTableCaptionElement,\n\tReact.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n\t<caption\n\t\tref={ref}\n\t\tclassName={cn(\n\t\t\t\"caption-bottom mt-[var(--space-4,1rem)] text-sm text-muted-foreground\",\n\t\t\tclassName,\n\t\t)}\n\t\t{...props}\n\t/>\n));\nTableCaption.displayName = \"TableCaption\";\n\nexport {\n\tTable,\n\tTableHeader,\n\tTableBody,\n\tTableFooter,\n\tTableHead,\n\tTableRow,\n\tTableCell,\n\tTableCaption,\n};\n","\"use client\";\n\nimport * as React from \"react\";\nimport {\n\ttype ColumnDef,\n\tflexRender,\n\tgetCoreRowModel,\n\tuseReactTable,\n} from \"@tanstack/react-table\";\nimport {\n\tTable,\n\tTableBody,\n\tTableCaption,\n\tTableCell,\n\tTableHead,\n\tTableHeader,\n\tTableRow,\n} from \"../table/table.js\";\n\n/**\n * Generic DataTable wrapper that renders a TanStack Table model using Hex Core's\n * Table primitives. Pass columns + data; use TanStack hooks for sorting,\n * filtering, pagination, row-selection as needed.\n * @template TData - Row data type. Cell value types are inferred per column by TanStack.\n */\nexport interface DataTableProps<TData> {\n\tcolumns: ColumnDef<TData, unknown>[];\n\tdata: TData[];\n\t/**\n\t * Visible caption rendered below the table. Announced by screen readers\n\t * when the user enters the table. Provide either `caption` or `aria-label`.\n\t */\n\tcaption?: React.ReactNode;\n\t/**\n\t * Accessible label for the table when no visible caption is shown.\n\t * Forwarded as `aria-label` on the underlying `<table>` element. Kebab-case\n\t * to match the canonical ARIA prop convention used elsewhere in Hex Core.\n\t */\n\t\"aria-label\"?: string;\n}\n\n/**\n * Render a data-driven table from TanStack column definitions.\n * @param props - Columns, data, and optional accessible labelling (`caption` or `aria-label`)\n * @returns A styled Table rendered from the TanStack row model\n */\nexport function DataTable<TData>({\n\tcolumns,\n\tdata,\n\tcaption,\n\t\"aria-label\": ariaLabel,\n}: DataTableProps<TData>) {\n\tconst table = useReactTable({\n\t\tdata,\n\t\tcolumns,\n\t\tgetCoreRowModel: getCoreRowModel(),\n\t});\n\n\treturn (\n\t\t<div className=\"rounded-md border border-foreground/[0.08]\">\n\t\t\t<Table aria-label={ariaLabel}>\n\t\t\t\t{caption ? <TableCaption>{caption}</TableCaption> : null}\n\t\t\t\t<TableHeader>\n\t\t\t\t\t{table.getHeaderGroups().map((headerGroup) => (\n\t\t\t\t\t\t<TableRow key={headerGroup.id}>\n\t\t\t\t\t\t\t{headerGroup.headers.map((header) => (\n\t\t\t\t\t\t\t\t<TableHead key={header.id}>\n\t\t\t\t\t\t\t\t\t{header.isPlaceholder\n\t\t\t\t\t\t\t\t\t\t? null\n\t\t\t\t\t\t\t\t\t\t: flexRender(header.column.columnDef.header, header.getContext())}\n\t\t\t\t\t\t\t\t</TableHead>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t))}\n\t\t\t\t</TableHeader>\n\t\t\t\t<TableBody>\n\t\t\t\t\t{table.getRowModel().rows?.length ? (\n\t\t\t\t\t\ttable.getRowModel().rows.map((row) => (\n\t\t\t\t\t\t\t<TableRow key={row.id} data-state={row.getIsSelected() && \"selected\"}>\n\t\t\t\t\t\t\t\t{row.getVisibleCells().map((cell) => (\n\t\t\t\t\t\t\t\t\t<TableCell key={cell.id}>\n\t\t\t\t\t\t\t\t\t\t{flexRender(cell.column.columnDef.cell, cell.getContext())}\n\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t))\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t<TableCell colSpan={columns.length} className=\"h-24 text-center\">\n\t\t\t\t\t\t\t\tNo results.\n\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t)}\n\t\t\t\t</TableBody>\n\t\t\t</Table>\n\t\t</div>\n\t);\n}\n"]}
|