chore: make collapsible arrow key behavior same as lexical
This commit is contained in:
@@ -24,6 +24,9 @@ import {
|
|||||||
DELETE_CHARACTER_COMMAND,
|
DELETE_CHARACTER_COMMAND,
|
||||||
INSERT_PARAGRAPH_COMMAND,
|
INSERT_PARAGRAPH_COMMAND,
|
||||||
KEY_ARROW_DOWN_COMMAND,
|
KEY_ARROW_DOWN_COMMAND,
|
||||||
|
KEY_ARROW_LEFT_COMMAND,
|
||||||
|
KEY_ARROW_RIGHT_COMMAND,
|
||||||
|
KEY_ARROW_UP_COMMAND,
|
||||||
NodeKey,
|
NodeKey,
|
||||||
} from 'lexical'
|
} from 'lexical'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
@@ -52,6 +55,49 @@ export default function CollapsiblePlugin(): JSX.Element | null {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onEscapeUp = () => {
|
||||||
|
const selection = $getSelection()
|
||||||
|
if ($isRangeSelection(selection) && selection.isCollapsed() && selection.anchor.offset === 0) {
|
||||||
|
const container = $findMatchingParent(selection.anchor.getNode(), $isCollapsibleContainerNode)
|
||||||
|
|
||||||
|
if ($isCollapsibleContainerNode(container)) {
|
||||||
|
const parent = container.getParent()
|
||||||
|
if (
|
||||||
|
parent !== null &&
|
||||||
|
parent.getFirstChild() === container &&
|
||||||
|
selection.anchor.key === container.getFirstDescendant()?.getKey()
|
||||||
|
) {
|
||||||
|
container.insertBefore($createParagraphNode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onEscapeDown = () => {
|
||||||
|
const selection = $getSelection()
|
||||||
|
if ($isRangeSelection(selection) && selection.isCollapsed()) {
|
||||||
|
const container = $findMatchingParent(selection.anchor.getNode(), $isCollapsibleContainerNode)
|
||||||
|
|
||||||
|
if ($isCollapsibleContainerNode(container)) {
|
||||||
|
const parent = container.getParent()
|
||||||
|
if (parent !== null && parent.getLastChild() === container) {
|
||||||
|
const lastDescendant = container.getLastDescendant()
|
||||||
|
if (
|
||||||
|
lastDescendant !== null &&
|
||||||
|
selection.anchor.key === lastDescendant.getKey() &&
|
||||||
|
selection.anchor.offset === lastDescendant.getTextContentSize()
|
||||||
|
) {
|
||||||
|
container.insertAfter($createParagraphNode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return mergeRegister(
|
return mergeRegister(
|
||||||
// Structure enforcing transformers for each node type. In case nesting structure is not
|
// Structure enforcing transformers for each node type. In case nesting structure is not
|
||||||
// "Container > Title + Content" it'll unwrap nodes and convert it back
|
// "Container > Title + Content" it'll unwrap nodes and convert it back
|
||||||
@@ -109,32 +155,18 @@ export default function CollapsiblePlugin(): JSX.Element | null {
|
|||||||
},
|
},
|
||||||
COMMAND_PRIORITY_LOW,
|
COMMAND_PRIORITY_LOW,
|
||||||
),
|
),
|
||||||
// When collapsible is the last child pressing down arrow will insert paragraph
|
// When collapsible is the last child pressing down/right arrow will insert paragraph
|
||||||
// below it to allow adding more content. It's similar what $insertBlockNode
|
// below it to allow adding more content. It's similar what $insertBlockNode
|
||||||
// (mainly for decorators), except it'll always be possible to continue adding
|
// (mainly for decorators), except it'll always be possible to continue adding
|
||||||
// new content even if trailing paragraph is accidentally deleted
|
// new content even if trailing paragraph is accidentally deleted
|
||||||
editor.registerCommand(
|
editor.registerCommand(KEY_ARROW_DOWN_COMMAND, onEscapeDown, COMMAND_PRIORITY_LOW),
|
||||||
KEY_ARROW_DOWN_COMMAND,
|
editor.registerCommand(KEY_ARROW_RIGHT_COMMAND, onEscapeDown, COMMAND_PRIORITY_LOW),
|
||||||
() => {
|
// When collapsible is the first child pressing up/left arrow will insert paragraph
|
||||||
const selection = $getSelection()
|
// above it to allow adding more content. It's similar what $insertBlockNode
|
||||||
if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
|
// (mainly for decorators), except it'll always be possible to continue adding
|
||||||
return false
|
// new content even if leading paragraph is accidentally deleted
|
||||||
}
|
editor.registerCommand(KEY_ARROW_UP_COMMAND, onEscapeUp, COMMAND_PRIORITY_LOW),
|
||||||
|
editor.registerCommand(KEY_ARROW_LEFT_COMMAND, onEscapeUp, COMMAND_PRIORITY_LOW),
|
||||||
const container = $findMatchingParent(selection.anchor.getNode(), $isCollapsibleContainerNode)
|
|
||||||
|
|
||||||
if (container === null) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const parent = container.getParent()
|
|
||||||
if (parent !== null && parent.getLastChild() === container) {
|
|
||||||
parent.append($createParagraphNode())
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
COMMAND_PRIORITY_LOW,
|
|
||||||
),
|
|
||||||
// Handling CMD+Enter to toggle collapsible element collapsed state
|
// Handling CMD+Enter to toggle collapsible element collapsed state
|
||||||
editor.registerCommand(
|
editor.registerCommand(
|
||||||
INSERT_PARAGRAPH_COMMAND,
|
INSERT_PARAGRAPH_COMMAND,
|
||||||
|
|||||||
Reference in New Issue
Block a user