From 1ba9ecdde8e57f7bed9dd5341e340c7bc3b8fac6 Mon Sep 17 00:00:00 2001 From: Md Saban Date: Wed, 2 Oct 2024 19:57:11 +0530 Subject: [PATCH 1/6] feat: allow pasting image from clipboard --- .../editor/src/parsers/getClipboardImage.ts | 41 +++++++++++++++++++ .../src/plugins/SlateEditorComponent.tsx | 8 +++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 packages/core/editor/src/parsers/getClipboardImage.ts diff --git a/packages/core/editor/src/parsers/getClipboardImage.ts b/packages/core/editor/src/parsers/getClipboardImage.ts new file mode 100644 index 000000000..4dd22f7cc --- /dev/null +++ b/packages/core/editor/src/parsers/getClipboardImage.ts @@ -0,0 +1,41 @@ +import { generateId } from '../utils/generateId'; +import { YooEditor, YooptaBlockData } from '../editor/types'; + +const buildBlockData = (imageURL: string) => { + const blockData = { + id: generateId(), + type: 'Image', + value: [ + { + id: generateId(), + type: 'image', + children: [{ text: '' }], + props: { + nodeType: 'void', + src: imageURL, + alt: 'pasted image', + srcSet: null, + fit: 'contain', + }, + }, + ], + meta: { + order: 0, + depth: 0, + align: 'left', + }, + }; + return blockData as YooptaBlockData; +}; + +export const pasteClipboardImage = (editor: YooEditor, image: DataTransferItem) => { + const blob = image.getAsFile(); + if (!blob) return; + const reader = new FileReader(); + reader.onload = (e) => { + if (!e.target) return; + const blockData = buildBlockData(e.target.result as string); + editor.insertBlock(blockData, { at: editor.selection, focus: true }); + }; + reader.readAsDataURL(blob); +}; diff --git a/packages/core/editor/src/plugins/SlateEditorComponent.tsx b/packages/core/editor/src/plugins/SlateEditorComponent.tsx index e029e6ee5..8f40ca0db 100644 --- a/packages/core/editor/src/plugins/SlateEditorComponent.tsx +++ b/packages/core/editor/src/plugins/SlateEditorComponent.tsx @@ -11,6 +11,7 @@ import { TextLeaf } from '../components/TextLeaf/TextLeaf'; import { IS_FOCUSED_EDITOR } from '../utils/weakMaps'; import { deserializeHTML } from '../parsers/deserializeHTML'; +import { pasteClipboardImage } from '../parsers/getClipboardImage'; import { useEventHandlers, useSlateEditor } from './hooks'; import { SlateElement } from '../editor/types'; @@ -154,9 +155,9 @@ const SlateEditorComponent = , const data = event.clipboardData; const html = data.getData('text/html'); + const clipboardItem = data.items[0]; const parsedHTML = new DOMParser().parseFromString(html, 'text/html'); - if (parsedHTML.body.childNodes.length > 0) { const blocks = deserializeHTML(editor, parsedHTML.body); @@ -167,6 +168,11 @@ const SlateEditorComponent = , return; } } + const isImageInClipboard = clipboardItem?.type?.startsWith('image/'); + if (isImageInClipboard) { + event.preventDefault(); + pasteClipboardImage(editor, clipboardItem); + } }, [eventHandlers.onPaste, editor.readOnly], ); From a70600be543b3252da448975004b5e2b0cf93807 Mon Sep 17 00:00:00 2001 From: Md Saban Date: Sun, 10 Nov 2024 15:35:54 +0530 Subject: [PATCH 2/6] fix: add onpaste and ondrop on editor --- .../editor/src/components/Editor/Editor.tsx | 54 ++++++++++++++++++- .../editor/src/parsers/getClipboardImage.ts | 41 -------------- .../src/plugins/SlateEditorComponent.tsx | 8 +-- packages/plugins/image/src/plugin/index.tsx | 1 + packages/plugins/image/src/types.ts | 1 + packages/plugins/video/src/plugin/index.tsx | 1 + packages/plugins/video/src/types.ts | 1 + 7 files changed, 58 insertions(+), 49 deletions(-) delete mode 100644 packages/core/editor/src/parsers/getClipboardImage.ts diff --git a/packages/core/editor/src/components/Editor/Editor.tsx b/packages/core/editor/src/components/Editor/Editor.tsx index e88cebc5d..84c3af8c6 100644 --- a/packages/core/editor/src/components/Editor/Editor.tsx +++ b/packages/core/editor/src/components/Editor/Editor.tsx @@ -169,7 +169,6 @@ const Editor = ({ navigator.clipboard.write([clipboardItem]).then(() => { const html = new DOMParser().parseFromString(htmlString, 'text/html'); - console.log('HTML copied\n', html.body); }); if (HOTKEYS.isCut(event)) { @@ -306,6 +305,57 @@ const Editor = ({ } }; + const addImageOrVideoFromClipboard = async (file: File) => { + const ImagePlugin = { + plugin: editor.plugins.Image, + type: 'Image', + }; + const VideoPlugin = { + plugin: editor.plugins.Video, + type: 'Video', + }; + + const isImage = file.type.startsWith('image/'); + const { plugin, type } = isImage ? ImagePlugin : VideoPlugin; + + if (!plugin?.options) return; + + if (!plugin.options.enableFromClipboard) return; + + const mimeTypes = plugin.options.accept; + if (isImage && !mimeTypes.includes(file.type)) return; + if (!file.type.includes('video')) return; + + const element = await plugin.options.onUpload(file); + let block; + if (type === 'Image') { + block = plugin.commands?.buildImageElements(editor, { props: element }); + } + if (type === 'Video') { + block = plugin.commands?.buildVideoElements(editor, { props: element }); + } + const blockData = Blocks.buildBlockData({ type, value: [block] }); + Blocks.insertBlock(editor, type, { focus: true, blockData }); + }; + + const onPaste = (e: ClipboardEvent) => { + const items = e.clipboardData.items; + for (const item of items) { + const file = item.getAsFile(); + if (!file) continue; + addImageOrVideoFromClipboard(file); + } + }; + + const onDrop = (e: DragEvent) => { + const items = e.dataTransfer?.files; + if (!items) return; + for (const file of items) { + if (!file) continue; + addImageOrVideoFromClipboard(file); + } + }; + const editorStyles: CSSProperties = getEditorStyles({ userSelect: selectionBox.selection ? 'none' : 'auto', pointerEvents: selectionBox.selection ? 'none' : 'auto', @@ -322,6 +372,8 @@ const Editor = ({ onBlur={onBlur} onCopy={onCopy} onCut={onCopy} + onPaste={onPaste} + onDrop={onDrop} > {selectionBoxRoot !== false && ( diff --git a/packages/core/editor/src/parsers/getClipboardImage.ts b/packages/core/editor/src/parsers/getClipboardImage.ts deleted file mode 100644 index 4dd22f7cc..000000000 --- a/packages/core/editor/src/parsers/getClipboardImage.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { generateId } from '../utils/generateId'; -import { YooEditor, YooptaBlockData } from '../editor/types'; - -const buildBlockData = (imageURL: string) => { - const blockData = { - id: generateId(), - type: 'Image', - value: [ - { - id: generateId(), - type: 'image', - children: [{ text: '' }], - props: { - nodeType: 'void', - src: imageURL, - alt: 'pasted image', - srcSet: null, - fit: 'contain', - }, - }, - ], - meta: { - order: 0, - depth: 0, - align: 'left', - }, - }; - return blockData as YooptaBlockData; -}; - -export const pasteClipboardImage = (editor: YooEditor, image: DataTransferItem) => { - const blob = image.getAsFile(); - if (!blob) return; - const reader = new FileReader(); - reader.onload = (e) => { - if (!e.target) return; - const blockData = buildBlockData(e.target.result as string); - editor.insertBlock(blockData, { at: editor.selection, focus: true }); - }; - reader.readAsDataURL(blob); -}; diff --git a/packages/core/editor/src/plugins/SlateEditorComponent.tsx b/packages/core/editor/src/plugins/SlateEditorComponent.tsx index 4ad242162..1c494724a 100644 --- a/packages/core/editor/src/plugins/SlateEditorComponent.tsx +++ b/packages/core/editor/src/plugins/SlateEditorComponent.tsx @@ -11,7 +11,6 @@ import { TextLeaf } from '../components/TextLeaf/TextLeaf'; import { IS_FOCUSED_EDITOR } from '../utils/weakMaps'; import { deserializeHTML } from '../parsers/deserializeHTML'; -import { pasteClipboardImage } from '../parsers/getClipboardImage'; import { useEventHandlers, useSlateEditor } from './hooks'; import { SlateElement } from '../editor/types'; import { Paths } from '../editor/paths'; @@ -163,9 +162,9 @@ const SlateEditorComponent = , const data = event.clipboardData; const html = data.getData('text/html'); - const clipboardItem = data.items[0]; const parsedHTML = new DOMParser().parseFromString(html, 'text/html'); + if (parsedHTML.body.childNodes.length > 0) { const blocks = deserializeHTML(editor, parsedHTML.body); @@ -212,11 +211,6 @@ const SlateEditorComponent = , return; } } - const isImageInClipboard = clipboardItem?.type?.startsWith('image/'); - if (isImageInClipboard) { - event.preventDefault(); - pasteClipboardImage(editor, clipboardItem); - } }, [eventHandlers.onPaste, editor.readOnly], ); diff --git a/packages/plugins/image/src/plugin/index.tsx b/packages/plugins/image/src/plugin/index.tsx index b5397e446..e7cda79c7 100644 --- a/packages/plugins/image/src/plugin/index.tsx +++ b/packages/plugins/image/src/plugin/index.tsx @@ -35,6 +35,7 @@ const Image = new YooptaPlugin({ onUpload: () => Promise.resolve({ src: null, alt: null }), accept: 'image/png, image/jpeg, image/gif, image/webp', maxSizes: { maxWidth: 650, maxHeight: 550 }, + enableFromClipboard: true, }, parsers: { html: { diff --git a/packages/plugins/image/src/types.ts b/packages/plugins/image/src/types.ts index db17df3db..51895af7e 100644 --- a/packages/plugins/image/src/types.ts +++ b/packages/plugins/image/src/types.ts @@ -32,6 +32,7 @@ export type ImagePluginOptions = { maxWidth?: number; maxHeight?: number; }; + enableFromClipboard?: boolean; }; export type ImageElementMap = { diff --git a/packages/plugins/video/src/plugin/index.tsx b/packages/plugins/video/src/plugin/index.tsx index 1c21de845..350f21633 100644 --- a/packages/plugins/video/src/plugin/index.tsx +++ b/packages/plugins/video/src/plugin/index.tsx @@ -43,6 +43,7 @@ const Video = new YooptaPlugin({ title: 'Video', description: 'Upload from device, embed from Youtube, Vimeo', }, + enableFromClipboard: true, }, commands: VideoCommands, parsers: { diff --git a/packages/plugins/video/src/types.ts b/packages/plugins/video/src/types.ts index 6f365e64c..a34bdc2e6 100644 --- a/packages/plugins/video/src/types.ts +++ b/packages/plugins/video/src/types.ts @@ -43,6 +43,7 @@ export type VideoPluginOptions = { maxWidth?: number; maxHeight?: number; }; + enableFromClipboard?: boolean; }; export type VideoElementMap = { From 5e0845fcdf529411a1e37517d0960ff501d61c29 Mon Sep 17 00:00:00 2001 From: Md Saban Date: Tue, 12 Nov 2024 22:46:01 +0530 Subject: [PATCH 3/6] fix: remove plugin logic from core --- .../editor/src/components/Editor/Editor.tsx | 45 +++++++------------ .../editor/src/plugins/createYooptaPlugin.tsx | 2 + packages/core/editor/src/plugins/types.ts | 1 + packages/plugins/image/src/commands/index.ts | 4 +- packages/plugins/image/src/plugin/index.tsx | 9 +++- packages/plugins/image/src/types.ts | 1 - packages/plugins/video/src/commands/index.ts | 4 +- packages/plugins/video/src/plugin/index.tsx | 9 +++- packages/plugins/video/src/types.ts | 1 - 9 files changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/core/editor/src/components/Editor/Editor.tsx b/packages/core/editor/src/components/Editor/Editor.tsx index 84c3af8c6..b398d8f6d 100644 --- a/packages/core/editor/src/components/Editor/Editor.tsx +++ b/packages/core/editor/src/components/Editor/Editor.tsx @@ -306,36 +306,21 @@ const Editor = ({ }; const addImageOrVideoFromClipboard = async (file: File) => { - const ImagePlugin = { - plugin: editor.plugins.Image, - type: 'Image', - }; - const VideoPlugin = { - plugin: editor.plugins.Video, - type: 'Video', - }; - - const isImage = file.type.startsWith('image/'); - const { plugin, type } = isImage ? ImagePlugin : VideoPlugin; - - if (!plugin?.options) return; - - if (!plugin.options.enableFromClipboard) return; - - const mimeTypes = plugin.options.accept; - if (isImage && !mimeTypes.includes(file.type)) return; - if (!file.type.includes('video')) return; - - const element = await plugin.options.onUpload(file); - let block; - if (type === 'Image') { - block = plugin.commands?.buildImageElements(editor, { props: element }); - } - if (type === 'Video') { - block = plugin.commands?.buildVideoElements(editor, { props: element }); - } - const blockData = Blocks.buildBlockData({ type, value: [block] }); - Blocks.insertBlock(editor, type, { focus: true, blockData }); + const plugin = Object.keys(editor.plugins).find((plugin) => { + const pluginInstance = editor.plugins[plugin]; + const mimeTypes = pluginInstance.clipboardPasteOrDropRules?.mimeTypes; + if (!mimeTypes) return false; + return mimeTypes.includes(file.type); + }); + + if (!plugin) return; + + const pluginInstance = editor.plugins[plugin]; + const block = await pluginInstance.clipboardPasteOrDropRules?.handler(file); + if (!block) return; + + const blockData = Blocks.buildBlockData({ type: pluginInstance.type, value: [block] }); + Blocks.insertBlock(editor, pluginInstance.type, { focus: true, blockData }); }; const onPaste = (e: ClipboardEvent) => { diff --git a/packages/core/editor/src/plugins/createYooptaPlugin.tsx b/packages/core/editor/src/plugins/createYooptaPlugin.tsx index ed926514f..c282121df 100644 --- a/packages/core/editor/src/plugins/createYooptaPlugin.tsx +++ b/packages/core/editor/src/plugins/createYooptaPlugin.tsx @@ -38,6 +38,7 @@ export class YooptaPlugin, TOpt const extendedOptions = { ...this.plugin.options, ...options }; const elements = { ...this.plugin.elements }; + const clipboardPasteOrDropRules = { ...this.plugin.clipboardPasteOrDropRules }; if (renders) { Object.keys(renders).forEach((elementType) => { @@ -84,6 +85,7 @@ export class YooptaPlugin, TOpt ...this.plugin, elements: elements, options: extendedOptions as PluginOptions, + clipboardPasteOrDropRules: clipboardPasteOrDropRules, }); } } diff --git a/packages/core/editor/src/plugins/types.ts b/packages/core/editor/src/plugins/types.ts index cfcc3c7bd..ae3118915 100644 --- a/packages/core/editor/src/plugins/types.ts +++ b/packages/core/editor/src/plugins/types.ts @@ -89,6 +89,7 @@ export type Plugin, TPluginOpti events?: PluginEvents; options?: PluginOptions; parsers?: Partial>; + clipboardPasteOrDropRules?: Record; }; export type PluginParsers = { diff --git a/packages/plugins/image/src/commands/index.ts b/packages/plugins/image/src/commands/index.ts index 4b39abceb..166d9a9d2 100644 --- a/packages/plugins/image/src/commands/index.ts +++ b/packages/plugins/image/src/commands/index.ts @@ -11,14 +11,14 @@ type InsertImageOptions = ImageElementOptions & { }; export type ImageCommands = { - buildImageElements: (editor: YooEditor, options?: Partial) => ImageElement; + buildImageElements: (editor?: YooEditor, options?: Partial) => ImageElement; insertImage: (editor: YooEditor, options?: Partial) => void; deleteImage: (editor: YooEditor, blockId: string) => void; updateImage: (editor: YooEditor, blockId: string, props: Partial) => void; }; export const ImageCommands: ImageCommands = { - buildImageElements: (editor: YooEditor, options = {}) => { + buildImageElements: (editor?: YooEditor, options = {}) => { const imageProps = { ...options.props, nodeType: 'void' }; return { id: generateId(), type: 'image', children: [{ text: '' }], props: imageProps as ImageElementProps }; }, diff --git a/packages/plugins/image/src/plugin/index.tsx b/packages/plugins/image/src/plugin/index.tsx index e7cda79c7..1069cb4ed 100644 --- a/packages/plugins/image/src/plugin/index.tsx +++ b/packages/plugins/image/src/plugin/index.tsx @@ -35,7 +35,14 @@ const Image = new YooptaPlugin({ onUpload: () => Promise.resolve({ src: null, alt: null }), accept: 'image/png, image/jpeg, image/gif, image/webp', maxSizes: { maxWidth: 650, maxHeight: 550 }, - enableFromClipboard: true, + }, + clipboardPasteOrDropRules: { + mimeTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'], + handler: async (file: File) => { + const data = await Image.getPlugin.options.onUpload(file); + const block = ImageCommands.buildImageElements(undefined, { props: data }); + return block; + }, }, parsers: { html: { diff --git a/packages/plugins/image/src/types.ts b/packages/plugins/image/src/types.ts index 51895af7e..db17df3db 100644 --- a/packages/plugins/image/src/types.ts +++ b/packages/plugins/image/src/types.ts @@ -32,7 +32,6 @@ export type ImagePluginOptions = { maxWidth?: number; maxHeight?: number; }; - enableFromClipboard?: boolean; }; export type ImageElementMap = { diff --git a/packages/plugins/video/src/commands/index.ts b/packages/plugins/video/src/commands/index.ts index 5849c9ab9..4a9a6079e 100644 --- a/packages/plugins/video/src/commands/index.ts +++ b/packages/plugins/video/src/commands/index.ts @@ -11,14 +11,14 @@ type InsertVideoOptions = VideoElementOptions & { }; export type VideoCommands = { - buildVideoElements: (editor: YooEditor, options?: Partial) => VideoElement; + buildVideoElements: (editor?: YooEditor, options?: Partial) => VideoElement; insertVideo: (editor: YooEditor, options?: Partial) => void; deleteVideo: (editor: YooEditor, blockId: string) => void; updateVideo: (editor: YooEditor, blockId: string, props: Partial) => void; }; export const VideoCommands: VideoCommands = { - buildVideoElements: (editor: YooEditor, options = {}) => { + buildVideoElements: (editor?: YooEditor, options = {}) => { const videoProps = { ...options.props, nodeType: 'void' }; return { id: generateId(), type: 'video', children: [{ text: '' }], props: videoProps as VideoElementProps }; }, diff --git a/packages/plugins/video/src/plugin/index.tsx b/packages/plugins/video/src/plugin/index.tsx index 350f21633..71ca61604 100644 --- a/packages/plugins/video/src/plugin/index.tsx +++ b/packages/plugins/video/src/plugin/index.tsx @@ -43,7 +43,14 @@ const Video = new YooptaPlugin({ title: 'Video', description: 'Upload from device, embed from Youtube, Vimeo', }, - enableFromClipboard: true, + }, + clipboardPasteOrDropRules: { + mimeTypes: ['video/mp4', 'video/webm', 'video/ogg', 'video/quicktime'], + handler: async (file: File) => { + const data = await Video.getPlugin.options.onUpload(file); + const block = VideoCommands.buildVideoElements(undefined, { props: data }); + return block; + }, }, commands: VideoCommands, parsers: { diff --git a/packages/plugins/video/src/types.ts b/packages/plugins/video/src/types.ts index a34bdc2e6..6f365e64c 100644 --- a/packages/plugins/video/src/types.ts +++ b/packages/plugins/video/src/types.ts @@ -43,7 +43,6 @@ export type VideoPluginOptions = { maxWidth?: number; maxHeight?: number; }; - enableFromClipboard?: boolean; }; export type VideoElementMap = { From 6a4ea4bc3beee6f87d0b3c382bc7114dfd323e5c Mon Sep 17 00:00:00 2001 From: Md Saban Date: Wed, 13 Nov 2024 09:08:21 +0530 Subject: [PATCH 4/6] fix: use onUpload in editor's context --- packages/core/editor/src/components/Editor/Editor.tsx | 8 ++++---- packages/core/editor/src/plugins/types.ts | 7 ++++++- packages/plugins/image/src/plugin/index.tsx | 7 ++++--- packages/plugins/video/src/plugin/index.tsx | 7 ++++--- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/core/editor/src/components/Editor/Editor.tsx b/packages/core/editor/src/components/Editor/Editor.tsx index b398d8f6d..989c06c56 100644 --- a/packages/core/editor/src/components/Editor/Editor.tsx +++ b/packages/core/editor/src/components/Editor/Editor.tsx @@ -305,7 +305,7 @@ const Editor = ({ } }; - const addImageOrVideoFromClipboard = async (file: File) => { + const handleClipboardContent = async (file: File) => { const plugin = Object.keys(editor.plugins).find((plugin) => { const pluginInstance = editor.plugins[plugin]; const mimeTypes = pluginInstance.clipboardPasteOrDropRules?.mimeTypes; @@ -316,7 +316,7 @@ const Editor = ({ if (!plugin) return; const pluginInstance = editor.plugins[plugin]; - const block = await pluginInstance.clipboardPasteOrDropRules?.handler(file); + const block = await pluginInstance.clipboardPasteOrDropRules?.handler(file, editor); if (!block) return; const blockData = Blocks.buildBlockData({ type: pluginInstance.type, value: [block] }); @@ -328,7 +328,7 @@ const Editor = ({ for (const item of items) { const file = item.getAsFile(); if (!file) continue; - addImageOrVideoFromClipboard(file); + handleClipboardContent(file); } }; @@ -337,7 +337,7 @@ const Editor = ({ if (!items) return; for (const file of items) { if (!file) continue; - addImageOrVideoFromClipboard(file); + handleClipboardContent(file); } }; diff --git a/packages/core/editor/src/plugins/types.ts b/packages/core/editor/src/plugins/types.ts index ae3118915..67ca16062 100644 --- a/packages/core/editor/src/plugins/types.ts +++ b/packages/core/editor/src/plugins/types.ts @@ -64,6 +64,11 @@ export type EventHandlers = { ) => EditorEventHandlers[key] | void; }; +export type PluginClipboardPasteOrDropRules = { + mimeTypes: string[]; + handler: (file: File, editor: YooEditor) => Promise; +}; + export type PluginEventHandlerOptions = { hotkeys: HOTKEYS_TYPE; defaultBlock: YooptaBlockData; @@ -89,7 +94,7 @@ export type Plugin, TPluginOpti events?: PluginEvents; options?: PluginOptions; parsers?: Partial>; - clipboardPasteOrDropRules?: Record; + clipboardPasteOrDropRules?: PluginClipboardPasteOrDropRules; }; export type PluginParsers = { diff --git a/packages/plugins/image/src/plugin/index.tsx b/packages/plugins/image/src/plugin/index.tsx index 1069cb4ed..30d8e2983 100644 --- a/packages/plugins/image/src/plugin/index.tsx +++ b/packages/plugins/image/src/plugin/index.tsx @@ -1,4 +1,4 @@ -import { generateId, SlateElement, YooptaPlugin } from '@yoopta/editor'; +import { generateId, SlateElement, YooptaPlugin, YooEditor } from '@yoopta/editor'; import { ImageCommands } from '../commands'; import { ImageElementMap, ImageElementProps, ImagePluginElements, ImagePluginOptions } from '../types'; import { ImageRender } from '../ui/Image'; @@ -38,8 +38,9 @@ const Image = new YooptaPlugin({ }, clipboardPasteOrDropRules: { mimeTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'], - handler: async (file: File) => { - const data = await Image.getPlugin.options.onUpload(file); + handler: async (file: File, editor: YooEditor) => { + const pluginOptions = editor.plugins.Image.options as ImagePluginOptions; + const data = await pluginOptions.onUpload(file); const block = ImageCommands.buildImageElements(undefined, { props: data }); return block; }, diff --git a/packages/plugins/video/src/plugin/index.tsx b/packages/plugins/video/src/plugin/index.tsx index 71ca61604..3ce0be585 100644 --- a/packages/plugins/video/src/plugin/index.tsx +++ b/packages/plugins/video/src/plugin/index.tsx @@ -1,4 +1,4 @@ -import { generateId, YooptaPlugin } from '@yoopta/editor'; +import { generateId, YooptaPlugin, YooEditor } from '@yoopta/editor'; import { VideoCommands } from '../commands'; import { VideoElementMap, VideoPluginOptions } from '../types'; import { VideoRender } from '../ui/Video'; @@ -46,8 +46,9 @@ const Video = new YooptaPlugin({ }, clipboardPasteOrDropRules: { mimeTypes: ['video/mp4', 'video/webm', 'video/ogg', 'video/quicktime'], - handler: async (file: File) => { - const data = await Video.getPlugin.options.onUpload(file); + handler: async (file: File, editor: YooEditor) => { + const pluginOptions = editor.plugins.Video.options as VideoPluginOptions; + const data = await pluginOptions.onUpload(file); const block = VideoCommands.buildVideoElements(undefined, { props: data }); return block; }, From e79ea2de560338b4ad60fcfec78331afe5239147 Mon Sep 17 00:00:00 2001 From: Alexandru Golovatenco <38139664+5andu@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:39:26 +0100 Subject: [PATCH 5/6] update email examples (#391) ## Description Added the ability to add Loom & Wistia videos in the Video plugin. Note that I'm not used to Typescrpt at all, so I might need some help with this if you see issues. Fixes # (issue) ## Type of change Please tick the relevant option. - [ ] Bug fix (non-breaking change which fixes an issue) - [x ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ## Checklist: - [ ] I have performed a self-review of my own code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have checked my code and corrected any misspellings --- packages/plugins/embed/src/providers/Loom.tsx | 38 +++++++++++ .../plugins/embed/src/providers/Wistia.tsx | 43 ++++++++++++ packages/plugins/embed/src/types.ts | 2 + .../plugins/embed/src/ui/EmbedComponent.tsx | 2 + packages/plugins/embed/src/utils/providers.ts | 16 +++++ packages/plugins/video/src/plugin/index.tsx | 2 +- packages/plugins/video/src/types.ts | 2 +- .../plugins/video/src/ui/EmbedUploader.tsx | 2 +- packages/plugins/video/src/ui/LoomPlayer.tsx | 66 +++++++++++++++++++ .../plugins/video/src/ui/VideoComponent.tsx | 4 ++ .../plugins/video/src/ui/WistiaPlayer.tsx | 52 +++++++++++++++ packages/plugins/video/src/utils/providers.ts | 33 ++++++++++ 12 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 packages/plugins/embed/src/providers/Loom.tsx create mode 100644 packages/plugins/embed/src/providers/Wistia.tsx create mode 100644 packages/plugins/video/src/ui/LoomPlayer.tsx create mode 100644 packages/plugins/video/src/ui/WistiaPlayer.tsx diff --git a/packages/plugins/embed/src/providers/Loom.tsx b/packages/plugins/embed/src/providers/Loom.tsx new file mode 100644 index 000000000..8003e21a9 --- /dev/null +++ b/packages/plugins/embed/src/providers/Loom.tsx @@ -0,0 +1,38 @@ +import { useRef, useState } from 'react'; +import { useIntersectionObserver } from '../hooks/useIntersectionObserver'; +import { ProviderRenderProps } from '../types'; + +function Loom({ provider, attributes, children }: ProviderRenderProps) { + const loomRootRef = useRef(null); + const [isFrameLoaded, setFrameLoaded] = useState(false); + + const { isIntersecting: isInViewport } = useIntersectionObserver(loomRootRef, { + freezeOnceVisible: true, + rootMargin: '50%', + }); + + const onRef = (node) => { + loomRootRef.current = node; + attributes.ref(node); + }; + + return ( +
+ {isInViewport && ( +