stacker.news/lexical/plugins/list-max-indent.js

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
}