1
0
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:
Ziad Beyens
2025-04-29 16:30:57 +02:00
committed by GitHub
parent 2c62e01797
commit 22a3dda36d
20 changed files with 390 additions and 117 deletions

View File

@@ -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>

View File

@@ -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) &&

View File

@@ -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) => {

View File

@@ -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

View File

@@ -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
}) => {

View File

@@ -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'