mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-16 12:14:14 +02:00
Add renderText
and leafPosition
(#5850)
* feat * revert * revert * docs * test * refactor * test * revert * refactor * doc * docs * refactor * docs * test * docs * docs * docs * refactor
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
||||
Text,
|
||||
Transforms,
|
||||
DecoratedRange,
|
||||
LeafPosition,
|
||||
} from 'slate'
|
||||
import { useAndroidInputManager } from '../hooks/android-input-manager/use-android-input-manager'
|
||||
import useChildren from '../hooks/use-children'
|
||||
@@ -105,11 +106,31 @@ export interface RenderElementProps {
|
||||
|
||||
export interface RenderLeafProps {
|
||||
children: any
|
||||
/**
|
||||
* The leaf node with any applied decorations.
|
||||
* If no decorations are applied, it will be identical to the `text` property.
|
||||
*/
|
||||
leaf: Text
|
||||
text: Text
|
||||
attributes: {
|
||||
'data-slate-leaf': true
|
||||
}
|
||||
/**
|
||||
* The position of the leaf within the Text node, only present when the text node is split by decorations.
|
||||
*/
|
||||
leafPosition?: LeafPosition
|
||||
}
|
||||
|
||||
/**
|
||||
* `RenderTextProps` are passed to the `renderText` handler.
|
||||
*/
|
||||
export interface RenderTextProps {
|
||||
text: Text
|
||||
children: any
|
||||
attributes: {
|
||||
'data-slate-node': 'text'
|
||||
ref: any
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,6 +146,7 @@ export type EditableProps = {
|
||||
style?: React.CSSProperties
|
||||
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||
renderLeaf?: (props: RenderLeafProps) => JSX.Element
|
||||
renderText?: (props: RenderTextProps) => JSX.Element
|
||||
renderPlaceholder?: (props: RenderPlaceholderProps) => JSX.Element
|
||||
scrollSelectionIntoView?: (editor: ReactEditor, domRange: DOMRange) => void
|
||||
as?: React.ElementType
|
||||
@@ -149,6 +171,7 @@ export const Editable = forwardRef(
|
||||
readOnly = false,
|
||||
renderElement,
|
||||
renderLeaf,
|
||||
renderText,
|
||||
renderPlaceholder = defaultRenderPlaceholder,
|
||||
scrollSelectionIntoView = defaultScrollSelectionIntoView,
|
||||
style: userStyle = {},
|
||||
@@ -1831,6 +1854,7 @@ export const Editable = forwardRef(
|
||||
renderElement={renderElement}
|
||||
renderPlaceholder={renderPlaceholder}
|
||||
renderLeaf={renderLeaf}
|
||||
renderText={renderText}
|
||||
selection={editor.selection}
|
||||
/>
|
||||
</Component>
|
||||
|
@@ -22,6 +22,7 @@ import {
|
||||
RenderElementProps,
|
||||
RenderLeafProps,
|
||||
RenderPlaceholderProps,
|
||||
RenderTextProps,
|
||||
} from './editable'
|
||||
|
||||
import Text from './text'
|
||||
@@ -35,6 +36,7 @@ const Element = (props: {
|
||||
element: SlateElement
|
||||
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||
renderPlaceholder: (props: RenderPlaceholderProps) => JSX.Element
|
||||
renderText?: (props: RenderTextProps) => JSX.Element
|
||||
renderLeaf?: (props: RenderLeafProps) => JSX.Element
|
||||
selection: Range | null
|
||||
}) => {
|
||||
@@ -44,6 +46,7 @@ const Element = (props: {
|
||||
renderElement = (p: RenderElementProps) => <DefaultElement {...p} />,
|
||||
renderPlaceholder,
|
||||
renderLeaf,
|
||||
renderText,
|
||||
selection,
|
||||
} = props
|
||||
const editor = useSlateStatic()
|
||||
@@ -71,6 +74,7 @@ const Element = (props: {
|
||||
renderElement,
|
||||
renderPlaceholder,
|
||||
renderLeaf,
|
||||
renderText,
|
||||
selection,
|
||||
})
|
||||
|
||||
@@ -145,6 +149,7 @@ const MemoizedElement = React.memo(Element, (prev, next) => {
|
||||
return (
|
||||
prev.element === next.element &&
|
||||
prev.renderElement === next.renderElement &&
|
||||
prev.renderText === next.renderText &&
|
||||
prev.renderLeaf === next.renderLeaf &&
|
||||
prev.renderPlaceholder === next.renderPlaceholder &&
|
||||
isElementDecorationsEqual(prev.decorations, next.decorations) &&
|
||||
|
@@ -6,7 +6,7 @@ import React, {
|
||||
useEffect,
|
||||
} from 'react'
|
||||
import { JSX } from 'react'
|
||||
import { Element, Text } from 'slate'
|
||||
import { Element, LeafPosition, Text } from 'slate'
|
||||
import { ResizeObserver as ResizeObserverPolyfill } from '@juggle/resize-observer'
|
||||
import String from './string'
|
||||
import {
|
||||
@@ -53,6 +53,7 @@ const Leaf = (props: {
|
||||
renderPlaceholder: (props: RenderPlaceholderProps) => JSX.Element
|
||||
renderLeaf?: (props: RenderLeafProps) => JSX.Element
|
||||
text: Text
|
||||
leafPosition?: LeafPosition
|
||||
}) => {
|
||||
const {
|
||||
leaf,
|
||||
@@ -61,6 +62,7 @@ const Leaf = (props: {
|
||||
parent,
|
||||
renderPlaceholder,
|
||||
renderLeaf = (props: RenderLeafProps) => <DefaultLeaf {...props} />,
|
||||
leafPosition,
|
||||
} = props
|
||||
|
||||
const editor = useSlateStatic()
|
||||
@@ -157,7 +159,13 @@ const Leaf = (props: {
|
||||
'data-slate-leaf': true,
|
||||
}
|
||||
|
||||
return renderLeaf({ attributes, children, leaf, text })
|
||||
return renderLeaf({
|
||||
attributes,
|
||||
children,
|
||||
leaf,
|
||||
text,
|
||||
leafPosition,
|
||||
})
|
||||
}
|
||||
|
||||
const MemoizedLeaf = React.memo(Leaf, (prev, next) => {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useRef } from 'react'
|
||||
import { Element, DecoratedRange, Text as SlateText } from 'slate'
|
||||
import { Element, Text as SlateText, DecoratedRange } from 'slate'
|
||||
import { ReactEditor, useSlateStatic } from '..'
|
||||
import { isTextDecorationsEqual } from 'slate-dom'
|
||||
import {
|
||||
@@ -7,7 +7,11 @@ import {
|
||||
ELEMENT_TO_NODE,
|
||||
NODE_TO_ELEMENT,
|
||||
} from 'slate-dom'
|
||||
import { RenderLeafProps, RenderPlaceholderProps } from './editable'
|
||||
import {
|
||||
RenderLeafProps,
|
||||
RenderPlaceholderProps,
|
||||
RenderTextProps,
|
||||
} from './editable'
|
||||
import Leaf from './leaf'
|
||||
|
||||
/**
|
||||
@@ -20,25 +24,34 @@ const Text = (props: {
|
||||
parent: Element
|
||||
renderPlaceholder: (props: RenderPlaceholderProps) => JSX.Element
|
||||
renderLeaf?: (props: RenderLeafProps) => JSX.Element
|
||||
renderText?: (props: RenderTextProps) => JSX.Element
|
||||
text: SlateText
|
||||
}) => {
|
||||
const { decorations, isLast, parent, renderPlaceholder, renderLeaf, text } =
|
||||
props
|
||||
const {
|
||||
decorations,
|
||||
isLast,
|
||||
parent,
|
||||
renderPlaceholder,
|
||||
renderLeaf,
|
||||
renderText = (props: RenderTextProps) => <DefaultText {...props} />,
|
||||
text,
|
||||
} = props
|
||||
const editor = useSlateStatic()
|
||||
const ref = useRef<HTMLSpanElement | null>(null)
|
||||
const leaves = SlateText.decorations(text, decorations)
|
||||
const decoratedLeaves = SlateText.decorations(text, decorations)
|
||||
const key = ReactEditor.findKey(editor, text)
|
||||
const children = []
|
||||
|
||||
for (let i = 0; i < leaves.length; i++) {
|
||||
const leaf = leaves[i]
|
||||
for (let i = 0; i < decoratedLeaves.length; i++) {
|
||||
const { leaf, position } = decoratedLeaves[i]
|
||||
|
||||
children.push(
|
||||
<Leaf
|
||||
isLast={isLast && i === leaves.length - 1}
|
||||
isLast={isLast && i === decoratedLeaves.length - 1}
|
||||
key={`${key.id}-${i}`}
|
||||
renderPlaceholder={renderPlaceholder}
|
||||
leaf={leaf}
|
||||
leafPosition={position}
|
||||
text={text}
|
||||
parent={parent}
|
||||
renderLeaf={renderLeaf}
|
||||
@@ -65,17 +78,27 @@ const Text = (props: {
|
||||
},
|
||||
[ref, editor, key, text]
|
||||
)
|
||||
return (
|
||||
<span data-slate-node="text" ref={callbackRef}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
|
||||
const attributes: {
|
||||
'data-slate-node': 'text'
|
||||
ref: any
|
||||
} = {
|
||||
'data-slate-node': 'text',
|
||||
ref: callbackRef,
|
||||
}
|
||||
|
||||
return renderText({
|
||||
text,
|
||||
children,
|
||||
attributes,
|
||||
})
|
||||
}
|
||||
|
||||
const MemoizedText = React.memo(Text, (prev, next) => {
|
||||
return (
|
||||
next.parent === prev.parent &&
|
||||
next.isLast === prev.isLast &&
|
||||
next.renderText === prev.renderText &&
|
||||
next.renderLeaf === prev.renderLeaf &&
|
||||
next.renderPlaceholder === prev.renderPlaceholder &&
|
||||
next.text === prev.text &&
|
||||
@@ -83,4 +106,9 @@ const MemoizedText = React.memo(Text, (prev, next) => {
|
||||
)
|
||||
})
|
||||
|
||||
export const DefaultText = (props: RenderTextProps) => {
|
||||
const { attributes, children } = props
|
||||
return <span {...attributes}>{children}</span>
|
||||
}
|
||||
|
||||
export default MemoizedText
|
||||
|
@@ -11,6 +11,7 @@ import {
|
||||
RenderElementProps,
|
||||
RenderLeafProps,
|
||||
RenderPlaceholderProps,
|
||||
RenderTextProps,
|
||||
} from '../components/editable'
|
||||
|
||||
import ElementComponent from '../components/element'
|
||||
@@ -30,6 +31,7 @@ const useChildren = (props: {
|
||||
node: Ancestor
|
||||
renderElement?: (props: RenderElementProps) => JSX.Element
|
||||
renderPlaceholder: (props: RenderPlaceholderProps) => JSX.Element
|
||||
renderText?: (props: RenderTextProps) => JSX.Element
|
||||
renderLeaf?: (props: RenderLeafProps) => JSX.Element
|
||||
selection: Range | null
|
||||
}) => {
|
||||
|
@@ -8,6 +8,7 @@ export {
|
||||
} from './components/editable'
|
||||
|
||||
export { DefaultElement } from './components/element'
|
||||
export { DefaultText } from './components/text'
|
||||
export { DefaultLeaf } from './components/leaf'
|
||||
export { Slate } from './components/slate'
|
||||
|
||||
|
Reference in New Issue
Block a user