mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-15 03:33:59 +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 { NODE_TO_INDEX, NODE_TO_PARENT } from '../utils/weak-maps'
|
||||
import {
|
||||
CustomDecorationProps,
|
||||
CustomElementProps,
|
||||
CustomMarkProps,
|
||||
} from './custom'
|
||||
RenderDecorationProps,
|
||||
RenderElementProps,
|
||||
RenderMarkProps,
|
||||
} from './editable'
|
||||
|
||||
/**
|
||||
* Children.
|
||||
@@ -20,9 +20,9 @@ const Children = (props: {
|
||||
decorate: (entry: NodeEntry) => Range[]
|
||||
decorations: Range[]
|
||||
node: Ancestor
|
||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
||||
renderElement?: (props: CustomElementProps) => JSX.Element
|
||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
||||
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||
selection: Range | null
|
||||
}) => {
|
||||
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 { Editor, Element, NodeEntry, Node, Range } from 'slate'
|
||||
import { Editor, Element, NodeEntry, Node, Range, Text, Mark } from 'slate'
|
||||
import debounce from 'debounce'
|
||||
import scrollIntoView from 'scroll-into-view-if-needed'
|
||||
|
||||
@@ -9,6 +9,7 @@ import { IS_FIREFOX, IS_SAFARI } from '../utils/environment'
|
||||
import { ReactEditor } from '..'
|
||||
import { ReadOnlyContext } from '../hooks/use-read-only'
|
||||
import { useSlate } from '../hooks/use-slate'
|
||||
import { Leaf } from '../utils/leaf'
|
||||
import {
|
||||
DOMElement,
|
||||
DOMNode,
|
||||
@@ -26,11 +27,50 @@ import {
|
||||
IS_FOCUSED,
|
||||
PLACEHOLDER_SYMBOL,
|
||||
} from '../utils/weak-maps'
|
||||
import {
|
||||
CustomDecorationProps,
|
||||
CustomElementProps,
|
||||
CustomMarkProps,
|
||||
} from './custom'
|
||||
|
||||
/**
|
||||
* `RenderDecorationProps` are passed to the `renderDecoration` handler.
|
||||
*/
|
||||
|
||||
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.
|
||||
@@ -44,9 +84,9 @@ export const Editable = (
|
||||
readOnly?: boolean
|
||||
role?: string
|
||||
style?: React.CSSProperties
|
||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
||||
renderElement?: (props: CustomElementProps) => JSX.Element
|
||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
||||
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||
} & React.TextareaHTMLAttributes<HTMLDivElement>
|
||||
) => {
|
||||
const {
|
||||
|
@@ -14,11 +14,10 @@ import {
|
||||
KEY_TO_ELEMENT,
|
||||
} from '../utils/weak-maps'
|
||||
import {
|
||||
CustomDecorationProps,
|
||||
CustomElement,
|
||||
CustomElementProps,
|
||||
CustomMarkProps,
|
||||
} from './custom'
|
||||
RenderDecorationProps,
|
||||
RenderElementProps,
|
||||
RenderMarkProps,
|
||||
} from './editable'
|
||||
import { isRangeListEqual } from '../utils/leaf'
|
||||
|
||||
/**
|
||||
@@ -29,9 +28,9 @@ const Element = (props: {
|
||||
decorate: (entry: NodeEntry) => Range[]
|
||||
decorations: Range[]
|
||||
element: SlateElement
|
||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
||||
renderElement?: (props: CustomElementProps) => JSX.Element
|
||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
||||
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||
selection: Range | null
|
||||
}) => {
|
||||
const {
|
||||
@@ -39,7 +38,7 @@ const Element = (props: {
|
||||
decorations,
|
||||
element,
|
||||
renderDecoration,
|
||||
renderElement = (p: CustomElementProps) => <CustomElement {...p} />,
|
||||
renderElement = (p: RenderElementProps) => <DefaultElement {...p} />,
|
||||
renderMark,
|
||||
selection,
|
||||
} = 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
|
||||
|
@@ -1,15 +1,10 @@
|
||||
import React from 'react'
|
||||
import { Text, Element } from 'slate'
|
||||
|
||||
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 { PLACEHOLDER_SYMBOL } from '../utils/weak-maps'
|
||||
import { RenderDecorationProps, RenderMarkProps } from './editable'
|
||||
|
||||
/**
|
||||
* Individual leaves in a text node with unique formatting.
|
||||
@@ -19,8 +14,8 @@ const Leaf = (props: {
|
||||
isLast: boolean
|
||||
leaf: SlateLeaf
|
||||
parent: Element
|
||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
||||
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||
text: Text
|
||||
}) => {
|
||||
const {
|
||||
@@ -28,10 +23,10 @@ const Leaf = (props: {
|
||||
isLast,
|
||||
text,
|
||||
parent,
|
||||
renderDecoration = (props: CustomDecorationProps) => (
|
||||
<CustomDecoration {...props} />
|
||||
renderDecoration = (props: RenderDecorationProps) => (
|
||||
<DefaultDecoration {...props} />
|
||||
),
|
||||
renderMark = (props: CustomMarkProps) => <CustomMark {...props} />,
|
||||
renderMark = (props: RenderMarkProps) => <DefaultMark {...props} />,
|
||||
} = props
|
||||
|
||||
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
|
||||
|
@@ -4,12 +4,12 @@ import { Range, Element, Text as SlateText } from 'slate'
|
||||
import Leaf from './leaf'
|
||||
import { Leaf as SlateLeaf } from '../utils/leaf'
|
||||
import { ReactEditor, useEditor } from '..'
|
||||
import { RenderDecorationProps, RenderMarkProps } from './editable'
|
||||
import {
|
||||
KEY_TO_ELEMENT,
|
||||
NODE_TO_ELEMENT,
|
||||
ELEMENT_TO_NODE,
|
||||
} from '../utils/weak-maps'
|
||||
import { CustomDecorationProps, CustomMarkProps } from './custom'
|
||||
|
||||
/**
|
||||
* Text.
|
||||
@@ -19,8 +19,8 @@ const Text = (props: {
|
||||
decorations: Range[]
|
||||
isLast: boolean
|
||||
parent: Element
|
||||
renderDecoration?: (props: CustomDecorationProps) => JSX.Element
|
||||
renderMark?: (props: CustomMarkProps) => JSX.Element
|
||||
renderDecoration?: (props: RenderDecorationProps) => JSX.Element
|
||||
renderMark?: (props: RenderMarkProps) => JSX.Element
|
||||
text: SlateText
|
||||
}) => {
|
||||
const {
|
||||
|
@@ -1,4 +1,6 @@
|
||||
export * from './components/editable'
|
||||
export { DefaultElement } from './components/element'
|
||||
export { DefaultMark, DefaultDecoration } from './components/leaf'
|
||||
export * from './hooks/use-editor'
|
||||
export * from './hooks/use-focused'
|
||||
export * from './hooks/use-read-only'
|
||||
|
Reference in New Issue
Block a user