1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-01-29 11:18:25 +01:00
slate/site/examples/ts/embeds.tsx
Ravi Lamkoti 01dc30b81d
Add Javascript Examples Support (#5722)
* chore: moved all ts files for examples to examples/ts

* add: tsc to eject js and jsx output

* example: add js transpiled examples

* example: update example site to show both js and ts code

* chore: fix yarn lint

* fix(example): getAllExamplesPath
2024-09-26 00:24:11 -07:00

145 lines
3.3 KiB
TypeScript

import React, { useMemo } from 'react'
import {
Transforms,
createEditor,
Element as SlateElement,
Descendant,
} from 'slate'
import {
Slate,
Editable,
withReact,
useSlateStatic,
ReactEditor,
} from 'slate-react'
const EmbedsExample = () => {
const editor = useMemo(() => withEmbeds(withReact(createEditor())), [])
return (
<Slate editor={editor} initialValue={initialValue}>
<Editable
renderElement={props => <Element {...props} />}
placeholder="Enter some text..."
/>
</Slate>
)
}
const withEmbeds = editor => {
const { isVoid } = editor
editor.isVoid = element => (element.type === 'video' ? true : isVoid(element))
return editor
}
const Element = props => {
const { attributes, children, element } = props
switch (element.type) {
case 'video':
return <VideoElement {...props} />
default:
return <p {...attributes}>{children}</p>
}
}
const allowedSchemes = ['http:', 'https:']
const VideoElement = ({ attributes, children, element }) => {
const editor = useSlateStatic()
const { url } = element
const safeUrl = useMemo(() => {
let parsedUrl: URL = null
try {
parsedUrl = new URL(url)
// eslint-disable-next-line no-empty
} catch {}
if (parsedUrl && allowedSchemes.includes(parsedUrl.protocol)) {
return parsedUrl.href
}
return 'about:blank'
}, [url])
return (
<div {...attributes}>
<div contentEditable={false}>
<div
style={{
padding: '75% 0 0 0',
position: 'relative',
}}
>
<iframe
src={`${safeUrl}?title=0&byline=0&portrait=0`}
frameBorder="0"
style={{
position: 'absolute',
top: '0',
left: '0',
width: '100%',
height: '100%',
}}
/>
</div>
<UrlInput
url={url}
onChange={val => {
const path = ReactEditor.findPath(editor, element)
const newProperties: Partial<SlateElement> = {
url: val,
}
Transforms.setNodes<SlateElement>(editor, newProperties, {
at: path,
})
}}
/>
</div>
{children}
</div>
)
}
const UrlInput = ({ url, onChange }) => {
const [value, setValue] = React.useState(url)
return (
<input
value={value}
onClick={e => e.stopPropagation()}
style={{
marginTop: '5px',
boxSizing: 'border-box',
}}
onChange={e => {
const newUrl = e.target.value
setValue(newUrl)
onChange(newUrl)
}}
/>
)
}
const initialValue: Descendant[] = [
{
type: 'paragraph',
children: [
{
text: 'In addition to simple image nodes, you can actually create complex embedded nodes. For example, this one contains an input element that lets you change the video being rendered!',
},
],
},
{
type: 'video',
url: 'https://player.vimeo.com/video/26689853',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [
{
text: 'Try it out! This editor is built to handle Vimeo embeds, but you could handle any type.',
},
],
},
]
export default EmbedsExample