mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-11 17:53:59 +02:00
Change how Slate context updates and introduce useSlateSelection
hook (#5041)
* Fix DOM selection sync when there are unexpected rerenders * Create a useSlateSelection hook and expose it * update docs * add changeset * Undo the useEffect change and add a useSlateValue method * Use a version counter instead for SlateContext * comment out layout effect prevention for now * Undo useV comparison for now * Change the changeset * Fix lint * Remove the useSlateValue hook * remove some unused imports * Add useSlateWithV to the docs * fix changeset lint * Change changeset to minor instead
This commit is contained in:
@@ -150,7 +150,7 @@ export const Editable = (props: EditableProps) => {
|
||||
[]
|
||||
)
|
||||
|
||||
// Whenever the editor updates...
|
||||
// Whenever the editor updates, sync the DOM selection with the slate selection
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
// Update element-related weak maps with the DOM element ref.
|
||||
let window
|
||||
|
@@ -3,7 +3,7 @@ import { Editor, Node, Descendant, Scrubber } from 'slate'
|
||||
import { ReactEditor } from '../plugin/react-editor'
|
||||
import { FocusedContext } from '../hooks/use-focused'
|
||||
import { EditorContext } from '../hooks/use-slate-static'
|
||||
import { SlateContext } from '../hooks/use-slate'
|
||||
import { SlateContext, SlateContextValue } from '../hooks/use-slate'
|
||||
import {
|
||||
getSelectorContext,
|
||||
SlateSelectorContext,
|
||||
@@ -26,7 +26,7 @@ export const Slate = (props: {
|
||||
const { editor, children, onChange, value, ...rest } = props
|
||||
const unmountRef = useRef(false)
|
||||
|
||||
const [context, setContext] = React.useState<[ReactEditor]>(() => {
|
||||
const [context, setContext] = React.useState<SlateContextValue>(() => {
|
||||
if (!Node.isNodeList(value)) {
|
||||
throw new Error(
|
||||
`[Slate] value is invalid! Expected a list of elements` +
|
||||
@@ -41,7 +41,7 @@ export const Slate = (props: {
|
||||
}
|
||||
editor.children = value
|
||||
Object.assign(editor, rest)
|
||||
return [editor]
|
||||
return { v: 0, editor }
|
||||
})
|
||||
|
||||
const {
|
||||
@@ -54,7 +54,10 @@ export const Slate = (props: {
|
||||
onChange(editor.children)
|
||||
}
|
||||
|
||||
setContext([editor])
|
||||
setContext(prevContext => ({
|
||||
v: prevContext.v + 1,
|
||||
editor,
|
||||
}))
|
||||
handleSelectorChange(editor)
|
||||
}, [onChange])
|
||||
|
||||
|
17
packages/slate-react/src/hooks/use-slate-selection.tsx
Normal file
17
packages/slate-react/src/hooks/use-slate-selection.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { BaseSelection, Range } from 'slate'
|
||||
|
||||
import { useSlateSelector } from './use-slate-selector'
|
||||
|
||||
/**
|
||||
* Get the current slate selection.
|
||||
* Only triggers a rerender when the selection actually changes
|
||||
*/
|
||||
export const useSlateSelection = () => {
|
||||
return useSlateSelector(editor => editor.selection, isSelectionEqual)
|
||||
}
|
||||
|
||||
const isSelectionEqual = (a: BaseSelection, b: BaseSelection) => {
|
||||
if (!a && !b) return true
|
||||
if (!a || !b) return false
|
||||
return Range.equals(a, b)
|
||||
}
|
@@ -7,7 +7,15 @@ import { ReactEditor } from '../plugin/react-editor'
|
||||
* context whenever changes occur.
|
||||
*/
|
||||
|
||||
export const SlateContext = createContext<[ReactEditor] | null>(null)
|
||||
export interface SlateContextValue {
|
||||
v: number
|
||||
editor: ReactEditor
|
||||
}
|
||||
|
||||
export const SlateContext = createContext<{
|
||||
v: number
|
||||
editor: ReactEditor
|
||||
} | null>(null)
|
||||
|
||||
/**
|
||||
* Get the current editor object from the React context.
|
||||
@@ -22,6 +30,18 @@ export const useSlate = (): Editor => {
|
||||
)
|
||||
}
|
||||
|
||||
const [editor] = context
|
||||
const { editor } = context
|
||||
return editor
|
||||
}
|
||||
|
||||
export const useSlateWithV = () => {
|
||||
const context = useContext(SlateContext)
|
||||
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
`The \`useSlate\` hook must be used inside the <Slate> component's context.`
|
||||
)
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
@@ -23,8 +23,9 @@ export { useSlateStatic } from './hooks/use-slate-static'
|
||||
export { useFocused } from './hooks/use-focused'
|
||||
export { useReadOnly } from './hooks/use-read-only'
|
||||
export { useSelected } from './hooks/use-selected'
|
||||
export { useSlate } from './hooks/use-slate'
|
||||
export { useSlate, useSlateWithV } from './hooks/use-slate'
|
||||
export { useSlateSelector } from './hooks/use-slate-selector'
|
||||
export { useSlateSelection } from './hooks/use-slate-selection'
|
||||
|
||||
// Plugin
|
||||
export { ReactEditor } from './plugin/react-editor'
|
||||
|
Reference in New Issue
Block a user