UNPKG

@assistant-ui/react

Version:

Open-source TypeScript/React library for building production-grade AI chat experiences

83 lines (68 loc) • 2.32 kB
"use client"; import { type ActionButtonElement, type ActionButtonProps, createActionButton, } from "../../utils/createActionButton"; import { useCallback, useInsertionEffect, useRef } from "react"; import { useAui } from "@assistant-ui/store"; import { useComposerAddAttachment as useComposerAddAttachmentBehavior } from "@assistant-ui/core/react"; const useComposerAddAttachment = ({ multiple = true, }: { /** allow selecting multiple files */ multiple?: boolean | undefined; } = {}) => { const { disabled, addAttachment } = useComposerAddAttachmentBehavior(); const aui = useAui(); const scopeGenerationRef = useRef(0); useInsertionEffect( () => () => { scopeGenerationRef.current += 1; }, [aui.composer, aui.optional.threadListItem], ); const callback = useCallback(() => { const scopeGeneration = scopeGenerationRef.current; const input = document.createElement("input"); input.type = "file"; input.multiple = multiple; input.hidden = true; const attachmentAccept = aui.composer.getState().attachmentAccept; if (attachmentAccept !== "*") { input.accept = attachmentAccept; } document.body.appendChild(input); input.onchange = async (e) => { const fileList = (e.target as HTMLInputElement).files; if (!fileList) return; const attachmentPromises = Array.from(fileList, async (file) => { try { if (scopeGenerationRef.current !== scopeGeneration) return; await addAttachment(file); } catch { // The composer runtime emits composer.attachmentAddError before rejecting. } }); document.body.removeChild(input); await Promise.all(attachmentPromises); }; input.oncancel = () => { if (!input.files || input.files.length === 0) { document.body.removeChild(input); } }; input.click(); }, [aui, multiple, addAttachment]); if (disabled) return null; return callback; }; export namespace ComposerPrimitiveAddAttachment { export type Element = ActionButtonElement; export type Props = ActionButtonProps<typeof useComposerAddAttachment>; } export const ComposerPrimitiveAddAttachment = createActionButton( "ComposerPrimitive.AddAttachment", useComposerAddAttachment, ["multiple"], );