mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-15 11:44:05 +02:00
expose render prop types, refactor default renderers
This commit is contained in:
@@ -7,10 +7,10 @@ import { ReactEditor } from '..'
|
|||||||
import { useEditor } from '../hooks/use-editor'
|
import { useEditor } from '../hooks/use-editor'
|
||||||
import { NODE_TO_INDEX, NODE_TO_PARENT } from '../utils/weak-maps'
|
import { NODE_TO_INDEX, NODE_TO_PARENT } from '../utils/weak-maps'
|
||||||
import {
|
import {
|
||||||
CustomDecorationProps,
|
RenderDecorationProps,
|
||||||
CustomElementProps,
|
RenderElementProps,
|
||||||
CustomMarkProps,
|
RenderMarkProps,
|
||||||
} from './custom'
|
} from './editable'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Children.
|
* Children.
|
||||||
@@ -20,9 +20,9 @@ const Children = (props: {
|
|||||||
decorate: (entry: NodeEntry) => Range[]
|
decorate: (entry: NodeEntry) => Range[]
|
||||||
decorations: Range[]
|
decorations: Range[]
|
||||||
node: Ancestor
|
node: Ancestor
|
||||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||||
renderElement?: (props: CustomElementProps) => JSX.Element
|
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||||
selection: Range | null
|
selection: Range | null
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
|
@@ -1,106 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import { Element, Range, Mark, Text } from 'slate'
|
|
||||||
|
|
||||||
import { useEditor } from '../hooks/use-editor'
|
|
||||||
import { Leaf } from '../utils/leaf'
|
|
||||||
|
|
||||||
export interface CustomDecorationProps {
|
|
||||||
children: any
|
|
||||||
decoration: Range
|
|
||||||
leaf: Leaf
|
|
||||||
text: Text
|
|
||||||
attributes: {
|
|
||||||
'data-slate-decoration': true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default custom decoration renderer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const CustomDecoration = (props: CustomDecorationProps) => {
|
|
||||||
const { attributes, children } = props
|
|
||||||
return <span {...attributes}>{children}</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* `CustomElementProps` are passed to the `renderElement` handler.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface CustomElementProps {
|
|
||||||
children: any
|
|
||||||
element: Element
|
|
||||||
attributes: {
|
|
||||||
'data-slate-inline'?: true
|
|
||||||
'data-slate-node': 'element'
|
|
||||||
'data-slate-void'?: true
|
|
||||||
dir?: 'rtl'
|
|
||||||
ref: any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default element renderer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const CustomElement = (props: CustomElementProps) => {
|
|
||||||
const { attributes, children, element } = props
|
|
||||||
const editor = useEditor()
|
|
||||||
const Tag = editor.isInline(element) ? 'span' : 'div'
|
|
||||||
return (
|
|
||||||
<Tag {...attributes} style={{ position: 'relative' }}>
|
|
||||||
{children}
|
|
||||||
</Tag>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* `CustomMarkProps` are passed to the `renderMark` handler.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface CustomMarkProps {
|
|
||||||
children: any
|
|
||||||
mark: Mark
|
|
||||||
leaf: Leaf
|
|
||||||
text: Text
|
|
||||||
attributes: {
|
|
||||||
'data-slate-mark': true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default custom mark renderer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const CustomMark = (props: CustomMarkProps) => {
|
|
||||||
const { attributes, children } = props
|
|
||||||
return <span {...attributes}>{children}</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A custom decoration for the default placeholder behavior.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const PlaceholderDecoration = (props: CustomDecorationProps) => {
|
|
||||||
const { decoration, attributes, children } = props
|
|
||||||
const { placeholder } = decoration
|
|
||||||
return (
|
|
||||||
<span {...attributes}>
|
|
||||||
<span
|
|
||||||
contentEditable={false}
|
|
||||||
style={{
|
|
||||||
pointerEvents: 'none',
|
|
||||||
display: 'inline-block',
|
|
||||||
verticalAlign: 'text-top',
|
|
||||||
width: '0',
|
|
||||||
maxWidth: '100%',
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
opacity: '0.333',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{placeholder}
|
|
||||||
</span>
|
|
||||||
{children}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
@@ -1,5 +1,5 @@
|
|||||||
import React, { useLayoutEffect, useRef, useMemo, useCallback } from 'react'
|
import React, { useLayoutEffect, useRef, useMemo, useCallback } from 'react'
|
||||||
import { Editor, Element, NodeEntry, Node, Range } from 'slate'
|
import { Editor, Element, NodeEntry, Node, Range, Text, Mark } from 'slate'
|
||||||
import debounce from 'debounce'
|
import debounce from 'debounce'
|
||||||
import scrollIntoView from 'scroll-into-view-if-needed'
|
import scrollIntoView from 'scroll-into-view-if-needed'
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@ import { IS_FIREFOX, IS_SAFARI } from '../utils/environment'
|
|||||||
import { ReactEditor } from '..'
|
import { ReactEditor } from '..'
|
||||||
import { ReadOnlyContext } from '../hooks/use-read-only'
|
import { ReadOnlyContext } from '../hooks/use-read-only'
|
||||||
import { useSlate } from '../hooks/use-slate'
|
import { useSlate } from '../hooks/use-slate'
|
||||||
|
import { Leaf } from '../utils/leaf'
|
||||||
import {
|
import {
|
||||||
DOMElement,
|
DOMElement,
|
||||||
DOMNode,
|
DOMNode,
|
||||||
@@ -26,11 +27,50 @@ import {
|
|||||||
IS_FOCUSED,
|
IS_FOCUSED,
|
||||||
PLACEHOLDER_SYMBOL,
|
PLACEHOLDER_SYMBOL,
|
||||||
} from '../utils/weak-maps'
|
} from '../utils/weak-maps'
|
||||||
import {
|
|
||||||
CustomDecorationProps,
|
/**
|
||||||
CustomElementProps,
|
* `RenderDecorationProps` are passed to the `renderDecoration` handler.
|
||||||
CustomMarkProps,
|
*/
|
||||||
} from './custom'
|
|
||||||
|
export interface RenderDecorationProps {
|
||||||
|
children: any
|
||||||
|
decoration: Range
|
||||||
|
leaf: Leaf
|
||||||
|
text: Text
|
||||||
|
attributes: {
|
||||||
|
'data-slate-decoration': true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `RenderElementProps` are passed to the `renderElement` handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface RenderElementProps {
|
||||||
|
children: any
|
||||||
|
element: Element
|
||||||
|
attributes: {
|
||||||
|
'data-slate-inline'?: true
|
||||||
|
'data-slate-node': 'element'
|
||||||
|
'data-slate-void'?: true
|
||||||
|
dir?: 'rtl'
|
||||||
|
ref: any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `RenderMarkProps` are passed to the `renderMark` handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface RenderMarkProps {
|
||||||
|
children: any
|
||||||
|
mark: Mark
|
||||||
|
leaf: Leaf
|
||||||
|
text: Text
|
||||||
|
attributes: {
|
||||||
|
'data-slate-mark': true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editable.
|
* Editable.
|
||||||
@@ -44,9 +84,9 @@ export const Editable = (
|
|||||||
readOnly?: boolean
|
readOnly?: boolean
|
||||||
role?: string
|
role?: string
|
||||||
style?: React.CSSProperties
|
style?: React.CSSProperties
|
||||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||||
renderElement?: (props: CustomElementProps) => JSX.Element
|
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||||
} & React.TextareaHTMLAttributes<HTMLDivElement>
|
} & React.TextareaHTMLAttributes<HTMLDivElement>
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
|
@@ -14,11 +14,10 @@ import {
|
|||||||
KEY_TO_ELEMENT,
|
KEY_TO_ELEMENT,
|
||||||
} from '../utils/weak-maps'
|
} from '../utils/weak-maps'
|
||||||
import {
|
import {
|
||||||
CustomDecorationProps,
|
RenderDecorationProps,
|
||||||
CustomElement,
|
RenderElementProps,
|
||||||
CustomElementProps,
|
RenderMarkProps,
|
||||||
CustomMarkProps,
|
} from './editable'
|
||||||
} from './custom'
|
|
||||||
import { isRangeListEqual } from '../utils/leaf'
|
import { isRangeListEqual } from '../utils/leaf'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,9 +28,9 @@ const Element = (props: {
|
|||||||
decorate: (entry: NodeEntry) => Range[]
|
decorate: (entry: NodeEntry) => Range[]
|
||||||
decorations: Range[]
|
decorations: Range[]
|
||||||
element: SlateElement
|
element: SlateElement
|
||||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||||
renderElement?: (props: CustomElementProps) => JSX.Element
|
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||||
selection: Range | null
|
selection: Range | null
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
@@ -39,7 +38,7 @@ const Element = (props: {
|
|||||||
decorations,
|
decorations,
|
||||||
element,
|
element,
|
||||||
renderDecoration,
|
renderDecoration,
|
||||||
renderElement = (p: CustomElementProps) => <CustomElement {...p} />,
|
renderElement = (p: RenderElementProps) => <DefaultElement {...p} />,
|
||||||
renderMark,
|
renderMark,
|
||||||
selection,
|
selection,
|
||||||
} = props
|
} = props
|
||||||
@@ -153,4 +152,19 @@ const MemoizedElement = React.memo(Element, (prev, next) => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default element renderer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const DefaultElement = (props: RenderElementProps) => {
|
||||||
|
const { attributes, children, element } = props
|
||||||
|
const editor = useEditor()
|
||||||
|
const Tag = editor.isInline(element) ? 'span' : 'div'
|
||||||
|
return (
|
||||||
|
<Tag {...attributes} style={{ position: 'relative' }}>
|
||||||
|
{children}
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default MemoizedElement
|
export default MemoizedElement
|
||||||
|
@@ -1,15 +1,10 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Text, Element } from 'slate'
|
import { Text, Element } from 'slate'
|
||||||
|
|
||||||
import String from './string'
|
import String from './string'
|
||||||
import {
|
|
||||||
CustomDecoration,
|
|
||||||
CustomDecorationProps,
|
|
||||||
CustomMark,
|
|
||||||
CustomMarkProps,
|
|
||||||
PlaceholderDecoration,
|
|
||||||
} from './custom'
|
|
||||||
import { PLACEHOLDER_SYMBOL } from '../utils/weak-maps'
|
|
||||||
import { Leaf as SlateLeaf } from '../utils/leaf'
|
import { Leaf as SlateLeaf } from '../utils/leaf'
|
||||||
|
import { PLACEHOLDER_SYMBOL } from '../utils/weak-maps'
|
||||||
|
import { RenderDecorationProps, RenderMarkProps } from './editable'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Individual leaves in a text node with unique formatting.
|
* Individual leaves in a text node with unique formatting.
|
||||||
@@ -19,8 +14,8 @@ const Leaf = (props: {
|
|||||||
isLast: boolean
|
isLast: boolean
|
||||||
leaf: SlateLeaf
|
leaf: SlateLeaf
|
||||||
parent: Element
|
parent: Element
|
||||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||||
text: Text
|
text: Text
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
@@ -28,10 +23,10 @@ const Leaf = (props: {
|
|||||||
isLast,
|
isLast,
|
||||||
text,
|
text,
|
||||||
parent,
|
parent,
|
||||||
renderDecoration = (props: CustomDecorationProps) => (
|
renderDecoration = (props: RenderDecorationProps) => (
|
||||||
<CustomDecoration {...props} />
|
<DefaultDecoration {...props} />
|
||||||
),
|
),
|
||||||
renderMark = (props: CustomMarkProps) => <CustomMark {...props} />,
|
renderMark = (props: RenderMarkProps) => <DefaultMark {...props} />,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
let children = (
|
let children = (
|
||||||
@@ -95,4 +90,50 @@ const MemoizedLeaf = React.memo(Leaf, (prev, next) => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default custom decoration renderer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const DefaultDecoration = (props: RenderDecorationProps) => {
|
||||||
|
const { attributes, children } = props
|
||||||
|
return <span {...attributes}>{children}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default custom mark renderer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const DefaultMark = (props: RenderMarkProps) => {
|
||||||
|
const { attributes, children } = props
|
||||||
|
return <span {...attributes}>{children}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom decoration for the default placeholder behavior.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const PlaceholderDecoration = (props: RenderDecorationProps) => {
|
||||||
|
const { decoration, attributes, children } = props
|
||||||
|
const { placeholder } = decoration
|
||||||
|
return (
|
||||||
|
<span {...attributes}>
|
||||||
|
<span
|
||||||
|
contentEditable={false}
|
||||||
|
style={{
|
||||||
|
pointerEvents: 'none',
|
||||||
|
display: 'inline-block',
|
||||||
|
verticalAlign: 'text-top',
|
||||||
|
width: '0',
|
||||||
|
maxWidth: '100%',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
opacity: '0.333',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{placeholder}
|
||||||
|
</span>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default MemoizedLeaf
|
export default MemoizedLeaf
|
||||||
|
@@ -4,12 +4,12 @@ import { Range, Element, Text as SlateText } from 'slate'
|
|||||||
import Leaf from './leaf'
|
import Leaf from './leaf'
|
||||||
import { Leaf as SlateLeaf } from '../utils/leaf'
|
import { Leaf as SlateLeaf } from '../utils/leaf'
|
||||||
import { ReactEditor, useEditor } from '..'
|
import { ReactEditor, useEditor } from '..'
|
||||||
|
import { RenderDecorationProps, RenderMarkProps } from './editable'
|
||||||
import {
|
import {
|
||||||
KEY_TO_ELEMENT,
|
KEY_TO_ELEMENT,
|
||||||
NODE_TO_ELEMENT,
|
NODE_TO_ELEMENT,
|
||||||
ELEMENT_TO_NODE,
|
ELEMENT_TO_NODE,
|
||||||
} from '../utils/weak-maps'
|
} from '../utils/weak-maps'
|
||||||
import { CustomDecorationProps, CustomMarkProps } from './custom'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text.
|
* Text.
|
||||||
@@ -19,8 +19,8 @@ const Text = (props: {
|
|||||||
decorations: Range[]
|
decorations: Range[]
|
||||||
isLast: boolean
|
isLast: boolean
|
||||||
parent: Element
|
parent: Element
|
||||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||||
text: SlateText
|
text: SlateText
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
export * from './components/editable'
|
export * from './components/editable'
|
||||||
|
export { DefaultElement } from './components/element'
|
||||||
|
export { DefaultMark, DefaultDecoration } from './components/leaf'
|
||||||
export * from './hooks/use-editor'
|
export * from './hooks/use-editor'
|
||||||
export * from './hooks/use-focused'
|
export * from './hooks/use-focused'
|
||||||
export * from './hooks/use-read-only'
|
export * from './hooks/use-read-only'
|
||||||
|
Reference in New Issue
Block a user