@assistant-ui/react
Version:
Open-source TypeScript/React library for building production-grade AI chat experiences
79 lines (78 loc) • 3.04 kB
JavaScript
"use client";
import { renderSlot } from "../../utils/Primitive.js";
import { forwardRef, isValidElement, useCallback, useEffect, useState } from "@assistant-ui/tap/react-shim";
import { useAui, useAuiState } from "@assistant-ui/store";
import { jsx } from "react/jsx-runtime";
import { composeEventHandlers } from "radix-ui/internal";
import { Slot } from "radix-ui";
// src/primitives/composer/ComposerAttachmentDropzone.tsx
const ComposerPrimitiveAttachmentDropzone = forwardRef(({ disabled, asChild = false, render, children, ...rest }, ref) => {
const [isDragging, setIsDragging] = useState(false);
const aui = useAui();
const disabledByThread = useAuiState((s) => s.thread.isDisabled);
const isDisabled = disabled || disabledByThread;
useEffect(() => {
if (!isDisabled) return;
setIsDragging(false);
}, [isDisabled]);
const handleDragEnterCapture = useCallback((e) => {
if (!e.dataTransfer.types.includes("Files")) return;
e.preventDefault();
if (isDisabled || !aui.thread.getState().capabilities.attachments) {
e.dataTransfer.dropEffect = "none";
return;
}
setIsDragging(true);
}, [isDisabled, aui]);
const handleDragOverCapture = useCallback((e_0) => {
if (!e_0.dataTransfer.types.includes("Files")) return;
e_0.preventDefault();
if (isDisabled || !aui.thread.getState().capabilities.attachments) {
e_0.dataTransfer.dropEffect = "none";
return;
}
if (!isDragging) setIsDragging(true);
}, [
isDisabled,
isDragging,
aui
]);
const handleDragLeaveCapture = useCallback((e_1) => {
if (isDisabled) return;
e_1.preventDefault();
const next = e_1.relatedTarget;
if (next && e_1.currentTarget.contains(next)) return;
setIsDragging(false);
}, [isDisabled]);
const handleDrop = useCallback(async (e_2) => {
setIsDragging(false);
if (!e_2.dataTransfer.types.includes("Files")) return;
e_2.preventDefault();
if (isDisabled) return;
const files = Array.from(e_2.dataTransfer.files);
if (!aui.thread.getState().capabilities.attachments || files.length === 0) return;
await Promise.all(files.map(async (file) => {
try {
await aui.composer.addAttachment(file);
} catch {}
}));
}, [isDisabled, aui]);
const mergedProps = {
...isDragging && !isDisabled ? { "data-dragging": "true" } : null,
...rest,
onDragEnterCapture: composeEventHandlers(rest.onDragEnterCapture, handleDragEnterCapture),
onDragOverCapture: composeEventHandlers(rest.onDragOverCapture, handleDragOverCapture),
onDragLeaveCapture: composeEventHandlers(rest.onDragLeaveCapture, handleDragLeaveCapture),
onDropCapture: composeEventHandlers(rest.onDropCapture, handleDrop),
ref
};
if (render && isValidElement(render)) return renderSlot(render, children, mergedProps);
const Comp = asChild ? Slot.Root : "div";
return /* @__PURE__ */ jsx(Comp, {
...mergedProps,
children
});
});
ComposerPrimitiveAttachmentDropzone.displayName = "ComposerPrimitive.AttachmentDropzone";
export { ComposerPrimitiveAttachmentDropzone };
//# sourceMappingURL=ComposerAttachmentDropzone.js.map