@humain/ui 2.4.0 → 2.4.2
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/index150.js +1 -1
- package/dist/index150.js.map +1 -1
- package/dist/wc/AIInput.js +31 -31
- package/dist/wc/AIInput.js.map +1 -1
- package/dist/wc-react/AIInput.js +1 -1
- package/dist/wc-react/AIInput.js.map +1 -1
- package/package.json +1 -1
- package/skills/humain-ui/SKILL.md +1 -1
- package/skills/humain-ui-wc/SKILL.md +1 -1
- package/skills/humain-ui-wc.skill +0 -0
- package/skills/humain-ui.skill +0 -0
package/dist/index150.js
CHANGED
|
@@ -172,7 +172,7 @@ function AIInputDefaultButton({ customButton, disabled }) {
|
|
|
172
172
|
if (customButton) return customButton(buttonProps);
|
|
173
173
|
return /* @__PURE__ */ jsx(SubmitButton, {
|
|
174
174
|
icon: ArrowUp,
|
|
175
|
-
|
|
175
|
+
disabled: true
|
|
176
176
|
});
|
|
177
177
|
}
|
|
178
178
|
function AIInputRoot({ children, variant = "default", value: controlledValue, defaultValue = "", onChange, onSubmit, uploadingFiles = [], onRemoveFile, onCancelUpload, onRetryUpload, onRemoveAllFiles, disabled = false, className, onFilesSelected, accept, multiple = true, dropText = "Drop files to attach", pasteAsFile }) {
|
package/dist/index150.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index150.js","names":[],"sources":["../src/components/organisms/ai/AIInput/AIInput.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { ArrowDown, ArrowUp, X } from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { FileUploadItem } from '@/components/molecules/files/FileUpload';\nimport {\n matchesAcceptToken,\n toFileList,\n useDropZone,\n} from '@/hooks/use-drop-zone';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn } from '@/lib/utils';\nimport { analyzePaste, mapKindToFile, type PasteKind } from './paste-detection';\n\n// =============================================================================\n// Shared Styles\n// =============================================================================\n\nconst textareaClasses =\n 'flex-1 h-[40px] resize-none overflow-y-auto bg-transparent text-base text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground';\n\nconst compactTextareaClasses =\n 'flex-1 h-[32px] resize-none overflow-y-auto bg-transparent text-base leading-6 text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst inputVariants = cva(\n 'flex items-center w-full transition-[color,background-color,border-color,box-shadow,opacity]',\n {\n variants: {\n state: {\n default: '',\n focused: '',\n withText: '',\n disabled: 'cursor-not-allowed',\n attachments: '',\n dragover: '',\n },\n variant: {\n default: 'flex-col gap-2 py-4 px-4 rounded-[inherit]',\n compact: 'flex-row gap-2 py-4 px-4 rounded-[inherit]',\n inline: 'flex-row gap-2 px-4 py-4 rounded-[inherit]',\n },\n },\n defaultVariants: {\n state: 'default',\n variant: 'default',\n },\n },\n);\n\nfunction getAIInputShellClassName({\n state,\n variant,\n className,\n}: {\n state: VariantProps<typeof inputVariants>['state'];\n variant: 'default' | 'compact' | 'inline';\n className?: string;\n}) {\n const isDefault = variant === 'default';\n const isDisabled = state === 'disabled';\n const isPrimaryState =\n state === 'focused' ||\n state === 'withText' ||\n state === 'attachments' ||\n state === 'dragover';\n const isStrongState =\n state === 'focused' || state === 'withText' || state === 'dragover';\n\n return cn(\n 'relative w-full overflow-hidden border bg-background shadow-[var(--shadow-ai-input)] transition-[color,background-color,border-color,box-shadow,opacity] duration-150 ease-out',\n isDefault ? 'rounded-3xl max-w-[772px]' : 'rounded-2xl',\n isDisabled\n ? 'border-border bg-muted'\n : isPrimaryState\n ? 'border-primary'\n : 'border-ring/50 hover:border-primary',\n isStrongState ? 'border-2' : 'border-[1.25px]',\n className,\n );\n}\n\n// =============================================================================\n// Drop Overlay (shared across all variants)\n// =============================================================================\n\nfunction DropOverlay({\n isDefault,\n dropText,\n}: {\n isDefault: boolean;\n dropText: string;\n}) {\n return (\n <div\n data-slot=\"ai-input-drop-overlay\"\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n 'delight-drop-enter absolute inset-1.5 border-2 border-dashed border-primary/50 dark:border-primary/60 pointer-events-none flex flex-col items-center justify-center gap-1.5 z-10',\n isDefault ? 'rounded-[calc(1.5rem-8px)]' : 'rounded-[calc(1rem-8px)]',\n )}\n >\n <ArrowDown className=\"size-4 text-primary/70 delight-drop-icon\" />\n <span className=\"text-sm text-muted-foreground font-medium\">\n {dropText}\n </span>\n </div>\n );\n}\n\nDropOverlay.displayName = 'AIInput.DropOverlay';\n\n// =============================================================================\n// File Attachment Types\n// =============================================================================\n\nexport interface UploadingFile {\n id: string;\n name: string;\n size: string;\n progress: number;\n status: 'uploading' | 'complete' | 'error';\n /** File extension for icon display (e.g., 'pdf', 'docx') */\n fileExtension?: string;\n}\n\n// =============================================================================\n// Paste-as-File public types\n// =============================================================================\n\nexport type { PasteKind } from './paste-detection';\n\nexport interface PasteAsFileConfig {\n /** Char count above which plain text always converts. Default: 500 */\n threshold?: number;\n /** Line count above which plain text always converts. Default: 10 */\n lineThreshold?: number;\n /** Run structured-content heuristics (JSON/XML/CSV/code/log). Default: true */\n detectStructured?: boolean;\n /**\n * Auto-fill textarea after conversion. Receives filename + detected kind.\n * Return string to set as textarea value (appended with leading space if textarea non-empty).\n * Empty/whitespace-only return is treated as no-op.\n * Default: undefined → textarea stays empty.\n */\n prefillTemplate?: (filename: string, kind: PasteKind) => string;\n /** Fired after onFilesSelected and prefill. */\n onConverted?: (filename: string, kind: PasteKind) => void;\n}\n\n/**\n * Accepts boolean for runtime toggling. `false` and `undefined` both disable.\n * `true` enables with defaults. Object enables with overrides.\n */\nexport type PasteAsFileProp = boolean | PasteAsFileConfig;\n\n// =============================================================================\n// usePasteAsFile — internal hook\n// =============================================================================\n\ninterface UsePasteAsFileOpts {\n pasteAsFile: PasteAsFileProp | undefined;\n onFilesSelected: ((files: FileList) => void) | undefined;\n accept: string | undefined;\n disabled: boolean;\n variant: 'default' | 'compact' | 'inline';\n value: string;\n setValue: (next: string) => void;\n}\n\nfunction usePasteAsFile(opts: UsePasteAsFileOpts): {\n onPaste?: React.ClipboardEventHandler<HTMLTextAreaElement>;\n} {\n const counterRef = React.useRef(0);\n const warnedRef = React.useRef(false);\n const optsRef = React.useRef(opts);\n\n // Keep the ref pointing at the latest opts each render. This pattern lets the\n // returned `onPaste` be referentially stable (empty-deps useCallback) while\n // still seeing the freshest pasteAsFile config and callbacks.\n React.useEffect(() => {\n optsRef.current = opts;\n });\n\n const onPaste = React.useCallback<\n React.ClipboardEventHandler<HTMLTextAreaElement>\n >((e) => {\n const { pasteAsFile, onFilesSelected, accept, disabled, value, setValue } =\n optsRef.current;\n\n if (!pasteAsFile || disabled) return;\n\n const text = e.clipboardData.getData('text/plain');\n if (!text) return;\n\n const config: PasteAsFileConfig = pasteAsFile === true ? {} : pasteAsFile;\n\n const detectionOpts = {\n charThreshold: config.threshold,\n lineThreshold: config.lineThreshold,\n detectStructured: config.detectStructured,\n };\n\n const { shouldConvert, kind } = analyzePaste(text, detectionOpts);\n if (!shouldConvert) return;\n\n if (!onFilesSelected) {\n if (process.env.NODE_ENV !== 'production' && !warnedRef.current) {\n console.warn(\n '[AIInput] pasteAsFile is set but onFilesSelected is missing. Paste-to-file is a no-op.',\n );\n warnedRef.current = true;\n }\n return;\n }\n\n const { ext, mime } = mapKindToFile(kind);\n const nProspective = counterRef.current + 1;\n const filename = `Pasted-${nProspective}.${ext}`;\n\n if (\n accept &&\n !accept\n .split(',')\n .some((token) =>\n matchesAcceptToken({ name: filename, type: mime }, token),\n )\n ) {\n return;\n }\n\n let fileList: FileList;\n try {\n const file = new File([text], filename, { type: mime });\n fileList = toFileList([file]);\n } catch {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[AIInput] DataTransfer unavailable; falling back to native paste.',\n );\n }\n return;\n }\n\n e.preventDefault();\n counterRef.current = nProspective;\n onFilesSelected(fileList);\n\n if (config.prefillTemplate) {\n const tpl = config.prefillTemplate(filename, kind);\n if (tpl?.trim()) {\n setValue(value ? `${value} ${tpl}` : tpl);\n }\n }\n\n config.onConverted?.(filename, kind);\n }, []);\n\n if (opts.variant === 'inline' || !opts.pasteAsFile) {\n return { onPaste: undefined };\n }\n\n return { onPaste };\n}\n\n// =============================================================================\n// Context\n// =============================================================================\n\ninterface AIInputContextValue {\n /** Current input value */\n value: string;\n /** Whether the input has text */\n hasText: boolean;\n /** Whether the input is focused */\n isFocused: boolean;\n /** Whether the input is disabled */\n disabled: boolean;\n /** Visual variant */\n variant: 'default' | 'compact' | 'inline';\n /** Files being uploaded */\n uploadingFiles: UploadingFile[];\n /** Has attachments */\n hasAttachments: boolean;\n /** Update input value */\n setValue: (value: string) => void;\n /** Set focus state */\n setIsFocused: (focused: boolean) => void;\n /** Handle submit */\n handleSubmit: () => void;\n /** Handle key down */\n handleKeyDown: (\n e: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => void;\n /** Handle clear */\n handleClear: () => void;\n /** Paste handler from usePasteAsFile (only set when paste-as-file is active). */\n onPaste?: React.ClipboardEventHandler<HTMLTextAreaElement>;\n /** Remove file */\n onRemoveFile?: (fileId: string) => void;\n /** Cancel upload */\n onCancelUpload?: (fileId: string) => void;\n /** Retry failed upload */\n onRetryUpload?: (fileId: string) => void;\n /** Remove all files */\n onRemoveAllFiles?: () => void;\n /** Whether files are being dragged over the input */\n isDragging: boolean;\n /** Open the native file picker */\n openFilePicker: () => void;\n /** Callback when files are selected (via drop or picker) */\n onFilesSelected?: (files: FileList) => void;\n /** Textarea ref (for default variant) */\n textareaRef: React.RefObject<HTMLTextAreaElement | null>;\n /** Input ref (for compact variant) */\n inputRef: React.RefObject<HTMLInputElement | null>;\n}\n\nconst [AIInputContext, useAIInputContext] =\n createSafeContext<AIInputContextValue>('AIInput');\n\n// =============================================================================\n// Compound Components - Building Blocks\n// =============================================================================\n\nexport interface ActionButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Icon component to render */\n icon: React.ComponentType<{ className?: string }>;\n /** Tooltip text */\n tooltip?: string;\n}\n\nfunction ActionButton({\n icon: Icon,\n onClick,\n disabled,\n tooltip,\n className,\n ...props\n}: ActionButtonProps) {\n return (\n <button\n type=\"button\"\n data-slot=\"action-button\"\n onClick={onClick}\n disabled={disabled}\n title={tooltip}\n aria-label={tooltip}\n className={cn(\n 'p-2 rounded-full text-secondary-foreground hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n}\n\nActionButton.displayName = 'AIInput.ActionButton';\n\nexport interface SubmitButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {\n /** Icon component to render (defaults to ArrowUp) */\n icon?: React.ComponentType<{ className?: string }>;\n}\n\nfunction SubmitButton({\n icon: Icon = ArrowUp,\n className,\n onClick,\n disabled,\n ...props\n}: SubmitButtonProps) {\n return (\n <Button\n type=\"button\"\n data-slot=\"submit-button\"\n size=\"icon-sm\"\n onClick={onClick}\n disabled={disabled}\n aria-label=\"Send message\"\n className={cn(\n 'rounded-full bg-primary hover:bg-primary/90 text-primary-foreground disabled:bg-accent disabled:text-muted-foreground transition-colors duration-150 ease-out',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-4\" />\n </Button>\n );\n}\n\nSubmitButton.displayName = 'AIInput.SubmitButton';\n\nexport interface CompactActionButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {\n /** Icon component to render */\n icon: React.ComponentType<{ className?: string }>;\n /** Accessible label for the icon-only button (required for a11y) */\n 'aria-label': string;\n}\n\n/**\n * @deprecated Use `ActionButton` instead. CompactActionButton will be removed in a future major version.\n */\nfunction CompactActionButton({\n icon: Icon,\n className,\n onClick,\n disabled,\n ...props\n}: CompactActionButtonProps) {\n return (\n <Button\n type=\"button\"\n data-slot=\"compact-action-button\"\n onClick={onClick}\n disabled={disabled}\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"icon\"\n className={cn(\n 'rounded-full border-border text-foreground hover:bg-muted',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-5\" />\n </Button>\n );\n}\n\nCompactActionButton.displayName = 'AIInput.CompactActionButton';\n\nfunction RemoveAllButton({ onClick }: { onClick?: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label=\"Remove all attached files\"\n className=\"flex items-center gap-1.5 h-5 px-2 py-1 rounded-full bg-accent border border-border text-xs font-medium text-foreground hover:bg-accent/80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring transition-colors\"\n >\n <X className=\"size-4\" />\n Remove all\n </button>\n );\n}\n\nRemoveAllButton.displayName = 'AIInput.RemoveAllButton';\n\n// =============================================================================\n// Render Function Types (for monolithic API)\n// =============================================================================\n\n/** Props passed to custom submit button render function */\nexport interface SubmitButtonRenderProps {\n onClick: () => void;\n disabled: boolean;\n}\n\n/** Render function type for custom submit button */\nexport type SubmitButtonRenderFn = (\n props: SubmitButtonRenderProps,\n) => React.ReactElement;\n\n/** Props passed to custom default button render function */\nexport interface DefaultButtonRenderProps {\n disabled: boolean;\n}\n\n/** Render function type for custom default button */\nexport type DefaultButtonRenderFn = (\n props: DefaultButtonRenderProps,\n) => React.ReactElement;\n\nfunction AIInputSubmitButton({\n customButton,\n onClick,\n disabled,\n}: {\n customButton?: SubmitButtonRenderFn;\n onClick: () => void;\n disabled: boolean;\n}) {\n const buttonProps: SubmitButtonRenderProps = {\n onClick,\n disabled,\n };\n\n if (customButton) {\n return customButton(buttonProps);\n }\n\n return <SubmitButton {...buttonProps} />;\n}\n\nfunction AIInputDefaultButton({\n customButton,\n disabled,\n}: {\n customButton?: DefaultButtonRenderFn;\n disabled: boolean;\n}) {\n const buttonProps: DefaultButtonRenderProps = {\n disabled,\n };\n\n if (customButton) {\n return customButton(buttonProps);\n }\n\n return <SubmitButton icon={ArrowUp} {...buttonProps} />;\n}\n\n// =============================================================================\n// Composable Subcomponents (for dual-API)\n// =============================================================================\n\nexport interface AIInputRootProps {\n /** Children (composable subcomponents) */\n children: React.ReactNode;\n /** Visual variant of the input */\n variant?: 'default' | 'compact' | 'inline';\n /** Current input value (controlled) */\n value?: string;\n /** Default input value (uncontrolled) */\n defaultValue?: string;\n /** Callback when value changes */\n onChange?: (value: string) => void;\n /** Callback when message is submitted */\n onSubmit?: (message: string) => void;\n /** Files being uploaded */\n uploadingFiles?: UploadingFile[];\n /** Callback when file is removed */\n onRemoveFile?: (fileId: string) => void;\n /** Callback when file upload is cancelled */\n onCancelUpload?: (fileId: string) => void;\n /** Callback to retry a failed upload */\n onRetryUpload?: (fileId: string) => void;\n /** Callback to remove all files */\n onRemoveAllFiles?: () => void;\n /** Whether the input is disabled */\n disabled?: boolean;\n /** Additional class name */\n className?: string;\n /** Callback when files are selected (via drag-drop or file picker) */\n onFilesSelected?: (files: FileList) => void;\n /** Accepted file types (e.g. 'image/*,.pdf') */\n accept?: string;\n /** Allow multiple file selection */\n multiple?: boolean;\n /** Text shown in the drop overlay */\n dropText?: string;\n /** Convert large/structured paste into a file attachment. Requires onFilesSelected. */\n pasteAsFile?: PasteAsFileProp;\n}\n\nfunction AIInputRoot({\n children,\n variant = 'default',\n value: controlledValue,\n defaultValue = '',\n onChange,\n onSubmit,\n uploadingFiles = [],\n onRemoveFile,\n onCancelUpload,\n onRetryUpload,\n onRemoveAllFiles,\n disabled = false,\n className,\n onFilesSelected,\n accept,\n multiple = true,\n dropText = 'Drop files to attach',\n pasteAsFile,\n}: AIInputRootProps) {\n const [internalValue, setInternalValue] = React.useState(defaultValue);\n const [isFocused, setIsFocused] = React.useState(false);\n const textareaRef = React.useRef<HTMLTextAreaElement>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n\n const { isDragging, dropZoneProps, openFilePicker } = useDropZone({\n onFilesSelected,\n accept,\n multiple,\n disabled,\n containerRef: rootRef,\n });\n\n const isControlled = controlledValue !== undefined;\n const value = isControlled ? controlledValue : internalValue;\n const hasText = value.trim().length > 0;\n const hasAttachments = uploadingFiles.length > 0;\n const setValue = React.useCallback(\n (newValue: string) => {\n if (onChange) {\n onChange(newValue);\n }\n if (!isControlled) {\n setInternalValue(newValue);\n }\n },\n [onChange, isControlled],\n );\n\n const { onPaste } = usePasteAsFile({\n pasteAsFile,\n onFilesSelected,\n accept,\n disabled,\n variant,\n value,\n setValue,\n });\n\n const handleSubmit = React.useCallback(() => {\n if (hasText && onSubmit) {\n onSubmit(value);\n if (!isControlled) {\n setInternalValue('');\n }\n }\n }, [hasText, onSubmit, value, isControlled]);\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n },\n [handleSubmit],\n );\n\n const handleClear = React.useCallback(() => {\n setValue('');\n if (variant === 'inline') {\n inputRef.current?.focus();\n } else {\n textareaRef.current?.focus();\n }\n }, [setValue, variant]);\n\n // Determine visual state\n const getState = (): VariantProps<typeof inputVariants>['state'] => {\n if (disabled) return 'disabled';\n if (isDragging) return 'dragover';\n if (hasAttachments) return 'attachments';\n if (hasText) return 'withText';\n if (isFocused) return 'focused';\n return 'default';\n };\n\n const contextValue = React.useMemo<AIInputContextValue>(\n () => ({\n value,\n hasText,\n isFocused,\n disabled,\n variant,\n uploadingFiles,\n hasAttachments,\n setValue,\n setIsFocused,\n handleSubmit,\n handleKeyDown,\n handleClear,\n onPaste,\n onRemoveFile,\n onCancelUpload,\n onRetryUpload,\n onRemoveAllFiles,\n isDragging,\n openFilePicker,\n onFilesSelected,\n textareaRef,\n inputRef,\n }),\n [\n value,\n hasText,\n isFocused,\n disabled,\n variant,\n uploadingFiles,\n hasAttachments,\n setValue,\n handleSubmit,\n handleKeyDown,\n handleClear,\n onPaste,\n onRemoveFile,\n onCancelUpload,\n onRetryUpload,\n onRemoveAllFiles,\n isDragging,\n openFilePicker,\n onFilesSelected,\n ],\n );\n\n const isDefault = variant === 'default';\n const state = getState();\n\n return (\n <AIInputContext.Provider value={contextValue}>\n <div\n ref={rootRef}\n data-slot=\"ai-input\"\n data-dragging={isDragging}\n {...dropZoneProps}\n {...(onFilesSelected\n ? { 'aria-label': 'Chat input with file drop zone' }\n : {})}\n className={getAIInputShellClassName({ state, variant, className })}\n >\n <div\n data-slot=\"ai-input-inner\"\n className={cn(\n inputVariants({ state, variant }),\n 'relative',\n !isDefault && hasAttachments && 'flex-col items-stretch py-3',\n disabled && !isDefault ? 'bg-muted' : 'bg-background',\n 'rounded-[inherit]',\n disabled && isDefault && 'bg-muted',\n )}\n >\n {isDragging && (\n <DropOverlay isDefault={isDefault} dropText={dropText} />\n )}\n {children}\n </div>\n </div>\n </AIInputContext.Provider>\n );\n}\n\nAIInputRoot.displayName = 'AIInput.Root';\n\n// =============================================================================\n// AIInput.TextArea - The text input area\n// =============================================================================\n\nexport interface AIInputTextAreaProps {\n /** Placeholder text */\n placeholder?: string;\n /** Additional class name */\n className?: string;\n /** Show clear button when text is present */\n showClearButton?: boolean;\n}\n\nfunction AIInputTextArea({\n placeholder = 'How can HUMAIN ONE help you today?',\n className,\n showClearButton = true,\n}: AIInputTextAreaProps) {\n const ctx = useAIInputContext();\n const isInline = ctx.variant === 'inline';\n\n const handleChange = (\n e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => {\n ctx.setValue(e.target.value);\n };\n\n if (isInline) {\n return (\n <input\n ref={ctx.inputRef}\n data-slot=\"ai-input-text\"\n type=\"text\"\n value={ctx.value}\n onChange={handleChange}\n onFocus={() => ctx.setIsFocused(true)}\n onBlur={() => ctx.setIsFocused(false)}\n onKeyDown={ctx.handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={ctx.disabled}\n className={cn(\n 'flex-1 min-w-0 bg-transparent text-sm leading-5 text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground',\n className,\n )}\n />\n );\n }\n\n return (\n <div\n data-slot=\"ai-input-text-area\"\n className={cn(\n 'flex gap-2',\n ctx.variant === 'compact' && !ctx.hasAttachments\n ? 'min-w-0 flex-1 items-center'\n : 'w-full items-start',\n )}\n >\n <textarea\n ref={ctx.textareaRef}\n data-slot=\"ai-input-textarea\"\n value={ctx.value}\n onChange={handleChange}\n onPaste={ctx.onPaste}\n onFocus={() => ctx.setIsFocused(true)}\n onBlur={() => ctx.setIsFocused(false)}\n onKeyDown={ctx.handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={ctx.disabled}\n rows={1}\n className={cn(\n ctx.variant === 'compact' ? compactTextareaClasses : textareaClasses,\n className,\n )}\n />\n {showClearButton &&\n ctx.variant !== 'compact' &&\n ctx.hasText &&\n !ctx.disabled && (\n <button\n type=\"button\"\n onClick={ctx.handleClear}\n aria-label=\"Clear input\"\n className=\"p-2 rounded-full hover:bg-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring transition-colors duration-150 ease-out shrink-0\"\n >\n <X className=\"size-5 text-muted-foreground\" />\n </button>\n )}\n </div>\n );\n}\n\nAIInputTextArea.displayName = 'AIInput.TextArea';\n\n// =============================================================================\n// AIInput.LeadingIcon - Leading icon for inline variant\n// =============================================================================\n\nexport interface AIInputLeadingIconProps {\n /** Icon content (brand icon, spinner, avatar) */\n children: React.ReactNode;\n /** Additional class name */\n className?: string;\n}\n\nfunction AIInputLeadingIcon({ children, className }: AIInputLeadingIconProps) {\n return (\n <div\n data-slot=\"ai-input-leading-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'flex items-center justify-center shrink-0 size-9 rounded-xl bg-foreground/4 border border-border',\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nAIInputLeadingIcon.displayName = 'AIInput.LeadingIcon';\n\n// =============================================================================\n// AIInput.SendButton - The send/submit button\n// =============================================================================\n\nexport interface AIInputSendButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {\n /** Icon component to render */\n icon?: React.ComponentType<{ className?: string }>;\n}\n\nfunction AIInputSendButton({\n icon,\n className,\n ...props\n}: AIInputSendButtonProps) {\n const ctx = useAIInputContext();\n const Icon = icon ?? ArrowUp;\n\n return (\n <Button\n type=\"button\"\n data-slot=\"ai-input-send-button\"\n size=\"icon-sm\"\n onClick={ctx.handleSubmit}\n disabled={ctx.disabled || !ctx.hasText}\n aria-label=\"Send message\"\n className={cn(\n 'rounded-full bg-primary hover:bg-primary/90 text-primary-foreground disabled:bg-accent disabled:text-muted-foreground',\n 'transition-all duration-150 ease-out active:scale-90 motion-reduce:active:scale-100',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-4\" />\n </Button>\n );\n}\n\nAIInputSendButton.displayName = 'AIInput.SendButton';\n\n// =============================================================================\n// AIInput.AttachButton - Attach file button\n// =============================================================================\n\nexport interface AIInputAttachButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Icon component to render */\n icon: React.ComponentType<{ className?: string }>;\n /** Tooltip text */\n tooltip?: string;\n}\n\nfunction AIInputAttachButton({\n icon: Icon,\n tooltip,\n className,\n onClick,\n ...props\n}: AIInputAttachButtonProps) {\n const ctx = useAIInputContext();\n\n const handleClick = React.useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n if (onClick) {\n onClick(e);\n } else if (ctx.onFilesSelected) {\n ctx.openFilePicker();\n }\n },\n [onClick, ctx.onFilesSelected, ctx.openFilePicker],\n );\n\n return (\n <button\n type=\"button\"\n data-slot=\"ai-input-attach-button\"\n onClick={handleClick}\n disabled={ctx.disabled}\n title={tooltip}\n aria-label={tooltip ?? 'Attach file'}\n className={cn(\n 'p-2.5 min-h-11 min-w-11 flex items-center justify-center rounded-full text-secondary-foreground hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n}\n\nAIInputAttachButton.displayName = 'AIInput.AttachButton';\n\n// =============================================================================\n// AIInput.Actions - Container for action buttons\n// =============================================================================\n\nexport interface AIInputActionsProps {\n /** Children (action buttons) */\n children?: React.ReactNode;\n /** Position of actions */\n position?: 'leading' | 'trailing';\n /** Additional class name */\n className?: string;\n}\n\nfunction AIInputActions({\n children,\n position = 'leading',\n className,\n}: AIInputActionsProps) {\n return (\n <div\n data-slot=\"ai-input-actions\"\n data-position={position}\n className={cn('flex items-center gap-2', className)}\n >\n {children}\n </div>\n );\n}\n\nAIInputActions.displayName = 'AIInput.Actions';\n\n// =============================================================================\n// AIInput.ActionBar - The bottom action bar (for default variant)\n// =============================================================================\n\nexport interface AIInputActionBarProps {\n /** Children (leading actions, trailing actions, send button) */\n children?: React.ReactNode;\n /** Additional class name */\n className?: string;\n}\n\nfunction AIInputActionBar({ children, className }: AIInputActionBarProps) {\n const ctx = useAIInputContext();\n const isCompactRow = ctx.variant === 'compact' && !ctx.hasAttachments;\n\n return (\n <div\n data-slot=\"ai-input-action-bar\"\n className={cn(\n 'flex items-center',\n isCompactRow ? 'shrink-0 gap-3' : 'justify-between w-full',\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nAIInputActionBar.displayName = 'AIInput.ActionBar';\n\n// =============================================================================\n// AIInput.FilePreview - File attachments section\n// =============================================================================\n\nexport interface AIInputFilePreviewProps {\n /** Additional class name */\n className?: string;\n}\n\nfunction AIInputFilePreview({ className }: AIInputFilePreviewProps) {\n const ctx = useAIInputContext();\n\n if (!ctx.hasAttachments) return null;\n\n const completedFiles = ctx.uploadingFiles.filter(\n (f) => f.status === 'complete' || f.progress >= 100,\n );\n\n // Compact/inline variants use the mobile file mini-card.\n if (ctx.variant !== 'default') {\n return (\n <div\n data-slot=\"ai-input-file-preview\"\n className={cn('w-full flex flex-col gap-2', className)}\n >\n <div className=\"flex gap-2 w-full overflow-x-auto\">\n {ctx.uploadingFiles.map((file, index) => (\n <FileUploadItem\n key={file.id}\n mobile\n fileName={file.name}\n fileExtension={file.fileExtension ?? file.name.split('.').pop()}\n progress={file.progress}\n status={file.status}\n className=\"shrink-0 delight-stagger\"\n style={\n {\n '--delight-delay': `${index * 60}ms`,\n } as React.CSSProperties\n }\n onRemove={() => ctx.onRemoveFile?.(file.id)}\n onCancel={() => ctx.onCancelUpload?.(file.id)}\n onRetry={() => ctx.onRetryUpload?.(file.id)}\n />\n ))}\n </div>\n <div className=\"flex items-center justify-between w-full\">\n <span className=\"text-xs text-card-foreground\">\n {completedFiles.length} file\n {completedFiles.length !== 1 ? 's' : ''} added\n </span>\n <RemoveAllButton onClick={ctx.onRemoveAllFiles} />\n </div>\n <div className=\"w-full h-px bg-border\" />\n </div>\n );\n }\n\n // Default variant uses the horizontal file mini-card.\n return (\n <div\n data-slot=\"ai-input-file-preview\"\n className={cn('w-full flex flex-col gap-2', className)}\n >\n <div className=\"flex items-start gap-2 w-full overflow-x-auto\">\n {ctx.uploadingFiles.map((file, index) => (\n <FileUploadItem\n key={file.id}\n fileName={file.name}\n fileSize={file.size}\n fileExtension={file.fileExtension ?? file.name.split('.').pop()}\n progress={file.progress}\n status={file.status}\n className=\"flex-1 min-w-0 delight-stagger\"\n style={\n { '--delight-delay': `${index * 60}ms` } as React.CSSProperties\n }\n onRemove={() => ctx.onRemoveFile?.(file.id)}\n onCancel={() => ctx.onCancelUpload?.(file.id)}\n onRetry={() => ctx.onRetryUpload?.(file.id)}\n />\n ))}\n </div>\n <div className=\"flex items-end justify-between w-full\">\n <span className=\"text-xs text-card-foreground\">\n {completedFiles.length} file\n {completedFiles.length !== 1 ? 's' : ''} added\n </span>\n <RemoveAllButton onClick={ctx.onRemoveAllFiles} />\n </div>\n <div className=\"w-full h-px bg-border\" />\n </div>\n );\n}\n\nAIInputFilePreview.displayName = 'AIInput.FilePreview';\n\n// =============================================================================\n// Monolithic AIInput Component (Batteries-Included)\n// =============================================================================\n\nexport interface AIInputProps extends VariantProps<typeof inputVariants> {\n /** Visual variant of the input */\n variant?: 'default' | 'compact' | 'inline';\n /** Placeholder text */\n placeholder?: string;\n /** Current input value */\n value?: string;\n /** Initial input value for uncontrolled usage */\n defaultValue?: string;\n /** Callback when value changes */\n onChange?: (value: string) => void;\n /** Callback when message is submitted */\n onSubmit?: (message: string) => void;\n /** Files being uploaded */\n uploadingFiles?: UploadingFile[];\n /** Callback when file is removed */\n onRemoveFile?: (fileId: string) => void;\n /** Callback when file upload is cancelled */\n onCancelUpload?: (fileId: string) => void;\n /** Callback to retry a failed upload */\n onRetryUpload?: (fileId: string) => void;\n /** Callback to remove all files */\n onRemoveAllFiles?: () => void;\n /** Callback when files are selected (via drag-drop or file picker) */\n onFilesSelected?: (files: FileList) => void;\n /** Accepted file types (e.g. 'image/*,.pdf') */\n accept?: string;\n /** Allow multiple file selection */\n multiple?: boolean;\n /** Text shown in the drop overlay */\n dropText?: string;\n /** Whether the input is disabled */\n disabled?: boolean;\n /** Additional class name */\n className?: string;\n\n // ==========================================================================\n // Slot Props (for customizing buttons)\n // ==========================================================================\n\n /** Actions rendered on the left side of the action bar, or before submit in inline mode */\n leadingActions?: React.ReactNode;\n /** Actions rendered on the right side, before submit button */\n trailingActions?: React.ReactNode;\n /** Custom submit button render function - receives onClick and disabled */\n submitButton?: SubmitButtonRenderFn;\n /** Custom default button render function (default variant only) - receives disabled */\n defaultButton?: DefaultButtonRenderFn;\n /** Leading icon for inline variant (brand icon, spinner, avatar). Required for inline, ignored for other variants. */\n leadingIcon?: React.ReactNode;\n /** Convert large/structured paste into a file attachment. */\n pasteAsFile?: PasteAsFileProp;\n}\n\nfunction AIInputDefault({\n variant = 'default',\n placeholder = 'How can HUMAIN ONE help you today?',\n value,\n defaultValue = '',\n onChange,\n onSubmit,\n uploadingFiles = [],\n onRemoveFile,\n onCancelUpload,\n onRetryUpload,\n onRemoveAllFiles,\n onFilesSelected,\n accept,\n multiple = true,\n dropText = 'Drop files to attach',\n disabled = false,\n className,\n // Slot props\n leadingActions,\n trailingActions,\n submitButton,\n defaultButton,\n leadingIcon,\n pasteAsFile,\n}: AIInputProps) {\n const [internalValue, setInternalValue] = React.useState(defaultValue);\n const [isFocused, setIsFocused] = React.useState(false);\n const textareaRef = React.useRef<HTMLTextAreaElement>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n\n const { isDragging, dropZoneProps } = useDropZone({\n onFilesSelected,\n accept,\n multiple,\n disabled,\n containerRef: rootRef,\n });\n\n const inputValue = value !== undefined ? value : internalValue;\n const hasText = inputValue.trim().length > 0;\n const hasAttachments = uploadingFiles.length > 0;\n const isControlled = value !== undefined;\n\n const isInline = variant === 'inline';\n const isDefault = variant === 'default';\n\n // Determine visual state\n const getState = (): VariantProps<typeof inputVariants>['state'] => {\n if (disabled) return 'disabled';\n if (isDragging) return 'dragover';\n if (hasAttachments) return 'attachments';\n if (hasText) return 'withText';\n if (isFocused) return 'focused';\n return 'default';\n };\n\n const setValue = React.useCallback(\n (next: string) => {\n if (onChange) {\n onChange(next);\n }\n if (!isControlled) {\n setInternalValue(next);\n }\n },\n [onChange, isControlled],\n );\n\n const handleChange = (\n e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => {\n setValue(e.target.value);\n };\n\n const { onPaste } = usePasteAsFile({\n pasteAsFile,\n onFilesSelected,\n accept,\n disabled,\n variant,\n value: inputValue,\n setValue,\n });\n\n const handleSubmit = () => {\n if (hasText && onSubmit) {\n onSubmit(inputValue);\n if (!isControlled) {\n setInternalValue('');\n }\n }\n };\n\n const handleKeyDown = (\n e: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const handleClear = () => {\n if (onChange) {\n onChange('');\n }\n if (!isControlled) {\n setInternalValue('');\n }\n if (variant === 'inline') {\n inputRef.current?.focus();\n } else {\n textareaRef.current?.focus();\n }\n };\n\n // Shared: completed file count for file preview sections\n const completedCount = uploadingFiles.filter(\n (f) => f.status === 'complete' || f.progress >= 100,\n ).length;\n\n // Compact file preview (shared by compact + inline variants, skipped for default)\n const compactFilePreview = !isDefault && hasAttachments && (\n <div\n data-slot=\"ai-input-file-preview\"\n className=\"w-full flex flex-col gap-2\"\n >\n <div className=\"flex gap-2 w-full overflow-x-auto\">\n {uploadingFiles.map((file, index) => (\n <FileUploadItem\n key={file.id}\n mobile\n fileName={file.name}\n fileExtension={file.fileExtension ?? file.name.split('.').pop()}\n progress={file.progress}\n status={file.status}\n className=\"shrink-0 delight-stagger\"\n style={\n { '--delight-delay': `${index * 60}ms` } as React.CSSProperties\n }\n onRemove={() => onRemoveFile?.(file.id)}\n onCancel={() => onCancelUpload?.(file.id)}\n onRetry={() => onRetryUpload?.(file.id)}\n />\n ))}\n </div>\n <div className=\"flex items-center justify-between w-full\">\n <span className=\"text-xs text-card-foreground\">\n {completedCount} file\n {completedCount !== 1 ? 's' : ''} added\n </span>\n <RemoveAllButton onClick={onRemoveAllFiles} />\n </div>\n <div className=\"w-full h-px bg-border\" />\n </div>\n );\n\n // Inline variant\n if (isInline) {\n return (\n <div\n ref={rootRef}\n data-slot=\"ai-input\"\n data-dragging={isDragging}\n {...dropZoneProps}\n {...(onFilesSelected\n ? { 'aria-label': 'Chat input with file drop zone' }\n : {})}\n className={getAIInputShellClassName({\n state: getState(),\n variant: 'inline',\n className,\n })}\n >\n <div\n data-slot=\"ai-input-inner\"\n className={cn(\n inputVariants({ state: getState(), variant: 'inline' }),\n 'relative bg-transparent',\n hasAttachments && 'flex-col items-stretch py-3',\n )}\n >\n {isDragging && (\n <DropOverlay isDefault={isDefault} dropText={dropText} />\n )}\n {compactFilePreview}\n\n <div className=\"flex items-center gap-2 w-full\">\n {leadingIcon ? (\n <AIInputLeadingIcon>{leadingIcon}</AIInputLeadingIcon>\n ) : null}\n\n <input\n ref={inputRef}\n data-slot=\"ai-input-text\"\n type=\"text\"\n value={inputValue}\n onChange={handleChange}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={disabled}\n className=\"flex-1 min-w-0 bg-transparent text-sm leading-5 text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground\"\n />\n\n {leadingActions}\n {trailingActions}\n\n <AIInputSubmitButton\n customButton={submitButton}\n onClick={handleSubmit}\n disabled={disabled || !hasText}\n />\n </div>\n </div>\n </div>\n );\n }\n\n // Compact variant\n if (!isDefault) {\n return (\n <div\n ref={rootRef}\n data-slot=\"ai-input\"\n data-dragging={isDragging}\n {...dropZoneProps}\n {...(onFilesSelected\n ? { 'aria-label': 'Chat input with file drop zone' }\n : {})}\n className={getAIInputShellClassName({\n state: getState(),\n variant: 'compact',\n className,\n })}\n >\n <div\n data-slot=\"ai-input-inner\"\n className={cn(\n inputVariants({ state: getState(), variant: 'compact' }),\n 'relative bg-transparent',\n hasAttachments && 'flex-col items-stretch',\n )}\n >\n {isDragging && (\n <DropOverlay isDefault={isDefault} dropText={dropText} />\n )}\n {compactFilePreview}\n\n <div\n data-slot=\"ai-input-text-area\"\n className={cn(\n 'flex gap-2',\n hasAttachments\n ? 'w-full items-start'\n : 'min-w-0 flex-1 items-center',\n )}\n >\n <textarea\n ref={textareaRef}\n data-slot=\"ai-input-textarea\"\n value={inputValue}\n onChange={handleChange}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={handleKeyDown}\n onPaste={onPaste}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={disabled}\n rows={1}\n className={compactTextareaClasses}\n />\n </div>\n\n <div\n data-slot=\"ai-input-action-bar\"\n className={cn(\n 'flex items-center',\n hasAttachments ? 'justify-between w-full' : 'shrink-0 gap-3',\n )}\n >\n <div\n data-slot=\"ai-input-actions\"\n className=\"flex items-center gap-2\"\n >\n {leadingActions}\n </div>\n <div\n data-slot=\"ai-input-actions\"\n className=\"flex items-center gap-2\"\n >\n {trailingActions}\n {hasText ? (\n <AIInputSubmitButton\n customButton={submitButton}\n onClick={handleSubmit}\n disabled={disabled || !hasText}\n />\n ) : (\n <AIInputDefaultButton\n customButton={defaultButton}\n disabled={disabled}\n />\n )}\n </div>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={rootRef}\n data-slot=\"ai-input\"\n data-dragging={isDragging}\n {...dropZoneProps}\n {...(onFilesSelected\n ? { 'aria-label': 'Chat input with file drop zone' }\n : {})}\n className={getAIInputShellClassName({\n state: getState(),\n variant: 'default',\n className,\n })}\n >\n <div\n data-slot=\"ai-input-inner\"\n className={cn(\n inputVariants({ state: getState(), variant: 'default' }),\n 'relative bg-transparent',\n )}\n >\n {isDragging && (\n <DropOverlay isDefault={isDefault} dropText={dropText} />\n )}\n {/* Attachments Section (above input, matching Figma layout) */}\n {hasAttachments && (\n <div\n data-slot=\"ai-input-file-preview\"\n className=\"w-full flex flex-col gap-2\"\n >\n <div className=\"flex items-start gap-2 w-full overflow-x-auto\">\n {uploadingFiles.map((file, index) => (\n <FileUploadItem\n key={file.id}\n fileName={file.name}\n fileSize={file.size}\n fileExtension={\n file.fileExtension ?? file.name.split('.').pop()\n }\n progress={file.progress}\n status={file.status}\n className=\"flex-1 min-w-0 delight-stagger\"\n style={\n {\n '--delight-delay': `${index * 60}ms`,\n } as React.CSSProperties\n }\n onRemove={() => onRemoveFile?.(file.id)}\n onCancel={() => onCancelUpload?.(file.id)}\n onRetry={() => onRetryUpload?.(file.id)}\n />\n ))}\n </div>\n\n <div className=\"flex items-end justify-between w-full\">\n <span className=\"text-xs text-card-foreground\">\n {completedCount} file\n {completedCount !== 1 ? 's' : ''} added\n </span>\n <RemoveAllButton onClick={onRemoveAllFiles} />\n </div>\n\n <div className=\"w-full h-px bg-border\" />\n </div>\n )}\n\n <div\n data-slot=\"ai-input-text-area\"\n className=\"flex items-start gap-2 w-full\"\n >\n <textarea\n ref={textareaRef}\n data-slot=\"ai-input-textarea\"\n value={inputValue}\n onChange={handleChange}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={handleKeyDown}\n onPaste={onPaste}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={disabled}\n rows={1}\n className={textareaClasses}\n />\n {hasText && !disabled && (\n <button\n type=\"button\"\n onClick={handleClear}\n aria-label=\"Clear input\"\n className=\"p-2 rounded-full hover:bg-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring transition-colors duration-150 ease-out shrink-0\"\n >\n <X className=\"size-5 text-muted-foreground\" />\n </button>\n )}\n </div>\n\n <div\n data-slot=\"ai-input-action-bar\"\n className=\"flex items-center justify-between w-full\"\n >\n <div data-slot=\"ai-input-actions\" className=\"flex items-center gap-2\">\n {leadingActions}\n </div>\n\n <div data-slot=\"ai-input-actions\" className=\"flex items-center gap-2\">\n {trailingActions}\n {hasText ? (\n <AIInputSubmitButton\n customButton={submitButton}\n onClick={handleSubmit}\n disabled={disabled || !hasText}\n />\n ) : (\n <AIInputDefaultButton\n customButton={defaultButton}\n disabled={disabled}\n />\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nAIInputDefault.displayName = 'AIInput';\n\n// =============================================================================\n// Export: Object.assign for dual-API\n// =============================================================================\n\n/**\n * AIInput - Dual-API component for AI chat input.\n *\n * Supports two usage patterns:\n *\n * 1. **Monolithic API (batteries-included)**:\n * ```tsx\n * <AIInput\n * placeholder=\"Ask anything...\"\n * onSubmit={handleSubmit}\n * leadingActions={<AIInput.ActionButton icon={Plus} />}\n * />\n * ```\n *\n * 2. **Composable API (full customization)**:\n * ```tsx\n * <AIInput.Root onSubmit={handleSubmit}>\n * <AIInput.TextArea placeholder=\"Ask anything...\" />\n * <AIInput.ActionBar>\n * <AIInput.Actions position=\"leading\">\n * <AIInput.AttachButton icon={Plus} tooltip=\"Add file\" />\n * </AIInput.Actions>\n * <AIInput.Actions position=\"trailing\">\n * <AIInput.SendButton />\n * </AIInput.Actions>\n * </AIInput.ActionBar>\n * <AIInput.FilePreview />\n * </AIInput.Root>\n * ```\n */\nconst AIInput = Object.assign(AIInputDefault, {\n Root: AIInputRoot,\n TextArea: AIInputTextArea,\n LeadingIcon: AIInputLeadingIcon,\n SendButton: AIInputSendButton,\n AttachButton: AIInputAttachButton,\n Actions: AIInputActions,\n ActionBar: AIInputActionBar,\n FilePreview: AIInputFilePreview,\n // Legacy compound components (also available on main export)\n ActionButton,\n SubmitButton,\n CompactActionButton,\n});\n\nexport {\n // Compound components (also available as AIInput.X)\n ActionButton,\n AIInput,\n AIInputActionBar,\n AIInputActions,\n AIInputAttachButton,\n AIInputFilePreview,\n AIInputLeadingIcon,\n // New composable components\n AIInputRoot,\n AIInputSendButton,\n AIInputTextArea,\n CompactActionButton,\n inputVariants,\n SubmitButton,\n // Context hook for custom subcomponents\n useAIInputContext,\n};\n\n// Note: SubmitButtonRenderProps, SubmitButtonRenderFn, DefaultButtonRenderProps,\n// and DefaultButtonRenderFn are exported at their definition sites above\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index150.js","names":[],"sources":["../src/components/organisms/ai/AIInput/AIInput.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { ArrowDown, ArrowUp, X } from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { FileUploadItem } from '@/components/molecules/files/FileUpload';\nimport {\n matchesAcceptToken,\n toFileList,\n useDropZone,\n} from '@/hooks/use-drop-zone';\nimport { createSafeContext } from '@/lib/create-safe-context';\nimport { cn } from '@/lib/utils';\nimport { analyzePaste, mapKindToFile, type PasteKind } from './paste-detection';\n\n// =============================================================================\n// Shared Styles\n// =============================================================================\n\nconst textareaClasses =\n 'flex-1 h-[40px] resize-none overflow-y-auto bg-transparent text-base text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground';\n\nconst compactTextareaClasses =\n 'flex-1 h-[32px] resize-none overflow-y-auto bg-transparent text-base leading-6 text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst inputVariants = cva(\n 'flex items-center w-full transition-[color,background-color,border-color,box-shadow,opacity]',\n {\n variants: {\n state: {\n default: '',\n focused: '',\n withText: '',\n disabled: 'cursor-not-allowed',\n attachments: '',\n dragover: '',\n },\n variant: {\n default: 'flex-col gap-2 py-4 px-4 rounded-[inherit]',\n compact: 'flex-row gap-2 py-4 px-4 rounded-[inherit]',\n inline: 'flex-row gap-2 px-4 py-4 rounded-[inherit]',\n },\n },\n defaultVariants: {\n state: 'default',\n variant: 'default',\n },\n },\n);\n\nfunction getAIInputShellClassName({\n state,\n variant,\n className,\n}: {\n state: VariantProps<typeof inputVariants>['state'];\n variant: 'default' | 'compact' | 'inline';\n className?: string;\n}) {\n const isDefault = variant === 'default';\n const isDisabled = state === 'disabled';\n const isPrimaryState =\n state === 'focused' ||\n state === 'withText' ||\n state === 'attachments' ||\n state === 'dragover';\n const isStrongState =\n state === 'focused' || state === 'withText' || state === 'dragover';\n\n return cn(\n 'relative w-full overflow-hidden border bg-background shadow-[var(--shadow-ai-input)] transition-[color,background-color,border-color,box-shadow,opacity] duration-150 ease-out',\n isDefault ? 'rounded-3xl max-w-[772px]' : 'rounded-2xl',\n isDisabled\n ? 'border-border bg-muted'\n : isPrimaryState\n ? 'border-primary'\n : 'border-ring/50 hover:border-primary',\n isStrongState ? 'border-2' : 'border-[1.25px]',\n className,\n );\n}\n\n// =============================================================================\n// Drop Overlay (shared across all variants)\n// =============================================================================\n\nfunction DropOverlay({\n isDefault,\n dropText,\n}: {\n isDefault: boolean;\n dropText: string;\n}) {\n return (\n <div\n data-slot=\"ai-input-drop-overlay\"\n role=\"status\"\n aria-live=\"polite\"\n className={cn(\n 'delight-drop-enter absolute inset-1.5 border-2 border-dashed border-primary/50 dark:border-primary/60 pointer-events-none flex flex-col items-center justify-center gap-1.5 z-10',\n isDefault ? 'rounded-[calc(1.5rem-8px)]' : 'rounded-[calc(1rem-8px)]',\n )}\n >\n <ArrowDown className=\"size-4 text-primary/70 delight-drop-icon\" />\n <span className=\"text-sm text-muted-foreground font-medium\">\n {dropText}\n </span>\n </div>\n );\n}\n\nDropOverlay.displayName = 'AIInput.DropOverlay';\n\n// =============================================================================\n// File Attachment Types\n// =============================================================================\n\nexport interface UploadingFile {\n id: string;\n name: string;\n size: string;\n progress: number;\n status: 'uploading' | 'complete' | 'error';\n /** File extension for icon display (e.g., 'pdf', 'docx') */\n fileExtension?: string;\n}\n\n// =============================================================================\n// Paste-as-File public types\n// =============================================================================\n\nexport type { PasteKind } from './paste-detection';\n\nexport interface PasteAsFileConfig {\n /** Char count above which plain text always converts. Default: 500 */\n threshold?: number;\n /** Line count above which plain text always converts. Default: 10 */\n lineThreshold?: number;\n /** Run structured-content heuristics (JSON/XML/CSV/code/log). Default: true */\n detectStructured?: boolean;\n /**\n * Auto-fill textarea after conversion. Receives filename + detected kind.\n * Return string to set as textarea value (appended with leading space if textarea non-empty).\n * Empty/whitespace-only return is treated as no-op.\n * Default: undefined → textarea stays empty.\n */\n prefillTemplate?: (filename: string, kind: PasteKind) => string;\n /** Fired after onFilesSelected and prefill. */\n onConverted?: (filename: string, kind: PasteKind) => void;\n}\n\n/**\n * Accepts boolean for runtime toggling. `false` and `undefined` both disable.\n * `true` enables with defaults. Object enables with overrides.\n */\nexport type PasteAsFileProp = boolean | PasteAsFileConfig;\n\n// =============================================================================\n// usePasteAsFile — internal hook\n// =============================================================================\n\ninterface UsePasteAsFileOpts {\n pasteAsFile: PasteAsFileProp | undefined;\n onFilesSelected: ((files: FileList) => void) | undefined;\n accept: string | undefined;\n disabled: boolean;\n variant: 'default' | 'compact' | 'inline';\n value: string;\n setValue: (next: string) => void;\n}\n\nfunction usePasteAsFile(opts: UsePasteAsFileOpts): {\n onPaste?: React.ClipboardEventHandler<HTMLTextAreaElement>;\n} {\n const counterRef = React.useRef(0);\n const warnedRef = React.useRef(false);\n const optsRef = React.useRef(opts);\n\n // Keep the ref pointing at the latest opts each render. This pattern lets the\n // returned `onPaste` be referentially stable (empty-deps useCallback) while\n // still seeing the freshest pasteAsFile config and callbacks.\n React.useEffect(() => {\n optsRef.current = opts;\n });\n\n const onPaste = React.useCallback<\n React.ClipboardEventHandler<HTMLTextAreaElement>\n >((e) => {\n const { pasteAsFile, onFilesSelected, accept, disabled, value, setValue } =\n optsRef.current;\n\n if (!pasteAsFile || disabled) return;\n\n const text = e.clipboardData.getData('text/plain');\n if (!text) return;\n\n const config: PasteAsFileConfig = pasteAsFile === true ? {} : pasteAsFile;\n\n const detectionOpts = {\n charThreshold: config.threshold,\n lineThreshold: config.lineThreshold,\n detectStructured: config.detectStructured,\n };\n\n const { shouldConvert, kind } = analyzePaste(text, detectionOpts);\n if (!shouldConvert) return;\n\n if (!onFilesSelected) {\n if (process.env.NODE_ENV !== 'production' && !warnedRef.current) {\n console.warn(\n '[AIInput] pasteAsFile is set but onFilesSelected is missing. Paste-to-file is a no-op.',\n );\n warnedRef.current = true;\n }\n return;\n }\n\n const { ext, mime } = mapKindToFile(kind);\n const nProspective = counterRef.current + 1;\n const filename = `Pasted-${nProspective}.${ext}`;\n\n if (\n accept &&\n !accept\n .split(',')\n .some((token) =>\n matchesAcceptToken({ name: filename, type: mime }, token),\n )\n ) {\n return;\n }\n\n let fileList: FileList;\n try {\n const file = new File([text], filename, { type: mime });\n fileList = toFileList([file]);\n } catch {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n '[AIInput] DataTransfer unavailable; falling back to native paste.',\n );\n }\n return;\n }\n\n e.preventDefault();\n counterRef.current = nProspective;\n onFilesSelected(fileList);\n\n if (config.prefillTemplate) {\n const tpl = config.prefillTemplate(filename, kind);\n if (tpl?.trim()) {\n setValue(value ? `${value} ${tpl}` : tpl);\n }\n }\n\n config.onConverted?.(filename, kind);\n }, []);\n\n if (opts.variant === 'inline' || !opts.pasteAsFile) {\n return { onPaste: undefined };\n }\n\n return { onPaste };\n}\n\n// =============================================================================\n// Context\n// =============================================================================\n\ninterface AIInputContextValue {\n /** Current input value */\n value: string;\n /** Whether the input has text */\n hasText: boolean;\n /** Whether the input is focused */\n isFocused: boolean;\n /** Whether the input is disabled */\n disabled: boolean;\n /** Visual variant */\n variant: 'default' | 'compact' | 'inline';\n /** Files being uploaded */\n uploadingFiles: UploadingFile[];\n /** Has attachments */\n hasAttachments: boolean;\n /** Update input value */\n setValue: (value: string) => void;\n /** Set focus state */\n setIsFocused: (focused: boolean) => void;\n /** Handle submit */\n handleSubmit: () => void;\n /** Handle key down */\n handleKeyDown: (\n e: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => void;\n /** Handle clear */\n handleClear: () => void;\n /** Paste handler from usePasteAsFile (only set when paste-as-file is active). */\n onPaste?: React.ClipboardEventHandler<HTMLTextAreaElement>;\n /** Remove file */\n onRemoveFile?: (fileId: string) => void;\n /** Cancel upload */\n onCancelUpload?: (fileId: string) => void;\n /** Retry failed upload */\n onRetryUpload?: (fileId: string) => void;\n /** Remove all files */\n onRemoveAllFiles?: () => void;\n /** Whether files are being dragged over the input */\n isDragging: boolean;\n /** Open the native file picker */\n openFilePicker: () => void;\n /** Callback when files are selected (via drop or picker) */\n onFilesSelected?: (files: FileList) => void;\n /** Textarea ref (for default variant) */\n textareaRef: React.RefObject<HTMLTextAreaElement | null>;\n /** Input ref (for compact variant) */\n inputRef: React.RefObject<HTMLInputElement | null>;\n}\n\nconst [AIInputContext, useAIInputContext] =\n createSafeContext<AIInputContextValue>('AIInput');\n\n// =============================================================================\n// Compound Components - Building Blocks\n// =============================================================================\n\nexport interface ActionButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Icon component to render */\n icon: React.ComponentType<{ className?: string }>;\n /** Tooltip text */\n tooltip?: string;\n}\n\nfunction ActionButton({\n icon: Icon,\n onClick,\n disabled,\n tooltip,\n className,\n ...props\n}: ActionButtonProps) {\n return (\n <button\n type=\"button\"\n data-slot=\"action-button\"\n onClick={onClick}\n disabled={disabled}\n title={tooltip}\n aria-label={tooltip}\n className={cn(\n 'p-2 rounded-full text-secondary-foreground hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n}\n\nActionButton.displayName = 'AIInput.ActionButton';\n\nexport interface SubmitButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {\n /** Icon component to render (defaults to ArrowUp) */\n icon?: React.ComponentType<{ className?: string }>;\n}\n\nfunction SubmitButton({\n icon: Icon = ArrowUp,\n className,\n onClick,\n disabled,\n ...props\n}: SubmitButtonProps) {\n return (\n <Button\n type=\"button\"\n data-slot=\"submit-button\"\n size=\"icon-sm\"\n onClick={onClick}\n disabled={disabled}\n aria-label=\"Send message\"\n className={cn(\n 'rounded-full bg-primary hover:bg-primary/90 text-primary-foreground disabled:bg-accent disabled:text-muted-foreground transition-colors duration-150 ease-out',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-4\" />\n </Button>\n );\n}\n\nSubmitButton.displayName = 'AIInput.SubmitButton';\n\nexport interface CompactActionButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {\n /** Icon component to render */\n icon: React.ComponentType<{ className?: string }>;\n /** Accessible label for the icon-only button (required for a11y) */\n 'aria-label': string;\n}\n\n/**\n * @deprecated Use `ActionButton` instead. CompactActionButton will be removed in a future major version.\n */\nfunction CompactActionButton({\n icon: Icon,\n className,\n onClick,\n disabled,\n ...props\n}: CompactActionButtonProps) {\n return (\n <Button\n type=\"button\"\n data-slot=\"compact-action-button\"\n onClick={onClick}\n disabled={disabled}\n appearance=\"outline\"\n variant=\"secondary\"\n size=\"icon\"\n className={cn(\n 'rounded-full border-border text-foreground hover:bg-muted',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-5\" />\n </Button>\n );\n}\n\nCompactActionButton.displayName = 'AIInput.CompactActionButton';\n\nfunction RemoveAllButton({ onClick }: { onClick?: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label=\"Remove all attached files\"\n className=\"flex items-center gap-1.5 h-5 px-2 py-1 rounded-full bg-accent border border-border text-xs font-medium text-foreground hover:bg-accent/80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring transition-colors\"\n >\n <X className=\"size-4\" />\n Remove all\n </button>\n );\n}\n\nRemoveAllButton.displayName = 'AIInput.RemoveAllButton';\n\n// =============================================================================\n// Render Function Types (for monolithic API)\n// =============================================================================\n\n/** Props passed to custom submit button render function */\nexport interface SubmitButtonRenderProps {\n onClick: () => void;\n disabled: boolean;\n}\n\n/** Render function type for custom submit button */\nexport type SubmitButtonRenderFn = (\n props: SubmitButtonRenderProps,\n) => React.ReactElement;\n\n/** Props passed to custom default button render function */\nexport interface DefaultButtonRenderProps {\n disabled: boolean;\n}\n\n/** Render function type for custom default button */\nexport type DefaultButtonRenderFn = (\n props: DefaultButtonRenderProps,\n) => React.ReactElement;\n\nfunction AIInputSubmitButton({\n customButton,\n onClick,\n disabled,\n}: {\n customButton?: SubmitButtonRenderFn;\n onClick: () => void;\n disabled: boolean;\n}) {\n const buttonProps: SubmitButtonRenderProps = {\n onClick,\n disabled,\n };\n\n if (customButton) {\n return customButton(buttonProps);\n }\n\n return <SubmitButton {...buttonProps} />;\n}\n\nfunction AIInputDefaultButton({\n customButton,\n disabled,\n}: {\n customButton?: DefaultButtonRenderFn;\n disabled: boolean;\n}) {\n const buttonProps: DefaultButtonRenderProps = {\n disabled,\n };\n\n if (customButton) {\n return customButton(buttonProps);\n }\n\n return <SubmitButton icon={ArrowUp} disabled />;\n}\n\n// =============================================================================\n// Composable Subcomponents (for dual-API)\n// =============================================================================\n\nexport interface AIInputRootProps {\n /** Children (composable subcomponents) */\n children: React.ReactNode;\n /** Visual variant of the input */\n variant?: 'default' | 'compact' | 'inline';\n /** Current input value (controlled) */\n value?: string;\n /** Default input value (uncontrolled) */\n defaultValue?: string;\n /** Callback when value changes */\n onChange?: (value: string) => void;\n /** Callback when message is submitted */\n onSubmit?: (message: string) => void;\n /** Files being uploaded */\n uploadingFiles?: UploadingFile[];\n /** Callback when file is removed */\n onRemoveFile?: (fileId: string) => void;\n /** Callback when file upload is cancelled */\n onCancelUpload?: (fileId: string) => void;\n /** Callback to retry a failed upload */\n onRetryUpload?: (fileId: string) => void;\n /** Callback to remove all files */\n onRemoveAllFiles?: () => void;\n /** Whether the input is disabled */\n disabled?: boolean;\n /** Additional class name */\n className?: string;\n /** Callback when files are selected (via drag-drop or file picker) */\n onFilesSelected?: (files: FileList) => void;\n /** Accepted file types (e.g. 'image/*,.pdf') */\n accept?: string;\n /** Allow multiple file selection */\n multiple?: boolean;\n /** Text shown in the drop overlay */\n dropText?: string;\n /** Convert large/structured paste into a file attachment. Requires onFilesSelected. */\n pasteAsFile?: PasteAsFileProp;\n}\n\nfunction AIInputRoot({\n children,\n variant = 'default',\n value: controlledValue,\n defaultValue = '',\n onChange,\n onSubmit,\n uploadingFiles = [],\n onRemoveFile,\n onCancelUpload,\n onRetryUpload,\n onRemoveAllFiles,\n disabled = false,\n className,\n onFilesSelected,\n accept,\n multiple = true,\n dropText = 'Drop files to attach',\n pasteAsFile,\n}: AIInputRootProps) {\n const [internalValue, setInternalValue] = React.useState(defaultValue);\n const [isFocused, setIsFocused] = React.useState(false);\n const textareaRef = React.useRef<HTMLTextAreaElement>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n\n const { isDragging, dropZoneProps, openFilePicker } = useDropZone({\n onFilesSelected,\n accept,\n multiple,\n disabled,\n containerRef: rootRef,\n });\n\n const isControlled = controlledValue !== undefined;\n const value = isControlled ? controlledValue : internalValue;\n const hasText = value.trim().length > 0;\n const hasAttachments = uploadingFiles.length > 0;\n const setValue = React.useCallback(\n (newValue: string) => {\n if (onChange) {\n onChange(newValue);\n }\n if (!isControlled) {\n setInternalValue(newValue);\n }\n },\n [onChange, isControlled],\n );\n\n const { onPaste } = usePasteAsFile({\n pasteAsFile,\n onFilesSelected,\n accept,\n disabled,\n variant,\n value,\n setValue,\n });\n\n const handleSubmit = React.useCallback(() => {\n if (hasText && onSubmit) {\n onSubmit(value);\n if (!isControlled) {\n setInternalValue('');\n }\n }\n }, [hasText, onSubmit, value, isControlled]);\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n },\n [handleSubmit],\n );\n\n const handleClear = React.useCallback(() => {\n setValue('');\n if (variant === 'inline') {\n inputRef.current?.focus();\n } else {\n textareaRef.current?.focus();\n }\n }, [setValue, variant]);\n\n // Determine visual state\n const getState = (): VariantProps<typeof inputVariants>['state'] => {\n if (disabled) return 'disabled';\n if (isDragging) return 'dragover';\n if (hasAttachments) return 'attachments';\n if (hasText) return 'withText';\n if (isFocused) return 'focused';\n return 'default';\n };\n\n const contextValue = React.useMemo<AIInputContextValue>(\n () => ({\n value,\n hasText,\n isFocused,\n disabled,\n variant,\n uploadingFiles,\n hasAttachments,\n setValue,\n setIsFocused,\n handleSubmit,\n handleKeyDown,\n handleClear,\n onPaste,\n onRemoveFile,\n onCancelUpload,\n onRetryUpload,\n onRemoveAllFiles,\n isDragging,\n openFilePicker,\n onFilesSelected,\n textareaRef,\n inputRef,\n }),\n [\n value,\n hasText,\n isFocused,\n disabled,\n variant,\n uploadingFiles,\n hasAttachments,\n setValue,\n handleSubmit,\n handleKeyDown,\n handleClear,\n onPaste,\n onRemoveFile,\n onCancelUpload,\n onRetryUpload,\n onRemoveAllFiles,\n isDragging,\n openFilePicker,\n onFilesSelected,\n ],\n );\n\n const isDefault = variant === 'default';\n const state = getState();\n\n return (\n <AIInputContext.Provider value={contextValue}>\n <div\n ref={rootRef}\n data-slot=\"ai-input\"\n data-dragging={isDragging}\n {...dropZoneProps}\n {...(onFilesSelected\n ? { 'aria-label': 'Chat input with file drop zone' }\n : {})}\n className={getAIInputShellClassName({ state, variant, className })}\n >\n <div\n data-slot=\"ai-input-inner\"\n className={cn(\n inputVariants({ state, variant }),\n 'relative',\n !isDefault && hasAttachments && 'flex-col items-stretch py-3',\n disabled && !isDefault ? 'bg-muted' : 'bg-background',\n 'rounded-[inherit]',\n disabled && isDefault && 'bg-muted',\n )}\n >\n {isDragging && (\n <DropOverlay isDefault={isDefault} dropText={dropText} />\n )}\n {children}\n </div>\n </div>\n </AIInputContext.Provider>\n );\n}\n\nAIInputRoot.displayName = 'AIInput.Root';\n\n// =============================================================================\n// AIInput.TextArea - The text input area\n// =============================================================================\n\nexport interface AIInputTextAreaProps {\n /** Placeholder text */\n placeholder?: string;\n /** Additional class name */\n className?: string;\n /** Show clear button when text is present */\n showClearButton?: boolean;\n}\n\nfunction AIInputTextArea({\n placeholder = 'How can HUMAIN ONE help you today?',\n className,\n showClearButton = true,\n}: AIInputTextAreaProps) {\n const ctx = useAIInputContext();\n const isInline = ctx.variant === 'inline';\n\n const handleChange = (\n e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => {\n ctx.setValue(e.target.value);\n };\n\n if (isInline) {\n return (\n <input\n ref={ctx.inputRef}\n data-slot=\"ai-input-text\"\n type=\"text\"\n value={ctx.value}\n onChange={handleChange}\n onFocus={() => ctx.setIsFocused(true)}\n onBlur={() => ctx.setIsFocused(false)}\n onKeyDown={ctx.handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={ctx.disabled}\n className={cn(\n 'flex-1 min-w-0 bg-transparent text-sm leading-5 text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground',\n className,\n )}\n />\n );\n }\n\n return (\n <div\n data-slot=\"ai-input-text-area\"\n className={cn(\n 'flex gap-2',\n ctx.variant === 'compact' && !ctx.hasAttachments\n ? 'min-w-0 flex-1 items-center'\n : 'w-full items-start',\n )}\n >\n <textarea\n ref={ctx.textareaRef}\n data-slot=\"ai-input-textarea\"\n value={ctx.value}\n onChange={handleChange}\n onPaste={ctx.onPaste}\n onFocus={() => ctx.setIsFocused(true)}\n onBlur={() => ctx.setIsFocused(false)}\n onKeyDown={ctx.handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={ctx.disabled}\n rows={1}\n className={cn(\n ctx.variant === 'compact' ? compactTextareaClasses : textareaClasses,\n className,\n )}\n />\n {showClearButton &&\n ctx.variant !== 'compact' &&\n ctx.hasText &&\n !ctx.disabled && (\n <button\n type=\"button\"\n onClick={ctx.handleClear}\n aria-label=\"Clear input\"\n className=\"p-2 rounded-full hover:bg-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring transition-colors duration-150 ease-out shrink-0\"\n >\n <X className=\"size-5 text-muted-foreground\" />\n </button>\n )}\n </div>\n );\n}\n\nAIInputTextArea.displayName = 'AIInput.TextArea';\n\n// =============================================================================\n// AIInput.LeadingIcon - Leading icon for inline variant\n// =============================================================================\n\nexport interface AIInputLeadingIconProps {\n /** Icon content (brand icon, spinner, avatar) */\n children: React.ReactNode;\n /** Additional class name */\n className?: string;\n}\n\nfunction AIInputLeadingIcon({ children, className }: AIInputLeadingIconProps) {\n return (\n <div\n data-slot=\"ai-input-leading-icon\"\n aria-hidden=\"true\"\n className={cn(\n 'flex items-center justify-center shrink-0 size-9 rounded-xl bg-foreground/4 border border-border',\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nAIInputLeadingIcon.displayName = 'AIInput.LeadingIcon';\n\n// =============================================================================\n// AIInput.SendButton - The send/submit button\n// =============================================================================\n\nexport interface AIInputSendButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {\n /** Icon component to render */\n icon?: React.ComponentType<{ className?: string }>;\n}\n\nfunction AIInputSendButton({\n icon,\n className,\n ...props\n}: AIInputSendButtonProps) {\n const ctx = useAIInputContext();\n const Icon = icon ?? ArrowUp;\n\n return (\n <Button\n type=\"button\"\n data-slot=\"ai-input-send-button\"\n size=\"icon-sm\"\n onClick={ctx.handleSubmit}\n disabled={ctx.disabled || !ctx.hasText}\n aria-label=\"Send message\"\n className={cn(\n 'rounded-full bg-primary hover:bg-primary/90 text-primary-foreground disabled:bg-accent disabled:text-muted-foreground',\n 'transition-all duration-150 ease-out active:scale-90 motion-reduce:active:scale-100',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-4\" />\n </Button>\n );\n}\n\nAIInputSendButton.displayName = 'AIInput.SendButton';\n\n// =============================================================================\n// AIInput.AttachButton - Attach file button\n// =============================================================================\n\nexport interface AIInputAttachButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Icon component to render */\n icon: React.ComponentType<{ className?: string }>;\n /** Tooltip text */\n tooltip?: string;\n}\n\nfunction AIInputAttachButton({\n icon: Icon,\n tooltip,\n className,\n onClick,\n ...props\n}: AIInputAttachButtonProps) {\n const ctx = useAIInputContext();\n\n const handleClick = React.useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n if (onClick) {\n onClick(e);\n } else if (ctx.onFilesSelected) {\n ctx.openFilePicker();\n }\n },\n [onClick, ctx.onFilesSelected, ctx.openFilePicker],\n );\n\n return (\n <button\n type=\"button\"\n data-slot=\"ai-input-attach-button\"\n onClick={handleClick}\n disabled={ctx.disabled}\n title={tooltip}\n aria-label={tooltip ?? 'Attach file'}\n className={cn(\n 'p-2.5 min-h-11 min-w-11 flex items-center justify-center rounded-full text-secondary-foreground hover:bg-accent transition-colors disabled:opacity-50 disabled:cursor-not-allowed',\n className,\n )}\n {...props}\n >\n <Icon className=\"size-4\" />\n </button>\n );\n}\n\nAIInputAttachButton.displayName = 'AIInput.AttachButton';\n\n// =============================================================================\n// AIInput.Actions - Container for action buttons\n// =============================================================================\n\nexport interface AIInputActionsProps {\n /** Children (action buttons) */\n children?: React.ReactNode;\n /** Position of actions */\n position?: 'leading' | 'trailing';\n /** Additional class name */\n className?: string;\n}\n\nfunction AIInputActions({\n children,\n position = 'leading',\n className,\n}: AIInputActionsProps) {\n return (\n <div\n data-slot=\"ai-input-actions\"\n data-position={position}\n className={cn('flex items-center gap-2', className)}\n >\n {children}\n </div>\n );\n}\n\nAIInputActions.displayName = 'AIInput.Actions';\n\n// =============================================================================\n// AIInput.ActionBar - The bottom action bar (for default variant)\n// =============================================================================\n\nexport interface AIInputActionBarProps {\n /** Children (leading actions, trailing actions, send button) */\n children?: React.ReactNode;\n /** Additional class name */\n className?: string;\n}\n\nfunction AIInputActionBar({ children, className }: AIInputActionBarProps) {\n const ctx = useAIInputContext();\n const isCompactRow = ctx.variant === 'compact' && !ctx.hasAttachments;\n\n return (\n <div\n data-slot=\"ai-input-action-bar\"\n className={cn(\n 'flex items-center',\n isCompactRow ? 'shrink-0 gap-3' : 'justify-between w-full',\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\nAIInputActionBar.displayName = 'AIInput.ActionBar';\n\n// =============================================================================\n// AIInput.FilePreview - File attachments section\n// =============================================================================\n\nexport interface AIInputFilePreviewProps {\n /** Additional class name */\n className?: string;\n}\n\nfunction AIInputFilePreview({ className }: AIInputFilePreviewProps) {\n const ctx = useAIInputContext();\n\n if (!ctx.hasAttachments) return null;\n\n const completedFiles = ctx.uploadingFiles.filter(\n (f) => f.status === 'complete' || f.progress >= 100,\n );\n\n // Compact/inline variants use the mobile file mini-card.\n if (ctx.variant !== 'default') {\n return (\n <div\n data-slot=\"ai-input-file-preview\"\n className={cn('w-full flex flex-col gap-2', className)}\n >\n <div className=\"flex gap-2 w-full overflow-x-auto\">\n {ctx.uploadingFiles.map((file, index) => (\n <FileUploadItem\n key={file.id}\n mobile\n fileName={file.name}\n fileExtension={file.fileExtension ?? file.name.split('.').pop()}\n progress={file.progress}\n status={file.status}\n className=\"shrink-0 delight-stagger\"\n style={\n {\n '--delight-delay': `${index * 60}ms`,\n } as React.CSSProperties\n }\n onRemove={() => ctx.onRemoveFile?.(file.id)}\n onCancel={() => ctx.onCancelUpload?.(file.id)}\n onRetry={() => ctx.onRetryUpload?.(file.id)}\n />\n ))}\n </div>\n <div className=\"flex items-center justify-between w-full\">\n <span className=\"text-xs text-card-foreground\">\n {completedFiles.length} file\n {completedFiles.length !== 1 ? 's' : ''} added\n </span>\n <RemoveAllButton onClick={ctx.onRemoveAllFiles} />\n </div>\n <div className=\"w-full h-px bg-border\" />\n </div>\n );\n }\n\n // Default variant uses the horizontal file mini-card.\n return (\n <div\n data-slot=\"ai-input-file-preview\"\n className={cn('w-full flex flex-col gap-2', className)}\n >\n <div className=\"flex items-start gap-2 w-full overflow-x-auto\">\n {ctx.uploadingFiles.map((file, index) => (\n <FileUploadItem\n key={file.id}\n fileName={file.name}\n fileSize={file.size}\n fileExtension={file.fileExtension ?? file.name.split('.').pop()}\n progress={file.progress}\n status={file.status}\n className=\"flex-1 min-w-0 delight-stagger\"\n style={\n { '--delight-delay': `${index * 60}ms` } as React.CSSProperties\n }\n onRemove={() => ctx.onRemoveFile?.(file.id)}\n onCancel={() => ctx.onCancelUpload?.(file.id)}\n onRetry={() => ctx.onRetryUpload?.(file.id)}\n />\n ))}\n </div>\n <div className=\"flex items-end justify-between w-full\">\n <span className=\"text-xs text-card-foreground\">\n {completedFiles.length} file\n {completedFiles.length !== 1 ? 's' : ''} added\n </span>\n <RemoveAllButton onClick={ctx.onRemoveAllFiles} />\n </div>\n <div className=\"w-full h-px bg-border\" />\n </div>\n );\n}\n\nAIInputFilePreview.displayName = 'AIInput.FilePreview';\n\n// =============================================================================\n// Monolithic AIInput Component (Batteries-Included)\n// =============================================================================\n\nexport interface AIInputProps extends VariantProps<typeof inputVariants> {\n /** Visual variant of the input */\n variant?: 'default' | 'compact' | 'inline';\n /** Placeholder text */\n placeholder?: string;\n /** Current input value */\n value?: string;\n /** Initial input value for uncontrolled usage */\n defaultValue?: string;\n /** Callback when value changes */\n onChange?: (value: string) => void;\n /** Callback when message is submitted */\n onSubmit?: (message: string) => void;\n /** Files being uploaded */\n uploadingFiles?: UploadingFile[];\n /** Callback when file is removed */\n onRemoveFile?: (fileId: string) => void;\n /** Callback when file upload is cancelled */\n onCancelUpload?: (fileId: string) => void;\n /** Callback to retry a failed upload */\n onRetryUpload?: (fileId: string) => void;\n /** Callback to remove all files */\n onRemoveAllFiles?: () => void;\n /** Callback when files are selected (via drag-drop or file picker) */\n onFilesSelected?: (files: FileList) => void;\n /** Accepted file types (e.g. 'image/*,.pdf') */\n accept?: string;\n /** Allow multiple file selection */\n multiple?: boolean;\n /** Text shown in the drop overlay */\n dropText?: string;\n /** Whether the input is disabled */\n disabled?: boolean;\n /** Additional class name */\n className?: string;\n\n // ==========================================================================\n // Slot Props (for customizing buttons)\n // ==========================================================================\n\n /** Actions rendered on the left side of the action bar, or before submit in inline mode */\n leadingActions?: React.ReactNode;\n /** Actions rendered on the right side, before submit button */\n trailingActions?: React.ReactNode;\n /** Custom submit button render function - receives onClick and disabled */\n submitButton?: SubmitButtonRenderFn;\n /** Custom default button render function (default variant only) - receives disabled */\n defaultButton?: DefaultButtonRenderFn;\n /** Leading icon for inline variant (brand icon, spinner, avatar). Required for inline, ignored for other variants. */\n leadingIcon?: React.ReactNode;\n /** Convert large/structured paste into a file attachment. */\n pasteAsFile?: PasteAsFileProp;\n}\n\nfunction AIInputDefault({\n variant = 'default',\n placeholder = 'How can HUMAIN ONE help you today?',\n value,\n defaultValue = '',\n onChange,\n onSubmit,\n uploadingFiles = [],\n onRemoveFile,\n onCancelUpload,\n onRetryUpload,\n onRemoveAllFiles,\n onFilesSelected,\n accept,\n multiple = true,\n dropText = 'Drop files to attach',\n disabled = false,\n className,\n // Slot props\n leadingActions,\n trailingActions,\n submitButton,\n defaultButton,\n leadingIcon,\n pasteAsFile,\n}: AIInputProps) {\n const [internalValue, setInternalValue] = React.useState(defaultValue);\n const [isFocused, setIsFocused] = React.useState(false);\n const textareaRef = React.useRef<HTMLTextAreaElement>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n\n const { isDragging, dropZoneProps } = useDropZone({\n onFilesSelected,\n accept,\n multiple,\n disabled,\n containerRef: rootRef,\n });\n\n const inputValue = value !== undefined ? value : internalValue;\n const hasText = inputValue.trim().length > 0;\n const hasAttachments = uploadingFiles.length > 0;\n const isControlled = value !== undefined;\n\n const isInline = variant === 'inline';\n const isDefault = variant === 'default';\n\n // Determine visual state\n const getState = (): VariantProps<typeof inputVariants>['state'] => {\n if (disabled) return 'disabled';\n if (isDragging) return 'dragover';\n if (hasAttachments) return 'attachments';\n if (hasText) return 'withText';\n if (isFocused) return 'focused';\n return 'default';\n };\n\n const setValue = React.useCallback(\n (next: string) => {\n if (onChange) {\n onChange(next);\n }\n if (!isControlled) {\n setInternalValue(next);\n }\n },\n [onChange, isControlled],\n );\n\n const handleChange = (\n e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => {\n setValue(e.target.value);\n };\n\n const { onPaste } = usePasteAsFile({\n pasteAsFile,\n onFilesSelected,\n accept,\n disabled,\n variant,\n value: inputValue,\n setValue,\n });\n\n const handleSubmit = () => {\n if (hasText && onSubmit) {\n onSubmit(inputValue);\n if (!isControlled) {\n setInternalValue('');\n }\n }\n };\n\n const handleKeyDown = (\n e: React.KeyboardEvent<HTMLTextAreaElement | HTMLInputElement>,\n ) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n };\n\n const handleClear = () => {\n if (onChange) {\n onChange('');\n }\n if (!isControlled) {\n setInternalValue('');\n }\n if (variant === 'inline') {\n inputRef.current?.focus();\n } else {\n textareaRef.current?.focus();\n }\n };\n\n // Shared: completed file count for file preview sections\n const completedCount = uploadingFiles.filter(\n (f) => f.status === 'complete' || f.progress >= 100,\n ).length;\n\n // Compact file preview (shared by compact + inline variants, skipped for default)\n const compactFilePreview = !isDefault && hasAttachments && (\n <div\n data-slot=\"ai-input-file-preview\"\n className=\"w-full flex flex-col gap-2\"\n >\n <div className=\"flex gap-2 w-full overflow-x-auto\">\n {uploadingFiles.map((file, index) => (\n <FileUploadItem\n key={file.id}\n mobile\n fileName={file.name}\n fileExtension={file.fileExtension ?? file.name.split('.').pop()}\n progress={file.progress}\n status={file.status}\n className=\"shrink-0 delight-stagger\"\n style={\n { '--delight-delay': `${index * 60}ms` } as React.CSSProperties\n }\n onRemove={() => onRemoveFile?.(file.id)}\n onCancel={() => onCancelUpload?.(file.id)}\n onRetry={() => onRetryUpload?.(file.id)}\n />\n ))}\n </div>\n <div className=\"flex items-center justify-between w-full\">\n <span className=\"text-xs text-card-foreground\">\n {completedCount} file\n {completedCount !== 1 ? 's' : ''} added\n </span>\n <RemoveAllButton onClick={onRemoveAllFiles} />\n </div>\n <div className=\"w-full h-px bg-border\" />\n </div>\n );\n\n // Inline variant\n if (isInline) {\n return (\n <div\n ref={rootRef}\n data-slot=\"ai-input\"\n data-dragging={isDragging}\n {...dropZoneProps}\n {...(onFilesSelected\n ? { 'aria-label': 'Chat input with file drop zone' }\n : {})}\n className={getAIInputShellClassName({\n state: getState(),\n variant: 'inline',\n className,\n })}\n >\n <div\n data-slot=\"ai-input-inner\"\n className={cn(\n inputVariants({ state: getState(), variant: 'inline' }),\n 'relative bg-transparent',\n hasAttachments && 'flex-col items-stretch py-3',\n )}\n >\n {isDragging && (\n <DropOverlay isDefault={isDefault} dropText={dropText} />\n )}\n {compactFilePreview}\n\n <div className=\"flex items-center gap-2 w-full\">\n {leadingIcon ? (\n <AIInputLeadingIcon>{leadingIcon}</AIInputLeadingIcon>\n ) : null}\n\n <input\n ref={inputRef}\n data-slot=\"ai-input-text\"\n type=\"text\"\n value={inputValue}\n onChange={handleChange}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={disabled}\n className=\"flex-1 min-w-0 bg-transparent text-sm leading-5 text-foreground placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:text-muted-foreground\"\n />\n\n {leadingActions}\n {trailingActions}\n\n <AIInputSubmitButton\n customButton={submitButton}\n onClick={handleSubmit}\n disabled={disabled || !hasText}\n />\n </div>\n </div>\n </div>\n );\n }\n\n // Compact variant\n if (!isDefault) {\n return (\n <div\n ref={rootRef}\n data-slot=\"ai-input\"\n data-dragging={isDragging}\n {...dropZoneProps}\n {...(onFilesSelected\n ? { 'aria-label': 'Chat input with file drop zone' }\n : {})}\n className={getAIInputShellClassName({\n state: getState(),\n variant: 'compact',\n className,\n })}\n >\n <div\n data-slot=\"ai-input-inner\"\n className={cn(\n inputVariants({ state: getState(), variant: 'compact' }),\n 'relative bg-transparent',\n hasAttachments && 'flex-col items-stretch',\n )}\n >\n {isDragging && (\n <DropOverlay isDefault={isDefault} dropText={dropText} />\n )}\n {compactFilePreview}\n\n <div\n data-slot=\"ai-input-text-area\"\n className={cn(\n 'flex gap-2',\n hasAttachments\n ? 'w-full items-start'\n : 'min-w-0 flex-1 items-center',\n )}\n >\n <textarea\n ref={textareaRef}\n data-slot=\"ai-input-textarea\"\n value={inputValue}\n onChange={handleChange}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={handleKeyDown}\n onPaste={onPaste}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={disabled}\n rows={1}\n className={compactTextareaClasses}\n />\n </div>\n\n <div\n data-slot=\"ai-input-action-bar\"\n className={cn(\n 'flex items-center',\n hasAttachments ? 'justify-between w-full' : 'shrink-0 gap-3',\n )}\n >\n <div\n data-slot=\"ai-input-actions\"\n className=\"flex items-center gap-2\"\n >\n {leadingActions}\n </div>\n <div\n data-slot=\"ai-input-actions\"\n className=\"flex items-center gap-2\"\n >\n {trailingActions}\n {hasText ? (\n <AIInputSubmitButton\n customButton={submitButton}\n onClick={handleSubmit}\n disabled={disabled || !hasText}\n />\n ) : (\n <AIInputDefaultButton\n customButton={defaultButton}\n disabled={disabled}\n />\n )}\n </div>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={rootRef}\n data-slot=\"ai-input\"\n data-dragging={isDragging}\n {...dropZoneProps}\n {...(onFilesSelected\n ? { 'aria-label': 'Chat input with file drop zone' }\n : {})}\n className={getAIInputShellClassName({\n state: getState(),\n variant: 'default',\n className,\n })}\n >\n <div\n data-slot=\"ai-input-inner\"\n className={cn(\n inputVariants({ state: getState(), variant: 'default' }),\n 'relative bg-transparent',\n )}\n >\n {isDragging && (\n <DropOverlay isDefault={isDefault} dropText={dropText} />\n )}\n {/* Attachments Section (above input, matching Figma layout) */}\n {hasAttachments && (\n <div\n data-slot=\"ai-input-file-preview\"\n className=\"w-full flex flex-col gap-2\"\n >\n <div className=\"flex items-start gap-2 w-full overflow-x-auto\">\n {uploadingFiles.map((file, index) => (\n <FileUploadItem\n key={file.id}\n fileName={file.name}\n fileSize={file.size}\n fileExtension={\n file.fileExtension ?? file.name.split('.').pop()\n }\n progress={file.progress}\n status={file.status}\n className=\"flex-1 min-w-0 delight-stagger\"\n style={\n {\n '--delight-delay': `${index * 60}ms`,\n } as React.CSSProperties\n }\n onRemove={() => onRemoveFile?.(file.id)}\n onCancel={() => onCancelUpload?.(file.id)}\n onRetry={() => onRetryUpload?.(file.id)}\n />\n ))}\n </div>\n\n <div className=\"flex items-end justify-between w-full\">\n <span className=\"text-xs text-card-foreground\">\n {completedCount} file\n {completedCount !== 1 ? 's' : ''} added\n </span>\n <RemoveAllButton onClick={onRemoveAllFiles} />\n </div>\n\n <div className=\"w-full h-px bg-border\" />\n </div>\n )}\n\n <div\n data-slot=\"ai-input-text-area\"\n className=\"flex items-start gap-2 w-full\"\n >\n <textarea\n ref={textareaRef}\n data-slot=\"ai-input-textarea\"\n value={inputValue}\n onChange={handleChange}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n onKeyDown={handleKeyDown}\n onPaste={onPaste}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={disabled}\n rows={1}\n className={textareaClasses}\n />\n {hasText && !disabled && (\n <button\n type=\"button\"\n onClick={handleClear}\n aria-label=\"Clear input\"\n className=\"p-2 rounded-full hover:bg-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring transition-colors duration-150 ease-out shrink-0\"\n >\n <X className=\"size-5 text-muted-foreground\" />\n </button>\n )}\n </div>\n\n <div\n data-slot=\"ai-input-action-bar\"\n className=\"flex items-center justify-between w-full\"\n >\n <div data-slot=\"ai-input-actions\" className=\"flex items-center gap-2\">\n {leadingActions}\n </div>\n\n <div data-slot=\"ai-input-actions\" className=\"flex items-center gap-2\">\n {trailingActions}\n {hasText ? (\n <AIInputSubmitButton\n customButton={submitButton}\n onClick={handleSubmit}\n disabled={disabled || !hasText}\n />\n ) : (\n <AIInputDefaultButton\n customButton={defaultButton}\n disabled={disabled}\n />\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nAIInputDefault.displayName = 'AIInput';\n\n// =============================================================================\n// Export: Object.assign for dual-API\n// =============================================================================\n\n/**\n * AIInput - Dual-API component for AI chat input.\n *\n * Supports two usage patterns:\n *\n * 1. **Monolithic API (batteries-included)**:\n * ```tsx\n * <AIInput\n * placeholder=\"Ask anything...\"\n * onSubmit={handleSubmit}\n * leadingActions={<AIInput.ActionButton icon={Plus} />}\n * />\n * ```\n *\n * 2. **Composable API (full customization)**:\n * ```tsx\n * <AIInput.Root onSubmit={handleSubmit}>\n * <AIInput.TextArea placeholder=\"Ask anything...\" />\n * <AIInput.ActionBar>\n * <AIInput.Actions position=\"leading\">\n * <AIInput.AttachButton icon={Plus} tooltip=\"Add file\" />\n * </AIInput.Actions>\n * <AIInput.Actions position=\"trailing\">\n * <AIInput.SendButton />\n * </AIInput.Actions>\n * </AIInput.ActionBar>\n * <AIInput.FilePreview />\n * </AIInput.Root>\n * ```\n */\nconst AIInput = Object.assign(AIInputDefault, {\n Root: AIInputRoot,\n TextArea: AIInputTextArea,\n LeadingIcon: AIInputLeadingIcon,\n SendButton: AIInputSendButton,\n AttachButton: AIInputAttachButton,\n Actions: AIInputActions,\n ActionBar: AIInputActionBar,\n FilePreview: AIInputFilePreview,\n // Legacy compound components (also available on main export)\n ActionButton,\n SubmitButton,\n CompactActionButton,\n});\n\nexport {\n // Compound components (also available as AIInput.X)\n ActionButton,\n AIInput,\n AIInputActionBar,\n AIInputActions,\n AIInputAttachButton,\n AIInputFilePreview,\n AIInputLeadingIcon,\n // New composable components\n AIInputRoot,\n AIInputSendButton,\n AIInputTextArea,\n CompactActionButton,\n inputVariants,\n SubmitButton,\n // Context hook for custom subcomponents\n useAIInputContext,\n};\n\n// Note: SubmitButtonRenderProps, SubmitButtonRenderFn, DefaultButtonRenderProps,\n// and DefaultButtonRenderFn are exported at their definition sites above\n"],"mappings":"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"}
|
package/dist/wc/AIInput.js
CHANGED
|
@@ -128,10 +128,10 @@ function me(s) {
|
|
|
128
128
|
if (!i || N) return;
|
|
129
129
|
const f = r.clipboardData.getData("text/plain");
|
|
130
130
|
if (!f) return;
|
|
131
|
-
const
|
|
132
|
-
charThreshold:
|
|
133
|
-
lineThreshold:
|
|
134
|
-
detectStructured:
|
|
131
|
+
const v = i === !0 ? {} : i, I = {
|
|
132
|
+
charThreshold: v.threshold,
|
|
133
|
+
lineThreshold: v.lineThreshold,
|
|
134
|
+
detectStructured: v.detectStructured
|
|
135
135
|
}, { shouldConvert: R, kind: d } = He(f, I);
|
|
136
136
|
if (!R || !c) return;
|
|
137
137
|
const { ext: B, mime: T } = Le(d), k = t.current + 1, j = `Pasted-${k}.${B}`;
|
|
@@ -146,11 +146,11 @@ function me(s) {
|
|
|
146
146
|
} catch {
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
|
-
if (r.preventDefault(), t.current = k, c(A),
|
|
150
|
-
const h =
|
|
149
|
+
if (r.preventDefault(), t.current = k, c(A), v.prefillTemplate) {
|
|
150
|
+
const h = v.prefillTemplate(j, d);
|
|
151
151
|
h?.trim() && S(m ? `${m} ${h}` : h);
|
|
152
152
|
}
|
|
153
|
-
|
|
153
|
+
v.onConverted?.(j, d);
|
|
154
154
|
}, []);
|
|
155
155
|
return s.variant === "inline" || !s.pasteAsFile ? { onPaste: void 0 } : { onPaste: a };
|
|
156
156
|
}
|
|
@@ -219,10 +219,10 @@ function ue({ customButton: s, disabled: t }) {
|
|
|
219
219
|
const n = { disabled: t };
|
|
220
220
|
return s ? s(n) : /* @__PURE__ */ (0, e.jsx)(ee, {
|
|
221
221
|
icon: ne,
|
|
222
|
-
|
|
222
|
+
disabled: !0
|
|
223
223
|
});
|
|
224
224
|
}
|
|
225
|
-
function he({ children: s, variant: t = "default", value: n, defaultValue: a = "", onChange: r, onSubmit: i, uploadingFiles: c = [], onRemoveFile: x, onCancelUpload: N, onRetryUpload: m, onRemoveAllFiles: S, disabled: f = !1, className:
|
|
225
|
+
function he({ children: s, variant: t = "default", value: n, defaultValue: a = "", onChange: r, onSubmit: i, uploadingFiles: c = [], onRemoveFile: x, onCancelUpload: N, onRetryUpload: m, onRemoveAllFiles: S, disabled: f = !1, className: v, onFilesSelected: I, accept: R, multiple: d = !0, dropText: B = "Drop files to attach", pasteAsFile: T }) {
|
|
226
226
|
const [k, j] = l.useState(a), [A, h] = l.useState(!1), X = l.useRef(null), W = l.useRef(null), L = l.useRef(null), { isDragging: F, dropZoneProps: D, openFilePicker: H } = ce({
|
|
227
227
|
onFilesSelected: I,
|
|
228
228
|
accept: R,
|
|
@@ -239,7 +239,7 @@ function he({ children: s, variant: t = "default", value: n, defaultValue: a = "
|
|
|
239
239
|
variant: t,
|
|
240
240
|
value: y,
|
|
241
241
|
setValue: g
|
|
242
|
-
}),
|
|
242
|
+
}), b = l.useCallback(() => {
|
|
243
243
|
p && i && (i(y), E || j(""));
|
|
244
244
|
}, [
|
|
245
245
|
p,
|
|
@@ -247,8 +247,8 @@ function he({ children: s, variant: t = "default", value: n, defaultValue: a = "
|
|
|
247
247
|
y,
|
|
248
248
|
E
|
|
249
249
|
]), _ = l.useCallback((C) => {
|
|
250
|
-
C.key === "Enter" && !C.shiftKey && (C.preventDefault(),
|
|
251
|
-
}, [
|
|
250
|
+
C.key === "Enter" && !C.shiftKey && (C.preventDefault(), b());
|
|
251
|
+
}, [b]), Z = l.useCallback(() => {
|
|
252
252
|
g(""), t === "inline" ? W.current?.focus() : X.current?.focus();
|
|
253
253
|
}, [g, t]), O = () => f ? "disabled" : F ? "dragover" : z ? "attachments" : p ? "withText" : A ? "focused" : "default", P = l.useMemo(() => ({
|
|
254
254
|
value: y,
|
|
@@ -260,7 +260,7 @@ function he({ children: s, variant: t = "default", value: n, defaultValue: a = "
|
|
|
260
260
|
hasAttachments: z,
|
|
261
261
|
setValue: g,
|
|
262
262
|
setIsFocused: h,
|
|
263
|
-
handleSubmit:
|
|
263
|
+
handleSubmit: b,
|
|
264
264
|
handleKeyDown: _,
|
|
265
265
|
handleClear: Z,
|
|
266
266
|
onPaste: w,
|
|
@@ -282,7 +282,7 @@ function he({ children: s, variant: t = "default", value: n, defaultValue: a = "
|
|
|
282
282
|
c,
|
|
283
283
|
z,
|
|
284
284
|
g,
|
|
285
|
-
|
|
285
|
+
b,
|
|
286
286
|
_,
|
|
287
287
|
Z,
|
|
288
288
|
w,
|
|
@@ -305,7 +305,7 @@ function he({ children: s, variant: t = "default", value: n, defaultValue: a = "
|
|
|
305
305
|
className: Q({
|
|
306
306
|
state: V,
|
|
307
307
|
variant: t,
|
|
308
|
-
className:
|
|
308
|
+
className: v
|
|
309
309
|
}),
|
|
310
310
|
children: /* @__PURE__ */ (0, e.jsxs)("div", {
|
|
311
311
|
"data-slot": "ai-input-inner",
|
|
@@ -375,7 +375,7 @@ function ie({ children: s, className: t }) {
|
|
|
375
375
|
});
|
|
376
376
|
}
|
|
377
377
|
ie.displayName = "AIInput.LeadingIcon";
|
|
378
|
-
function
|
|
378
|
+
function be({ icon: s, className: t, ...n }) {
|
|
379
379
|
const a = U(), r = s ?? ne;
|
|
380
380
|
return /* @__PURE__ */ (0, e.jsx)(oe, {
|
|
381
381
|
type: "button",
|
|
@@ -389,8 +389,8 @@ function ve({ icon: s, className: t, ...n }) {
|
|
|
389
389
|
children: /* @__PURE__ */ (0, e.jsx)(r, { className: "size-4" })
|
|
390
390
|
});
|
|
391
391
|
}
|
|
392
|
-
|
|
393
|
-
function
|
|
392
|
+
be.displayName = "AIInput.SendButton";
|
|
393
|
+
function ve({ icon: s, tooltip: t, className: n, onClick: a, ...r }) {
|
|
394
394
|
const i = U(), c = l.useCallback((x) => {
|
|
395
395
|
a ? a(x) : i.onFilesSelected && i.openFilePicker();
|
|
396
396
|
}, [
|
|
@@ -410,7 +410,7 @@ function be({ icon: s, tooltip: t, className: n, onClick: a, ...r }) {
|
|
|
410
410
|
children: /* @__PURE__ */ (0, e.jsx)(s, { className: "size-4" })
|
|
411
411
|
});
|
|
412
412
|
}
|
|
413
|
-
|
|
413
|
+
ve.displayName = "AIInput.AttachButton";
|
|
414
414
|
function je({ children: s, position: t = "leading", className: n }) {
|
|
415
415
|
return /* @__PURE__ */ (0, e.jsx)("div", {
|
|
416
416
|
"data-slot": "ai-input-actions",
|
|
@@ -502,21 +502,21 @@ function we({ className: s }) {
|
|
|
502
502
|
});
|
|
503
503
|
}
|
|
504
504
|
we.displayName = "AIInput.FilePreview";
|
|
505
|
-
function Ne({ variant: s = "default", placeholder: t = "How can HUMAIN ONE help you today?", value: n, defaultValue: a = "", onChange: r, onSubmit: i, uploadingFiles: c = [], onRemoveFile: x, onCancelUpload: N, onRetryUpload: m, onRemoveAllFiles: S, onFilesSelected: f, accept:
|
|
505
|
+
function Ne({ variant: s = "default", placeholder: t = "How can HUMAIN ONE help you today?", value: n, defaultValue: a = "", onChange: r, onSubmit: i, uploadingFiles: c = [], onRemoveFile: x, onCancelUpload: N, onRetryUpload: m, onRemoveAllFiles: S, onFilesSelected: f, accept: v, multiple: I = !0, dropText: R = "Drop files to attach", disabled: d = !1, className: B, leadingActions: T, trailingActions: k, submitButton: j, defaultButton: A, leadingIcon: h, pasteAsFile: X }) {
|
|
506
506
|
const [W, L] = l.useState(a), [F, D] = l.useState(!1), H = l.useRef(null), E = l.useRef(null), y = l.useRef(null), { isDragging: p, dropZoneProps: z } = ce({
|
|
507
507
|
onFilesSelected: f,
|
|
508
|
-
accept:
|
|
508
|
+
accept: v,
|
|
509
509
|
multiple: I,
|
|
510
510
|
disabled: d,
|
|
511
511
|
containerRef: y
|
|
512
|
-
}), g = n !== void 0 ? n : W, w = g.trim().length > 0,
|
|
512
|
+
}), g = n !== void 0 ? n : W, w = g.trim().length > 0, b = c.length > 0, _ = n !== void 0, Z = s === "inline", O = s === "default", P = () => d ? "disabled" : p ? "dragover" : b ? "attachments" : w ? "withText" : F ? "focused" : "default", K = l.useCallback((o) => {
|
|
513
513
|
r && r(o), _ || L(o);
|
|
514
514
|
}, [r, _]), V = (o) => {
|
|
515
515
|
K(o.target.value);
|
|
516
516
|
}, { onPaste: C } = me({
|
|
517
517
|
pasteAsFile: X,
|
|
518
518
|
onFilesSelected: f,
|
|
519
|
-
accept:
|
|
519
|
+
accept: v,
|
|
520
520
|
disabled: d,
|
|
521
521
|
variant: s,
|
|
522
522
|
value: g,
|
|
@@ -527,7 +527,7 @@ function Ne({ variant: s = "default", placeholder: t = "How can HUMAIN ONE help
|
|
|
527
527
|
o.key === "Enter" && !o.shiftKey && (o.preventDefault(), q());
|
|
528
528
|
}, Ie = () => {
|
|
529
529
|
r && r(""), _ || L(""), s === "inline" ? E.current?.focus() : H.current?.focus();
|
|
530
|
-
}, G = c.filter((o) => o.status === "complete" || o.progress >= 100).length, le = !O &&
|
|
530
|
+
}, G = c.filter((o) => o.status === "complete" || o.progress >= 100).length, le = !O && b && /* @__PURE__ */ (0, e.jsxs)("div", {
|
|
531
531
|
"data-slot": "ai-input-file-preview",
|
|
532
532
|
className: "w-full flex flex-col gap-2",
|
|
533
533
|
children: [
|
|
@@ -577,7 +577,7 @@ function Ne({ variant: s = "default", placeholder: t = "How can HUMAIN ONE help
|
|
|
577
577
|
className: u(J({
|
|
578
578
|
state: P(),
|
|
579
579
|
variant: "inline"
|
|
580
|
-
}), "relative bg-transparent",
|
|
580
|
+
}), "relative bg-transparent", b && "flex-col items-stretch py-3"),
|
|
581
581
|
children: [
|
|
582
582
|
p && /* @__PURE__ */ (0, e.jsx)($, {
|
|
583
583
|
isDefault: O,
|
|
@@ -635,7 +635,7 @@ function Ne({ variant: s = "default", placeholder: t = "How can HUMAIN ONE help
|
|
|
635
635
|
isDefault: O,
|
|
636
636
|
dropText: R
|
|
637
637
|
}),
|
|
638
|
-
|
|
638
|
+
b && /* @__PURE__ */ (0, e.jsxs)("div", {
|
|
639
639
|
"data-slot": "ai-input-file-preview",
|
|
640
640
|
className: "w-full flex flex-col gap-2",
|
|
641
641
|
children: [
|
|
@@ -732,7 +732,7 @@ function Ne({ variant: s = "default", placeholder: t = "How can HUMAIN ONE help
|
|
|
732
732
|
className: u(J({
|
|
733
733
|
state: P(),
|
|
734
734
|
variant: "compact"
|
|
735
|
-
}), "relative bg-transparent",
|
|
735
|
+
}), "relative bg-transparent", b && "flex-col items-stretch"),
|
|
736
736
|
children: [
|
|
737
737
|
p && /* @__PURE__ */ (0, e.jsx)($, {
|
|
738
738
|
isDefault: O,
|
|
@@ -741,7 +741,7 @@ function Ne({ variant: s = "default", placeholder: t = "How can HUMAIN ONE help
|
|
|
741
741
|
le,
|
|
742
742
|
/* @__PURE__ */ (0, e.jsx)("div", {
|
|
743
743
|
"data-slot": "ai-input-text-area",
|
|
744
|
-
className: u("flex gap-2",
|
|
744
|
+
className: u("flex gap-2", b ? "w-full items-start" : "min-w-0 flex-1 items-center"),
|
|
745
745
|
children: /* @__PURE__ */ (0, e.jsx)("textarea", {
|
|
746
746
|
ref: H,
|
|
747
747
|
"data-slot": "ai-input-textarea",
|
|
@@ -760,7 +760,7 @@ function Ne({ variant: s = "default", placeholder: t = "How can HUMAIN ONE help
|
|
|
760
760
|
}),
|
|
761
761
|
/* @__PURE__ */ (0, e.jsxs)("div", {
|
|
762
762
|
"data-slot": "ai-input-action-bar",
|
|
763
|
-
className: u("flex items-center",
|
|
763
|
+
className: u("flex items-center", b ? "justify-between w-full" : "shrink-0 gap-3"),
|
|
764
764
|
children: [/* @__PURE__ */ (0, e.jsx)("div", {
|
|
765
765
|
"data-slot": "ai-input-actions",
|
|
766
766
|
className: "flex items-center gap-2",
|
|
@@ -787,8 +787,8 @@ var nt = Object.assign(Ne, {
|
|
|
787
787
|
Root: he,
|
|
788
788
|
TextArea: ge,
|
|
789
789
|
LeadingIcon: ie,
|
|
790
|
-
SendButton:
|
|
791
|
-
AttachButton:
|
|
790
|
+
SendButton: be,
|
|
791
|
+
AttachButton: ve,
|
|
792
792
|
Actions: je,
|
|
793
793
|
ActionBar: ye,
|
|
794
794
|
FilePreview: we,
|