mirror of https://github.com/buster-so/buster.git
Update MediaEmbedNode.tsx
This commit is contained in:
parent
ce7ecbe4bb
commit
3b4394874e
|
@ -6,12 +6,19 @@ import LiteYouTubeEmbed from 'react-lite-youtube-embed';
|
||||||
import type { TMediaEmbedElement } from 'platejs';
|
import type { TMediaEmbedElement } from 'platejs';
|
||||||
import type { PlateElementProps } from 'platejs/react';
|
import type { PlateElementProps } from 'platejs/react';
|
||||||
|
|
||||||
import { parseTwitterUrl, parseVideoUrl } from '@platejs/media';
|
import {
|
||||||
|
parseTwitterUrl,
|
||||||
|
parseVideoUrl,
|
||||||
|
parseIframeUrl,
|
||||||
|
parseMediaUrl,
|
||||||
|
type EmbedUrlParser
|
||||||
|
} from '@platejs/media';
|
||||||
import { MediaEmbedPlugin, useMediaState } from '@platejs/media/react';
|
import { MediaEmbedPlugin, useMediaState } from '@platejs/media/react';
|
||||||
import { ResizableProvider, useResizableValue } from '@platejs/resizable';
|
import { ResizableProvider, useResizableValue } from '@platejs/resizable';
|
||||||
import {
|
import {
|
||||||
PlateElement,
|
PlateElement,
|
||||||
useEditorRef,
|
useEditorRef,
|
||||||
|
useElement,
|
||||||
useFocused,
|
useFocused,
|
||||||
useReadOnly,
|
useReadOnly,
|
||||||
useSelected,
|
useSelected,
|
||||||
|
@ -25,17 +32,27 @@ import { MediaToolbar } from './MediaToolbar';
|
||||||
import { mediaResizeHandleVariants, Resizable, ResizeHandle } from './ResizeHandle';
|
import { mediaResizeHandleVariants, Resizable, ResizeHandle } from './ResizeHandle';
|
||||||
import { Code3 } from '../../icons';
|
import { Code3 } from '../../icons';
|
||||||
import { PopoverAnchor, PopoverBase, PopoverContent } from '../../popover';
|
import { PopoverAnchor, PopoverBase, PopoverContent } from '../../popover';
|
||||||
import { Title, Text } from '../../typography';
|
import { Text } from '../../typography';
|
||||||
import { Input } from '../../inputs';
|
import { Input } from '../../inputs';
|
||||||
import { Button } from '../../buttons';
|
import { Button } from '../../buttons';
|
||||||
import { Separator } from '../../separator';
|
import { Separator } from '../../separator';
|
||||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useMount } from '@/hooks';
|
import { useClickAway } from '@/hooks/useClickAway';
|
||||||
|
|
||||||
|
const parseGenericUrl: EmbedUrlParser = (url: string) => {
|
||||||
|
return {
|
||||||
|
url,
|
||||||
|
provider: 'generic'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const urlParsers: EmbedUrlParser[] = [parseTwitterUrl, parseVideoUrl, parseGenericUrl];
|
||||||
|
|
||||||
export const MediaEmbedElement = withHOC(
|
export const MediaEmbedElement = withHOC(
|
||||||
ResizableProvider,
|
ResizableProvider,
|
||||||
function MediaEmbedElement(props: PlateElementProps<TMediaEmbedElement>) {
|
function MediaEmbedElement(props: PlateElementProps<TMediaEmbedElement>) {
|
||||||
|
const url = props.element.url;
|
||||||
const {
|
const {
|
||||||
align = 'center',
|
align = 'center',
|
||||||
embed,
|
embed,
|
||||||
|
@ -44,13 +61,14 @@ export const MediaEmbedElement = withHOC(
|
||||||
isVideo,
|
isVideo,
|
||||||
isYoutube,
|
isYoutube,
|
||||||
readOnly,
|
readOnly,
|
||||||
selected
|
selected,
|
||||||
|
...rest
|
||||||
} = useMediaState({
|
} = useMediaState({
|
||||||
urlParsers: [parseTwitterUrl, parseVideoUrl]
|
urlParsers
|
||||||
});
|
});
|
||||||
const width = useResizableValue('width');
|
const width = useResizableValue('width');
|
||||||
const provider = embed?.provider;
|
const provider = embed?.provider;
|
||||||
const hasElement = !!embed?.url;
|
const hasElement = !!url;
|
||||||
|
|
||||||
if (!hasElement) {
|
if (!hasElement) {
|
||||||
return <MediaEmbedPlaceholder {...props} />;
|
return <MediaEmbedPlaceholder {...props} />;
|
||||||
|
@ -115,7 +133,19 @@ export const MediaEmbedElement = withHOC(
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
) : null}
|
) : (
|
||||||
|
<div className="bg-gray-light/30 h-full min-h-16 w-full overflow-hidden rounded">
|
||||||
|
<iframe
|
||||||
|
className={cn(
|
||||||
|
'absolute top-0 left-0 size-full min-h-16 rounded-sm',
|
||||||
|
focused && selected && 'ring-ring ring-2 ring-offset-2'
|
||||||
|
)}
|
||||||
|
title="embed"
|
||||||
|
src={embed?.url ?? url}
|
||||||
|
allowFullScreen
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<ResizeHandle
|
<ResizeHandle
|
||||||
className={mediaResizeHandleVariants({ direction: 'right' })}
|
className={mediaResizeHandleVariants({ direction: 'right' })}
|
||||||
|
@ -141,8 +171,11 @@ export const MediaEmbedPlaceholder = (props: PlateElementProps<TMediaEmbedElemen
|
||||||
const focused = useFocused();
|
const focused = useFocused();
|
||||||
const editor = useEditorRef();
|
const editor = useEditorRef();
|
||||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
const popoverRef = React.useRef<HTMLDivElement>(null);
|
||||||
|
const anchorRef = React.useRef<HTMLDivElement>(null);
|
||||||
const { openInfoMessage } = useBusterNotifications();
|
const { openInfoMessage } = useBusterNotifications();
|
||||||
const [forceOpen, setForceOpen] = React.useState(false);
|
const [forceOpen, setForceOpen] = React.useState(false);
|
||||||
|
const element = useElement();
|
||||||
|
|
||||||
const isFocused = focused && selected && !readOnly;
|
const isFocused = focused && selected && !readOnly;
|
||||||
|
|
||||||
|
@ -153,6 +186,9 @@ export const MediaEmbedPlaceholder = (props: PlateElementProps<TMediaEmbedElemen
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the current node with the URL
|
||||||
|
editor.tf.setNodes({ url }, { at: editor.api.findPath(props.element) });
|
||||||
|
|
||||||
setForceOpen(false);
|
setForceOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,11 +198,21 @@ export const MediaEmbedPlaceholder = (props: PlateElementProps<TMediaEmbedElemen
|
||||||
}
|
}
|
||||||
}, [isFocused]);
|
}, [isFocused]);
|
||||||
|
|
||||||
|
useClickAway(
|
||||||
|
(e) => {
|
||||||
|
setForceOpen(false);
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
},
|
||||||
|
[popoverRef, anchorRef]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlateElement className="media-embed py-2.5" {...props}>
|
<PlateElement className="media-embed py-2.5" {...props}>
|
||||||
<PopoverBase open={forceOpen} onOpenChange={setForceOpen}>
|
<PopoverBase open={forceOpen}>
|
||||||
<PopoverAnchor>
|
<PopoverAnchor>
|
||||||
<div
|
<div
|
||||||
|
ref={anchorRef}
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-muted hover:bg-primary/10 flex cursor-pointer items-center rounded-sm p-3 pr-9 select-none'
|
'bg-muted hover:bg-primary/10 flex cursor-pointer items-center rounded-sm p-3 pr-9 select-none'
|
||||||
)}
|
)}
|
||||||
|
@ -181,13 +227,12 @@ export const MediaEmbedPlaceholder = (props: PlateElementProps<TMediaEmbedElemen
|
||||||
</PopoverAnchor>
|
</PopoverAnchor>
|
||||||
|
|
||||||
<PopoverContent
|
<PopoverContent
|
||||||
|
ref={popoverRef}
|
||||||
className="flex w-[300px] flex-col px-0 py-2"
|
className="flex w-[300px] flex-col px-0 py-2"
|
||||||
onOpenAutoFocus={(e) => {
|
onOpenAutoFocus={(e) => {
|
||||||
console.log('onOpenAutoFocus', e);
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}}
|
}}
|
||||||
onCloseAutoFocus={(e) => {
|
onCloseAutoFocus={(e) => {
|
||||||
console.log('onCloseAutoFocus', e);
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}}>
|
}}>
|
||||||
<div className="px-3">
|
<div className="px-3">
|
||||||
|
|
Loading…
Reference in New Issue