mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-11 17:53:59 +02:00
feat: Forward ref from <Editable /> (#5681)
* feat: Forward ref from <Editable /> * docs: add changeset * Update packages/slate-react/src/components/editable.tsx * Update packages/slate-react/src/components/editable.tsx --------- Co-authored-by: Dylan Schiemann <dylan@dojotoolkit.org>
This commit is contained in:
5
.changeset/angry-brooms-whisper.md
Normal file
5
.changeset/angry-brooms-whisper.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'slate-react': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Forward ref from Editable component
|
@@ -8,6 +8,8 @@ import React, {
|
|||||||
useReducer,
|
useReducer,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
|
forwardRef,
|
||||||
|
ForwardedRef,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { JSX } from 'react'
|
import { JSX } from 'react'
|
||||||
import scrollIntoView from 'scroll-into-view-if-needed'
|
import scrollIntoView from 'scroll-into-view-if-needed'
|
||||||
@@ -130,7 +132,8 @@ export type EditableProps = {
|
|||||||
* Editable.
|
* Editable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const Editable = (props: EditableProps) => {
|
export const Editable = forwardRef(
|
||||||
|
(props: EditableProps, forwardedRef: ForwardedRef<HTMLDivElement>) => {
|
||||||
const defaultRenderPlaceholder = useCallback(
|
const defaultRenderPlaceholder = useCallback(
|
||||||
(props: RenderPlaceholderProps) => <DefaultPlaceholder {...props} />,
|
(props: RenderPlaceholderProps) => <DefaultPlaceholder {...props} />,
|
||||||
[]
|
[]
|
||||||
@@ -590,7 +593,10 @@ export const Editable = (props: EditableProps) => {
|
|||||||
.createTreeWalker(anchorNode, NodeFilter.SHOW_TEXT)
|
.createTreeWalker(anchorNode, NodeFilter.SHOW_TEXT)
|
||||||
.lastChild() as DOMText | null
|
.lastChild() as DOMText | null
|
||||||
|
|
||||||
if (lastText === node && lastText.textContent?.length === offset) {
|
if (
|
||||||
|
lastText === node &&
|
||||||
|
lastText.textContent?.length === offset
|
||||||
|
) {
|
||||||
native = false
|
native = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -814,12 +820,18 @@ export const Editable = (props: EditableProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref.current = node
|
ref.current = node
|
||||||
|
if (typeof forwardedRef === 'function') {
|
||||||
|
forwardedRef(node)
|
||||||
|
} else if (forwardedRef) {
|
||||||
|
forwardedRef.current = node
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
onDOMSelectionChange,
|
onDOMSelectionChange,
|
||||||
scheduleOnDOMSelectionChange,
|
scheduleOnDOMSelectionChange,
|
||||||
editor,
|
editor,
|
||||||
onDOMBeforeInput,
|
onDOMBeforeInput,
|
||||||
|
forwardedRef,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1129,7 +1141,10 @@ export const Editable = (props: EditableProps) => {
|
|||||||
if (event.detail === TRIPLE_CLICK && path.length >= 1) {
|
if (event.detail === TRIPLE_CLICK && path.length >= 1) {
|
||||||
let blockPath = path
|
let blockPath = path
|
||||||
if (
|
if (
|
||||||
!(Element.isElement(node) && Editor.isBlock(editor, node))
|
!(
|
||||||
|
Element.isElement(node) &&
|
||||||
|
Editor.isBlock(editor, node)
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
const block = Editor.above(editor, {
|
const block = Editor.above(editor, {
|
||||||
match: n =>
|
match: n =>
|
||||||
@@ -1236,7 +1251,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
onCompositionStart={useCallback(
|
onCompositionStart={useCallback(
|
||||||
(event: React.CompositionEvent<HTMLDivElement>) => {
|
(event: React.CompositionEvent<HTMLDivElement>) => {
|
||||||
if (ReactEditor.hasSelectableTarget(editor, event.target)) {
|
if (ReactEditor.hasSelectableTarget(editor, event.target)) {
|
||||||
androidInputManagerRef.current?.handleCompositionStart(event)
|
androidInputManagerRef.current?.handleCompositionStart(
|
||||||
|
event
|
||||||
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isEventHandled(event, attributes.onCompositionStart) ||
|
isEventHandled(event, attributes.onCompositionStart) ||
|
||||||
@@ -1314,7 +1331,10 @@ export const Editable = (props: EditableProps) => {
|
|||||||
// default, and calling `preventDefault` hides the cursor.
|
// default, and calling `preventDefault` hides the cursor.
|
||||||
const node = ReactEditor.toSlateNode(editor, event.target)
|
const node = ReactEditor.toSlateNode(editor, event.target)
|
||||||
|
|
||||||
if (Element.isElement(node) && Editor.isVoid(editor, node)) {
|
if (
|
||||||
|
Element.isElement(node) &&
|
||||||
|
Editor.isVoid(editor, node)
|
||||||
|
) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1331,7 +1351,8 @@ export const Editable = (props: EditableProps) => {
|
|||||||
const node = ReactEditor.toSlateNode(editor, event.target)
|
const node = ReactEditor.toSlateNode(editor, event.target)
|
||||||
const path = ReactEditor.findPath(editor, node)
|
const path = ReactEditor.findPath(editor, node)
|
||||||
const voidMatch =
|
const voidMatch =
|
||||||
(Element.isElement(node) && Editor.isVoid(editor, node)) ||
|
(Element.isElement(node) &&
|
||||||
|
Editor.isVoid(editor, node)) ||
|
||||||
Editor.void(editor, { at: path, voids: true })
|
Editor.void(editor, { at: path, voids: true })
|
||||||
|
|
||||||
// If starting a drag on a void node, make sure it is selected
|
// If starting a drag on a void node, make sure it is selected
|
||||||
@@ -1610,7 +1631,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if (selection && Range.isExpanded(selection)) {
|
if (selection && Range.isExpanded(selection)) {
|
||||||
Editor.deleteFragment(editor, { direction: 'backward' })
|
Editor.deleteFragment(editor, {
|
||||||
|
direction: 'backward',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Editor.deleteBackward(editor)
|
Editor.deleteBackward(editor)
|
||||||
}
|
}
|
||||||
@@ -1622,7 +1645,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if (selection && Range.isExpanded(selection)) {
|
if (selection && Range.isExpanded(selection)) {
|
||||||
Editor.deleteFragment(editor, { direction: 'forward' })
|
Editor.deleteFragment(editor, {
|
||||||
|
direction: 'forward',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Editor.deleteForward(editor)
|
Editor.deleteForward(editor)
|
||||||
}
|
}
|
||||||
@@ -1634,7 +1659,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if (selection && Range.isExpanded(selection)) {
|
if (selection && Range.isExpanded(selection)) {
|
||||||
Editor.deleteFragment(editor, { direction: 'backward' })
|
Editor.deleteFragment(editor, {
|
||||||
|
direction: 'backward',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Editor.deleteBackward(editor, { unit: 'line' })
|
Editor.deleteBackward(editor, { unit: 'line' })
|
||||||
}
|
}
|
||||||
@@ -1646,7 +1673,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if (selection && Range.isExpanded(selection)) {
|
if (selection && Range.isExpanded(selection)) {
|
||||||
Editor.deleteFragment(editor, { direction: 'forward' })
|
Editor.deleteFragment(editor, {
|
||||||
|
direction: 'forward',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Editor.deleteForward(editor, { unit: 'line' })
|
Editor.deleteForward(editor, { unit: 'line' })
|
||||||
}
|
}
|
||||||
@@ -1658,7 +1687,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if (selection && Range.isExpanded(selection)) {
|
if (selection && Range.isExpanded(selection)) {
|
||||||
Editor.deleteFragment(editor, { direction: 'backward' })
|
Editor.deleteFragment(editor, {
|
||||||
|
direction: 'backward',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Editor.deleteBackward(editor, { unit: 'word' })
|
Editor.deleteBackward(editor, { unit: 'word' })
|
||||||
}
|
}
|
||||||
@@ -1670,7 +1701,9 @@ export const Editable = (props: EditableProps) => {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
if (selection && Range.isExpanded(selection)) {
|
if (selection && Range.isExpanded(selection)) {
|
||||||
Editor.deleteFragment(editor, { direction: 'forward' })
|
Editor.deleteFragment(editor, {
|
||||||
|
direction: 'forward',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Editor.deleteForward(editor, { unit: 'word' })
|
Editor.deleteForward(editor, { unit: 'word' })
|
||||||
}
|
}
|
||||||
@@ -1751,6 +1784,7 @@ export const Editable = (props: EditableProps) => {
|
|||||||
</ReadOnlyContext.Provider>
|
</ReadOnlyContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The props that get passed to renderPlaceholder
|
* The props that get passed to renderPlaceholder
|
||||||
|
Reference in New Issue
Block a user