mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-13 18:53:59 +02:00
* mvp implementation for working with non-global window instances * remove unused element renderer * fix typo in comment * fix wrong example reference * Add @babel/helper-call-delegate to fix build error Co-authored-by: Lukas Buenger <lukasbuenger@gmail.com>
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.7.4",
|
"@babel/cli": "^7.7.4",
|
||||||
"@babel/core": "^7.7.4",
|
"@babel/core": "^7.7.4",
|
||||||
|
"@babel/helper-call-delegate": "^7.7.4",
|
||||||
"@babel/plugin-external-helpers": "^7.7.4",
|
"@babel/plugin-external-helpers": "^7.7.4",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.7.4",
|
"@babel/plugin-proposal-class-properties": "^7.7.4",
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.7.4",
|
"@babel/plugin-transform-modules-commonjs": "^7.7.4",
|
||||||
|
@@ -29,6 +29,7 @@ import {
|
|||||||
DOMElement,
|
DOMElement,
|
||||||
DOMNode,
|
DOMNode,
|
||||||
DOMRange,
|
DOMRange,
|
||||||
|
getDefaultView,
|
||||||
isDOMElement,
|
isDOMElement,
|
||||||
isDOMNode,
|
isDOMNode,
|
||||||
isDOMText,
|
isDOMText,
|
||||||
@@ -42,6 +43,7 @@ import {
|
|||||||
NODE_TO_ELEMENT,
|
NODE_TO_ELEMENT,
|
||||||
IS_FOCUSED,
|
IS_FOCUSED,
|
||||||
PLACEHOLDER_SYMBOL,
|
PLACEHOLDER_SYMBOL,
|
||||||
|
EDITOR_TO_WINDOW,
|
||||||
} from '../utils/weak-maps'
|
} from '../utils/weak-maps'
|
||||||
|
|
||||||
// COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
|
// COMPAT: Firefox/Edge Legacy don't support the `beforeinput` event
|
||||||
@@ -132,7 +134,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
|
|
||||||
// Update element-related weak maps with the DOM element ref.
|
// Update element-related weak maps with the DOM element ref.
|
||||||
useIsomorphicLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
if (ref.current) {
|
let window
|
||||||
|
if (ref.current && (window = getDefaultView(ref.current))) {
|
||||||
|
EDITOR_TO_WINDOW.set(editor, window)
|
||||||
EDITOR_TO_ELEMENT.set(editor, ref.current)
|
EDITOR_TO_ELEMENT.set(editor, ref.current)
|
||||||
NODE_TO_ELEMENT.set(editor, ref.current)
|
NODE_TO_ELEMENT.set(editor, ref.current)
|
||||||
ELEMENT_TO_NODE.set(ref.current, editor)
|
ELEMENT_TO_NODE.set(ref.current, editor)
|
||||||
@@ -144,6 +148,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
// Whenever the editor updates, make sure the DOM selection state is in sync.
|
// Whenever the editor updates, make sure the DOM selection state is in sync.
|
||||||
useIsomorphicLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
const { selection } = editor
|
const { selection } = editor
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
const domSelection = window.getSelection()
|
const domSelection = window.getSelection()
|
||||||
|
|
||||||
if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) {
|
if (state.isComposing || !domSelection || !ReactEditor.isFocused(editor)) {
|
||||||
@@ -354,8 +359,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
case 'insertFromYank':
|
case 'insertFromYank':
|
||||||
case 'insertReplacementText':
|
case 'insertReplacementText':
|
||||||
case 'insertText': {
|
case 'insertText': {
|
||||||
if (data instanceof DataTransfer) {
|
const window = ReactEditor.getWindow(editor)
|
||||||
ReactEditor.insertData(editor, data)
|
if (data instanceof window.DataTransfer) {
|
||||||
|
ReactEditor.insertData(editor, data as DataTransfer)
|
||||||
} else if (typeof data === 'string') {
|
} else if (typeof data === 'string') {
|
||||||
Editor.insertText(editor, data)
|
Editor.insertText(editor, data)
|
||||||
}
|
}
|
||||||
@@ -394,6 +400,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
const onDOMSelectionChange = useCallback(
|
const onDOMSelectionChange = useCallback(
|
||||||
throttle(() => {
|
throttle(() => {
|
||||||
if (!readOnly && !state.isComposing && !state.isUpdatingSelection) {
|
if (!readOnly && !state.isComposing && !state.isUpdatingSelection) {
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
const { activeElement } = window.document
|
const { activeElement } = window.document
|
||||||
const el = ReactEditor.toDOMNode(editor, editor)
|
const el = ReactEditor.toDOMNode(editor, editor)
|
||||||
const domSelection = window.getSelection()
|
const domSelection = window.getSelection()
|
||||||
@@ -436,6 +443,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
// fire for any change to the selection inside the editor. (2019/11/04)
|
// fire for any change to the selection inside the editor. (2019/11/04)
|
||||||
// https://github.com/facebook/react/issues/5785
|
// https://github.com/facebook/react/issues/5785
|
||||||
useIsomorphicLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
window.document.addEventListener('selectionchange', onDOMSelectionChange)
|
window.document.addEventListener('selectionchange', onDOMSelectionChange)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -527,6 +535,8 @@ export const Editable = (props: EditableProps) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
|
|
||||||
// COMPAT: If the current `activeElement` is still the previous
|
// COMPAT: If the current `activeElement` is still the previous
|
||||||
// one, this is due to the window being blurred when the tab
|
// one, this is due to the window being blurred when the tab
|
||||||
// itself becomes unfocused, so we want to abort early to allow to
|
// itself becomes unfocused, so we want to abort early to allow to
|
||||||
@@ -735,6 +745,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
!isEventHandled(event, attributes.onFocus)
|
!isEventHandled(event, attributes.onFocus)
|
||||||
) {
|
) {
|
||||||
const el = ReactEditor.toDOMNode(editor, editor)
|
const el = ReactEditor.toDOMNode(editor, editor)
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
state.latestElement = window.document.activeElement
|
state.latestElement = window.document.activeElement
|
||||||
|
|
||||||
// COMPAT: If the editor has nested editable elements, the focus
|
// COMPAT: If the editor has nested editable elements, the focus
|
||||||
|
@@ -10,6 +10,7 @@ import {
|
|||||||
NODE_TO_INDEX,
|
NODE_TO_INDEX,
|
||||||
NODE_TO_KEY,
|
NODE_TO_KEY,
|
||||||
NODE_TO_PARENT,
|
NODE_TO_PARENT,
|
||||||
|
EDITOR_TO_WINDOW,
|
||||||
} from '../utils/weak-maps'
|
} from '../utils/weak-maps'
|
||||||
import {
|
import {
|
||||||
DOMElement,
|
DOMElement,
|
||||||
@@ -20,6 +21,7 @@ import {
|
|||||||
DOMStaticRange,
|
DOMStaticRange,
|
||||||
isDOMElement,
|
isDOMElement,
|
||||||
normalizeDOMPoint,
|
normalizeDOMPoint,
|
||||||
|
isDOMSelection,
|
||||||
} from '../utils/dom'
|
} from '../utils/dom'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,6 +34,18 @@ export interface ReactEditor extends Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ReactEditor = {
|
export const ReactEditor = {
|
||||||
|
/**
|
||||||
|
* Return the host window of the current editor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
getWindow(editor: ReactEditor): Window {
|
||||||
|
const window = EDITOR_TO_WINDOW.get(editor)
|
||||||
|
if (!window) {
|
||||||
|
throw new Error('Unable to find a host window element for this editor')
|
||||||
|
}
|
||||||
|
return window
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a key for a Slate node.
|
* Find a key for a Slate node.
|
||||||
*/
|
*/
|
||||||
@@ -104,7 +118,7 @@ export const ReactEditor = {
|
|||||||
blur(editor: ReactEditor): void {
|
blur(editor: ReactEditor): void {
|
||||||
const el = ReactEditor.toDOMNode(editor, editor)
|
const el = ReactEditor.toDOMNode(editor, editor)
|
||||||
IS_FOCUSED.set(editor, false)
|
IS_FOCUSED.set(editor, false)
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
if (window.document.activeElement === el) {
|
if (window.document.activeElement === el) {
|
||||||
el.blur()
|
el.blur()
|
||||||
}
|
}
|
||||||
@@ -118,6 +132,7 @@ export const ReactEditor = {
|
|||||||
const el = ReactEditor.toDOMNode(editor, editor)
|
const el = ReactEditor.toDOMNode(editor, editor)
|
||||||
IS_FOCUSED.set(editor, true)
|
IS_FOCUSED.set(editor, true)
|
||||||
|
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
if (window.document.activeElement !== el) {
|
if (window.document.activeElement !== el) {
|
||||||
el.focus({ preventScroll: true })
|
el.focus({ preventScroll: true })
|
||||||
}
|
}
|
||||||
@@ -129,6 +144,7 @@ export const ReactEditor = {
|
|||||||
|
|
||||||
deselect(editor: ReactEditor): void {
|
deselect(editor: ReactEditor): void {
|
||||||
const { selection } = editor
|
const { selection } = editor
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
const domSelection = window.getSelection()
|
const domSelection = window.getSelection()
|
||||||
|
|
||||||
if (domSelection && domSelection.rangeCount > 0) {
|
if (domSelection && domSelection.rangeCount > 0) {
|
||||||
@@ -284,6 +300,7 @@ export const ReactEditor = {
|
|||||||
? domAnchor
|
? domAnchor
|
||||||
: ReactEditor.toDOMPoint(editor, focus)
|
: ReactEditor.toDOMPoint(editor, focus)
|
||||||
|
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
const domRange = window.document.createRange()
|
const domRange = window.document.createRange()
|
||||||
const [startNode, startOffset] = isBackward ? domFocus : domAnchor
|
const [startNode, startOffset] = isBackward ? domFocus : domAnchor
|
||||||
const [endNode, endOffset] = isBackward ? domAnchor : domFocus
|
const [endNode, endOffset] = isBackward ? domAnchor : domFocus
|
||||||
@@ -410,6 +427,7 @@ export const ReactEditor = {
|
|||||||
// can determine what the offset relative to the text node is.
|
// can determine what the offset relative to the text node is.
|
||||||
if (leafNode) {
|
if (leafNode) {
|
||||||
textNode = leafNode.closest('[data-slate-node="text"]')!
|
textNode = leafNode.closest('[data-slate-node="text"]')!
|
||||||
|
const window = ReactEditor.getWindow(editor)
|
||||||
const range = window.document.createRange()
|
const range = window.document.createRange()
|
||||||
range.setStart(textNode, 0)
|
range.setStart(textNode, 0)
|
||||||
range.setEnd(nearestNode, nearestOffset)
|
range.setEnd(nearestNode, nearestOffset)
|
||||||
@@ -476,8 +494,7 @@ export const ReactEditor = {
|
|||||||
editor: ReactEditor,
|
editor: ReactEditor,
|
||||||
domRange: DOMRange | DOMStaticRange | DOMSelection
|
domRange: DOMRange | DOMStaticRange | DOMSelection
|
||||||
): Range {
|
): Range {
|
||||||
const el =
|
const el = isDOMSelection(domRange)
|
||||||
domRange instanceof Selection
|
|
||||||
? domRange.anchorNode
|
? domRange.anchorNode
|
||||||
: domRange.startContainer
|
: domRange.startContainer
|
||||||
let anchorNode
|
let anchorNode
|
||||||
@@ -487,7 +504,7 @@ export const ReactEditor = {
|
|||||||
let isCollapsed
|
let isCollapsed
|
||||||
|
|
||||||
if (el) {
|
if (el) {
|
||||||
if (domRange instanceof Selection) {
|
if (isDOMSelection(domRange)) {
|
||||||
anchorNode = domRange.anchorNode
|
anchorNode = domRange.anchorNode
|
||||||
anchorOffset = domRange.anchorOffset
|
anchorOffset = domRange.anchorOffset
|
||||||
focusNode = domRange.focusNode
|
focusNode = domRange.focusNode
|
||||||
|
@@ -23,8 +23,26 @@ export {
|
|||||||
DOMStaticRange,
|
DOMStaticRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
Selection: typeof Selection['constructor']
|
||||||
|
DataTransfer: typeof DataTransfer['constructor']
|
||||||
|
Node: typeof Node['constructor']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type DOMPoint = [Node, number]
|
export type DOMPoint = [Node, number]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the host window of a DOM node
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const getDefaultView = (value: any): Window | null => {
|
||||||
|
return (
|
||||||
|
(value && value.ownerDocument && value.ownerDocument.defaultView) || null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a DOM node is a comment node.
|
* Check if a DOM node is a comment node.
|
||||||
*/
|
*/
|
||||||
@@ -46,7 +64,17 @@ export const isDOMElement = (value: any): value is DOMElement => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const isDOMNode = (value: any): value is DOMNode => {
|
export const isDOMNode = (value: any): value is DOMNode => {
|
||||||
return value instanceof Node
|
const window = getDefaultView(value)
|
||||||
|
return !!window && value instanceof window.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a value is a DOM selection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const isDOMSelection = (value: any): value is DOMSelection => {
|
||||||
|
const window = value && value.anchorNode && getDefaultView(value.anchorNode)
|
||||||
|
return !!window && value instanceof window.Selection
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -14,7 +14,7 @@ export const NODE_TO_PARENT: WeakMap<Node, Ancestor> = new WeakMap()
|
|||||||
* Weak maps that allow us to go between Slate nodes and DOM nodes. These
|
* Weak maps that allow us to go between Slate nodes and DOM nodes. These
|
||||||
* are used to resolve DOM event-related logic into Slate actions.
|
* are used to resolve DOM event-related logic into Slate actions.
|
||||||
*/
|
*/
|
||||||
|
export const EDITOR_TO_WINDOW: WeakMap<Editor, Window> = new WeakMap()
|
||||||
export const EDITOR_TO_ELEMENT: WeakMap<Editor, HTMLElement> = new WeakMap()
|
export const EDITOR_TO_ELEMENT: WeakMap<Editor, HTMLElement> = new WeakMap()
|
||||||
export const EDITOR_TO_PLACEHOLDER: WeakMap<Editor, string> = new WeakMap()
|
export const EDITOR_TO_PLACEHOLDER: WeakMap<Editor, string> = new WeakMap()
|
||||||
export const ELEMENT_TO_NODE: WeakMap<HTMLElement, Node> = new WeakMap()
|
export const ELEMENT_TO_NODE: WeakMap<HTMLElement, Node> = new WeakMap()
|
||||||
|
158
site/examples/iframe.js
Normal file
158
site/examples/iframe.js
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import React, { useCallback, useMemo, useState } from 'react'
|
||||||
|
import { createPortal } from 'react-dom'
|
||||||
|
import isHotkey from 'is-hotkey'
|
||||||
|
import { Editable, withReact, useSlate, Slate, ReactEditor } from 'slate-react'
|
||||||
|
import { Editor, createEditor } from 'slate'
|
||||||
|
import { withHistory } from 'slate-history'
|
||||||
|
|
||||||
|
import { Button, Icon, Toolbar } from '../components'
|
||||||
|
|
||||||
|
const HOTKEYS = {
|
||||||
|
'mod+b': 'bold',
|
||||||
|
'mod+i': 'italic',
|
||||||
|
'mod+u': 'underline',
|
||||||
|
'mod+`': 'code',
|
||||||
|
}
|
||||||
|
|
||||||
|
const IFrameExample = () => {
|
||||||
|
const [value, setValue] = useState(initialValue)
|
||||||
|
const renderElement = useCallback(
|
||||||
|
({ attributes, children }) => <p {...attributes}>{children}</p>,
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||||
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
|
|
||||||
|
const handleBlur = useCallback(() => ReactEditor.deselect(editor), [editor])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||||
|
<Toolbar>
|
||||||
|
<MarkButton format="bold" icon="format_bold" />
|
||||||
|
<MarkButton format="italic" icon="format_italic" />
|
||||||
|
<MarkButton format="underline" icon="format_underlined" />
|
||||||
|
<MarkButton format="code" icon="code" />
|
||||||
|
</Toolbar>
|
||||||
|
<IFrame onBlur={handleBlur}>
|
||||||
|
<Editable
|
||||||
|
renderElement={renderElement}
|
||||||
|
renderLeaf={renderLeaf}
|
||||||
|
placeholder="Enter some rich text…"
|
||||||
|
spellCheck
|
||||||
|
autoFocus
|
||||||
|
onKeyDown={event => {
|
||||||
|
for (const hotkey in HOTKEYS) {
|
||||||
|
if (isHotkey(hotkey, event)) {
|
||||||
|
event.preventDefault()
|
||||||
|
const mark = HOTKEYS[hotkey]
|
||||||
|
toggleMark(editor, mark)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IFrame>
|
||||||
|
</Slate>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleMark = (editor, format) => {
|
||||||
|
const isActive = isMarkActive(editor, format)
|
||||||
|
if (isActive) {
|
||||||
|
Editor.removeMark(editor, format)
|
||||||
|
} else {
|
||||||
|
Editor.addMark(editor, format, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMarkActive = (editor, format) => {
|
||||||
|
const marks = Editor.marks(editor)
|
||||||
|
return marks ? marks[format] === true : false
|
||||||
|
}
|
||||||
|
|
||||||
|
const Leaf = ({ attributes, children, leaf }) => {
|
||||||
|
if (leaf.bold) {
|
||||||
|
children = <strong>{children}</strong>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leaf.code) {
|
||||||
|
children = <code>{children}</code>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leaf.italic) {
|
||||||
|
children = <em>{children}</em>
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leaf.underline) {
|
||||||
|
children = <u>{children}</u>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <span {...attributes}>{children}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
const MarkButton = ({ format, icon }) => {
|
||||||
|
const editor = useSlate()
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
active={isMarkActive(editor, format)}
|
||||||
|
onMouseDown={event => {
|
||||||
|
event.preventDefault()
|
||||||
|
toggleMark(editor, format)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon>{icon}</Icon>
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const IFrame = ({ children, ...props }) => {
|
||||||
|
const [contentRef, setContentRef] = useState(null)
|
||||||
|
const mountNode =
|
||||||
|
contentRef &&
|
||||||
|
contentRef.contentWindow &&
|
||||||
|
contentRef.contentWindow.document.body
|
||||||
|
return (
|
||||||
|
<iframe {...props} ref={setContentRef}>
|
||||||
|
{mountNode && createPortal(React.Children.only(children), mountNode)}
|
||||||
|
</iframe>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'In this example, the document gets rendered into a controlled ',
|
||||||
|
},
|
||||||
|
{ text: '<iframe>', code: true },
|
||||||
|
{
|
||||||
|
text: '. This is ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'particularly',
|
||||||
|
italic: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text:
|
||||||
|
' useful, when you need to separate the styles for your editor contents from the ones addressing your UI.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'This also the only reliable method to preview any ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'media queries',
|
||||||
|
bold: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: ' in your CSS.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export default IFrameExample
|
@@ -25,6 +25,7 @@ import RichText from '../../examples/richtext'
|
|||||||
import SearchHighlighting from '../../examples/search-highlighting'
|
import SearchHighlighting from '../../examples/search-highlighting'
|
||||||
import CodeHighlighting from '../../examples/code-highlighting'
|
import CodeHighlighting from '../../examples/code-highlighting'
|
||||||
import Tables from '../../examples/tables'
|
import Tables from '../../examples/tables'
|
||||||
|
import IFrames from '../../examples/iframe'
|
||||||
|
|
||||||
// node
|
// node
|
||||||
import { getAllExamples } from '../api'
|
import { getAllExamples } from '../api'
|
||||||
@@ -48,6 +49,7 @@ const EXAMPLES = [
|
|||||||
['Search Highlighting', SearchHighlighting, 'search-highlighting'],
|
['Search Highlighting', SearchHighlighting, 'search-highlighting'],
|
||||||
['Code Highlighting', CodeHighlighting, 'code-highlighting'],
|
['Code Highlighting', CodeHighlighting, 'code-highlighting'],
|
||||||
['Tables', Tables, 'tables'],
|
['Tables', Tables, 'tables'],
|
||||||
|
['Rendering in iframes', IFrames, 'iframe'],
|
||||||
]
|
]
|
||||||
|
|
||||||
const Header = props => (
|
const Header = props => (
|
||||||
|
@@ -70,6 +70,11 @@ input:focus {
|
|||||||
border-color: blue;
|
border-color: blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
[data-slate-editor] > * + * {
|
[data-slate-editor] > * + * {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
}
|
}
|
||||||
|
29
yarn.lock
29
yarn.lock
@@ -191,6 +191,14 @@
|
|||||||
"@babel/helper-annotate-as-pure" "^7.10.4"
|
"@babel/helper-annotate-as-pure" "^7.10.4"
|
||||||
"@babel/types" "^7.10.4"
|
"@babel/types" "^7.10.4"
|
||||||
|
|
||||||
|
"@babel/helper-call-delegate@^7.7.4":
|
||||||
|
version "7.12.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.12.13.tgz#119ef367451f90bed006c685816ba60fc33fee78"
|
||||||
|
integrity sha512-K1kF0RXK/GpdS9OZDlBllG0+RQQtyzG/TC+nk0VkrUry4l4Xh2T7HdDsDOVlXQY/KcqvE/JQ84pKjKucdrg3FQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-hoist-variables" "^7.12.13"
|
||||||
|
"@babel/types" "^7.12.13"
|
||||||
|
|
||||||
"@babel/helper-compilation-targets@^7.10.4", "@babel/helper-compilation-targets@^7.9.6":
|
"@babel/helper-compilation-targets@^7.10.4", "@babel/helper-compilation-targets@^7.9.6":
|
||||||
version "7.10.4"
|
version "7.10.4"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2"
|
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2"
|
||||||
@@ -263,6 +271,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.10.4"
|
"@babel/types" "^7.10.4"
|
||||||
|
|
||||||
|
"@babel/helper-hoist-variables@^7.12.13":
|
||||||
|
version "7.12.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.12.13.tgz#13aba58b7480b502362316ea02f52cca0e9796cd"
|
||||||
|
integrity sha512-KSC5XSj5HreRhYQtZ3cnSnQwDzgnbdUDEFsxkN0m6Q3WrCRt72xrnZ8+h+pX7YxM7hr87zIO3a/v5p/H3TrnVw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.12.13"
|
||||||
|
|
||||||
"@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5":
|
"@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5":
|
||||||
version "7.11.0"
|
version "7.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df"
|
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df"
|
||||||
@@ -357,6 +372,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
|
||||||
integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
|
integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
|
||||||
|
|
||||||
|
"@babel/helper-validator-identifier@^7.12.11":
|
||||||
|
version "7.12.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
|
||||||
|
integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
|
||||||
|
|
||||||
"@babel/helper-wrap-function@^7.10.4":
|
"@babel/helper-wrap-function@^7.10.4":
|
||||||
version "7.10.4"
|
version "7.10.4"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87"
|
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87"
|
||||||
@@ -1275,6 +1295,15 @@
|
|||||||
lodash "^4.17.19"
|
lodash "^4.17.19"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
|
"@babel/types@^7.12.13":
|
||||||
|
version "7.12.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.13.tgz#8be1aa8f2c876da11a9cf650c0ecf656913ad611"
|
||||||
|
integrity sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-validator-identifier" "^7.12.11"
|
||||||
|
lodash "^4.17.19"
|
||||||
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@emotion/cache@^10.0.27":
|
"@emotion/cache@^10.0.27":
|
||||||
version "10.0.29"
|
version "10.0.29"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
|
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
|
||||||
|
Reference in New Issue
Block a user