Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
1import { MAX_IMAGE_UPLOAD } from "@hey/data/constants";
2import { defineDOMEventHandler, type Editor, union } from "prosekit/core";
3import { useExtension } from "prosekit/react";
4import { useCallback, useEffect, useMemo, useRef } from "react";
5import { toast } from "sonner";
6import type { EditorExtension } from "@/helpers/prosekit/extension";
7import useUploadAttachments from "@/hooks/useUploadAttachments";
8import { usePostAttachmentStore } from "@/store/non-persisted/post/usePostAttachmentStore";
9
10const handleFiles = (
11 event: Event,
12 files: FileList | null | undefined,
13 onPaste: (files: FileList) => void
14): boolean => {
15 if (files?.length) {
16 event.preventDefault();
17 onPaste(files);
18 return true;
19 }
20 return false;
21};
22
23const definePasteDropExtension = (onPaste: (files: FileList) => void) => {
24 const dropExtension = defineDOMEventHandler("drop", (_view, event): boolean =>
25 handleFiles(event, event?.dataTransfer?.files, onPaste)
26 );
27
28 const pasteExtension = defineDOMEventHandler(
29 "paste",
30 (_view, event): boolean => {
31 if (event?.clipboardData?.getData("Text")) {
32 return false; // Ignore text pastes
33 }
34 return handleFiles(event, event?.clipboardData?.files, onPaste);
35 }
36 );
37
38 return union([dropExtension, pasteExtension]);
39};
40
41export const usePaste = (editor: Editor<EditorExtension>) => {
42 const { attachments } = usePostAttachmentStore();
43 const { handleUploadAttachments } = useUploadAttachments();
44
45 const handlePaste = useCallback(
46 async (pastedFiles: FileList) => {
47 const totalAttachments = attachments.length + pastedFiles.length;
48 if (
49 attachments.length === MAX_IMAGE_UPLOAD ||
50 totalAttachments > MAX_IMAGE_UPLOAD
51 ) {
52 return toast.error(
53 `Please choose either 1 video or up to ${MAX_IMAGE_UPLOAD} photos.`
54 );
55 }
56
57 if (pastedFiles) {
58 await handleUploadAttachments(pastedFiles);
59 }
60 },
61 [handleUploadAttachments, attachments.length]
62 );
63
64 const handlePasteRef = useRef(handlePaste);
65
66 useEffect(() => {
67 handlePasteRef.current = handlePaste;
68 }, [handlePaste]);
69
70 const extension = useMemo(() => {
71 return definePasteDropExtension((files) => handlePasteRef.current(files));
72 }, []);
73
74 useExtension(extension, { editor });
75};