mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 17:33:51 +02:00
Fix issue chat composer dropzone scope
This commit is contained in:
1 parent
d845ff6d9b
commit
1feac07821
4 files changed
+91
-4
No files matched your search
@@ -69,12 +69,14 @@ vi.mock("./MarkdownEditor", () => ({
|
||||
placeholder,
|
||||
className,
|
||||
contentClassName,
|
||||
fileDropTarget,
|
||||
}: {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
contentClassName?: string;
|
||||
fileDropTarget?: "editor" | "parent";
|
||||
}, ref) => {
|
||||
useImperativeHandle(ref, () => ({
|
||||
focus: markdownEditorFocusMock,
|
||||
@@ -85,6 +87,7 @@ vi.mock("./MarkdownEditor", () => ({
|
||||
aria-label="Issue chat editor"
|
||||
data-class-name={className}
|
||||
data-content-class-name={contentClassName}
|
||||
data-file-drop-target={fileDropTarget}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={(event) => onChange?.(event.target.value)}
|
||||
@@ -818,6 +821,7 @@ describe("IssueChatThread", () => {
|
||||
expect(editor?.dataset.contentClassName).toContain("max-h-[28dvh]");
|
||||
expect(editor?.dataset.contentClassName).toContain("overflow-y-auto");
|
||||
expect(editor?.dataset.contentClassName).not.toContain("min-h-[72px]");
|
||||
expect(editor?.dataset.fileDropTarget).toBe("parent");
|
||||
|
||||
act(() => {
|
||||
root.unmount();
|
||||
|
||||
@@ -2254,6 +2254,7 @@ const IssueChatComposer = forwardRef<IssueChatComposerHandle, IssueChatComposerP
|
||||
mentions={mentions}
|
||||
onSubmit={handleSubmit}
|
||||
imageUploadHandler={onImageUpload}
|
||||
fileDropTarget="parent"
|
||||
bordered={false}
|
||||
contentClassName="max-h-[28dvh] overflow-y-auto pr-1 text-sm scrollbar-auto-hide"
|
||||
/>
|
||||
@@ -2270,7 +2271,6 @@ const IssueChatComposer = forwardRef<IssueChatComposerHandle, IssueChatComposerP
|
||||
<input
|
||||
ref={attachInputRef}
|
||||
type="file"
|
||||
accept="image/png,image/jpeg,image/webp,image/gif"
|
||||
className="hidden"
|
||||
onChange={handleAttachFile}
|
||||
/>
|
||||
@@ -2279,7 +2279,7 @@ const IssueChatComposer = forwardRef<IssueChatComposerHandle, IssueChatComposerP
|
||||
size="icon-sm"
|
||||
onClick={() => attachInputRef.current?.click()}
|
||||
disabled={attaching}
|
||||
title="Attach image"
|
||||
title="Attach file"
|
||||
>
|
||||
<Paperclip className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
@@ -148,6 +148,17 @@ async function flush() {
|
||||
});
|
||||
}
|
||||
|
||||
function createFileDragEvent(type: string) {
|
||||
const event = new Event(type, { bubbles: true, cancelable: true }) as Event & {
|
||||
dataTransfer: { types: string[]; files: File[]; dropEffect?: string };
|
||||
};
|
||||
event.dataTransfer = {
|
||||
types: ["Files"],
|
||||
files: [],
|
||||
};
|
||||
return event;
|
||||
}
|
||||
|
||||
describe("MarkdownEditor", () => {
|
||||
let container: HTMLDivElement;
|
||||
let originalRangeRect: typeof Range.prototype.getBoundingClientRect;
|
||||
@@ -319,6 +330,76 @@ describe("MarkdownEditor", () => {
|
||||
root.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
it("shows the editor-scoped dropzone by default when files are dragged over it", async () => {
|
||||
const root = createRoot(container);
|
||||
|
||||
await act(async () => {
|
||||
root.render(
|
||||
<MarkdownEditor
|
||||
value=""
|
||||
onChange={() => {}}
|
||||
placeholder="Markdown body"
|
||||
imageUploadHandler={async () => "https://example.com/image.png"}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
await flush();
|
||||
|
||||
const scope = container.querySelector('[data-testid="mdx-editor"]')?.parentElement as HTMLDivElement | null;
|
||||
expect(scope).not.toBeNull();
|
||||
|
||||
act(() => {
|
||||
scope?.dispatchEvent(createFileDragEvent("dragenter"));
|
||||
});
|
||||
|
||||
expect(scope?.className).toContain("ring-1");
|
||||
expect(container.textContent).toContain("Drop image to upload");
|
||||
|
||||
act(() => {
|
||||
scope?.dispatchEvent(createFileDragEvent("dragleave"));
|
||||
});
|
||||
|
||||
expect(scope?.className).not.toContain("ring-1");
|
||||
|
||||
await act(async () => {
|
||||
root.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
it("defers file-drop visuals to a parent container when requested", async () => {
|
||||
const root = createRoot(container);
|
||||
|
||||
await act(async () => {
|
||||
root.render(
|
||||
<MarkdownEditor
|
||||
value=""
|
||||
onChange={() => {}}
|
||||
placeholder="Markdown body"
|
||||
imageUploadHandler={async () => "https://example.com/image.png"}
|
||||
fileDropTarget="parent"
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
await flush();
|
||||
|
||||
const scope = container.querySelector('[data-testid="mdx-editor"]')?.parentElement as HTMLDivElement | null;
|
||||
expect(scope).not.toBeNull();
|
||||
|
||||
act(() => {
|
||||
scope?.dispatchEvent(createFileDragEvent("dragenter"));
|
||||
});
|
||||
|
||||
expect(scope?.className).not.toContain("ring-1");
|
||||
expect(container.textContent).not.toContain("Drop image to upload");
|
||||
|
||||
await act(async () => {
|
||||
root.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
it("anchors the mention menu inside the visual viewport when mobile offsets are present", () => {
|
||||
expect(
|
||||
computeMentionMenuPosition(
|
||||
|
||||
@@ -68,6 +68,8 @@ interface MarkdownEditorProps {
|
||||
imageUploadHandler?: (file: File) => Promise<string>;
|
||||
/** Called when a non-image file is dropped onto the editor (e.g. .zip). */
|
||||
onDropFile?: (file: File) => Promise<void>;
|
||||
/** When set to `parent`, a wrapper owns drag/drop behavior and visuals. */
|
||||
fileDropTarget?: "editor" | "parent";
|
||||
bordered?: boolean;
|
||||
/** List of mentionable entities. Enables @-mention autocomplete. */
|
||||
mentions?: MentionOption[];
|
||||
@@ -491,6 +493,7 @@ export const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>
|
||||
onBlur,
|
||||
imageUploadHandler,
|
||||
onDropFile,
|
||||
fileDropTarget = "editor",
|
||||
bordered = true,
|
||||
mentions,
|
||||
onSubmit,
|
||||
@@ -897,8 +900,7 @@ export const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>
|
||||
return Array.from(evt.dataTransfer?.types ?? []).includes("Files");
|
||||
}
|
||||
|
||||
const canDropImage = Boolean(imageUploadHandler);
|
||||
const canDropFile = Boolean(imageUploadHandler || onDropFile);
|
||||
const canDropFile = fileDropTarget === "editor" && Boolean(imageUploadHandler || onDropFile);
|
||||
const handlePasteCapture = useCallback((event: ClipboardEvent<HTMLDivElement>) => {
|
||||
const clipboard = event.clipboardData;
|
||||
if (!clipboard || !ref.current) return;
|
||||
|
||||
Reference in new issue
Block a user