69 lines
1.8 KiB
JavaScript
69 lines
1.8 KiB
JavaScript
import { $getListDepth, $isListItemNode, $isListNode } from '@lexical/list'
|
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
|
import {
|
|
$getSelection,
|
|
$isElementNode,
|
|
$isRangeSelection,
|
|
INDENT_CONTENT_COMMAND,
|
|
COMMAND_PRIORITY_HIGH
|
|
} from 'lexical'
|
|
import { useEffect } from 'react'
|
|
|
|
function getElementNodesInSelection (selection) {
|
|
const nodesInSelection = selection.getNodes()
|
|
|
|
if (nodesInSelection.length === 0) {
|
|
return new Set([
|
|
selection.anchor.getNode().getParentOrThrow(),
|
|
selection.focus.getNode().getParentOrThrow()
|
|
])
|
|
}
|
|
|
|
return new Set(
|
|
nodesInSelection.map((n) => ($isElementNode(n) ? n : n.getParentOrThrow()))
|
|
)
|
|
}
|
|
|
|
function isIndentPermitted (maxDepth) {
|
|
const selection = $getSelection()
|
|
|
|
if (!$isRangeSelection(selection)) {
|
|
return false
|
|
}
|
|
|
|
const elementNodesInSelection = getElementNodesInSelection(selection)
|
|
|
|
let totalDepth = 0
|
|
|
|
for (const elementNode of elementNodesInSelection) {
|
|
if ($isListNode(elementNode)) {
|
|
totalDepth = Math.max($getListDepth(elementNode) + 1, totalDepth)
|
|
} else if ($isListItemNode(elementNode)) {
|
|
const parent = elementNode.getParent()
|
|
if (!$isListNode(parent)) {
|
|
throw new Error(
|
|
'ListMaxIndentLevelPlugin: A ListItemNode must have a ListNode for a parent.'
|
|
)
|
|
}
|
|
|
|
totalDepth = Math.max($getListDepth(parent) + 1, totalDepth)
|
|
}
|
|
}
|
|
|
|
return totalDepth <= maxDepth
|
|
}
|
|
|
|
export default function ListMaxIndentLevelPlugin ({ maxDepth }) {
|
|
const [editor] = useLexicalComposerContext()
|
|
|
|
useEffect(() => {
|
|
return editor.registerCommand(
|
|
INDENT_CONTENT_COMMAND,
|
|
() => !isIndentPermitted(maxDepth ?? 7),
|
|
COMMAND_PRIORITY_HIGH
|
|
)
|
|
}, [editor, maxDepth])
|
|
|
|
return null
|
|
}
|