-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Attempting to limit text insertion by overriding insertText
causes content to be out of sync with node representation
#5010
Comments
Facing the exact same issue. –– EDIT –– Adding an <Editable
renderElement={renderElement}
renderLeaf={renderLeaf}
onKeyDown={(event) => {
// disable key down events if max signs is reached
// (except nav keys such as Tab/Arrows)
if (
config.maxSigns &&
getCharCount(editor.children) >= config.maxSigns &&
!NAV_KEYS.concat('Backspace').includes(event.key)
) {
event.preventDefault()
return false
}
}}
/> |
Same issue. Only number input is limited. |
this worked perfectly, thanks a lot @annatraussnig! 🙌 |
If it is a Chinese input method, it will make an error. |
I have two more different approaches. The first one is based on predicting the result: <Editable
renderLeaf={renderLeaf}
renderElement={renderElement}
renderPlaceholder={renderPlaceholder}
placeholder={placeholder}
onDOMBeforeInput={(e) => {
if (
e.inputType !== 'insertText' &&
e.inputType !== 'insertFromPaste'
)
return
const input = e.data || e.dataTransfer?.getData('text/plain')
if (!input) return
const sel = [
editor.selection?.anchor?.offset || 0,
editor.selection?.focus?.offset || 0
].sort()
const text = serializeString(editor.children)
const newText =
text.substring(0, sel[0]) + input + text.substring(sel[1])
if (newText.length > config.maxSigns) e.preventDefault()
}}
/> It also works with pasting some (not every 🤷♂️) clipboard data. The second one I made for formatting on the go, so it may be overkill for just limiting the characters length. In the editor: const editor = useMemo(
() =>
withFormatting(
withHistory(withReact(createEditor())),
(s) =>
s.trimStart().replace(/\s+/gi, ' ') // some formatting
.substring(0, config.maxSigns) // limit char length
),
[]
) the plugin: function withFormatting<T extends Editor>(editor: T, format?: FormatCb) {
const { insertText, deleteFragment, deleteBackward, deleteForward } = editor
const canFormat = typeof format === 'function'
if (!canFormat) return editor
editor.insertText = (textPart) => {
insertText(textPart)
const text = serializeString(currentNode(editor))
const sel = editor.selection?.anchor?.offset || text.length
const formattedText = format(text)
// replacing with formatted text
Transforms.insertText(editor, formattedText, {
at: changeSelectionOffset(editor.selection, [0, text.length])
})
const textDiff = formattedText.length - text.length
const newOffset = Math.min(sel + textDiff, formattedText.length)
editor.selection = changeSelectionOffset(editor.selection, newOffset)
}
editor.deleteFragment = (d) => {
deleteFragment(d)
editor.insertText('')
}
editor.deleteBackward = (d) => {
deleteBackward(d)
editor.insertText('')
}
editor.deleteForward = (d) => {
deleteForward(d)
editor.insertText('')
}
return editor
}
function currentNode<T extends Editor>({
children,
selection
}: T): Descendant[] {
if (!selection) return children
const path = selection?.anchor.path || [0, 0]
const url = path
.slice(0, path.length - 1)
.map((i) => `[${i}]`)
.join('.children')
const node = _.get(children, url)
return node?.children || children
}
function changeSelectionOffset(
selection: BaseSelection,
offsetOrArray: [number, number] | number
) {
const offset =
typeof offsetOrArray === 'number' ? [offsetOrArray] : offsetOrArray
return {
anchor: {
...selection.anchor,
offset: offset[0]
},
focus: {
...selection.focus,
offset: offset[1] || offset[0]
}
}
}
function serializeString (value?: Descendant[]){
return (value || []).map((n) => Node.string(n)).join()
} |
not work while useing Chinese.....😮💨 |
Thx for the workarounds, but shouldn't this work correctly out of the box? |
how can i get the NAV_KEYS variable? |
Description
We're attempting to limit the content to a maximum length by overriding
insertText
, but as of version 0.67 Slate will continue to display characters that are typed even though they don't exist in the node representation. This can lead to data lossRecording
Screen.Recording.2022-05-26.at.3.04.27.PM.mov
Sandbox
https://codesandbox.io/s/slate-character-limit-bug-rdursq?file=/index.js
Change slate-react to < 0.67 to see the desired behavior
Steps
To reproduce the behavior:
insertText
Expectation
The editor should not allow any characters to be typed
Environment
Context
The text was updated successfully, but these errors were encountered: