Skip to content

Commit

Permalink
Merge pull request #330 from MovieReviewComment/feature/issue-302/lis…
Browse files Browse the repository at this point in the history
…t-max-indentation

[#302] Add ListMaxIndentLevelPlugin on Editor
  • Loading branch information
2wheeh authored Apr 14, 2024
2 parents 39b641c + 2a1e43b commit 8c2920d
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
2 changes: 2 additions & 0 deletions ui/src/editor/plugins/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useEditorRef } from '@/context/editor/editor-ref-context';

import { FixIOSKoreanIssuePlugin } from '@/editor/plugins/fix-ios-korean-issue';
import { HistoryPlugin } from '@/editor/plugins/history';
import { ListMaxIndentLevelPlugin } from '@/editor/plugins/list-max-indent-level';
import { MarkdownShortcutPlugin } from '@/editor/plugins/markdown-shorcut';
import { MaxLengthPlugin } from '@/editor/plugins/max-length';

Expand Down Expand Up @@ -37,6 +38,7 @@ export function Plugins({ maxLength }: { maxLength?: number }) {
<HistoryPlugin />
<TabIndentationPlugin />
<FixIOSKoreanIssuePlugin />
<ListMaxIndentLevelPlugin maxDepth={3} />
{onRef !== undefined && <EditorRefPlugin editorRef={onRef} />}
{maxLength && <MaxLengthPlugin maxLength={maxLength} />}
</>
Expand Down
78 changes: 78 additions & 0 deletions ui/src/editor/plugins/list-max-indent-level/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { ListNode } from '@lexical/list';
import { $getListDepth, $isListItemNode, $isListNode } from '@lexical/list';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import type { ElementNode, RangeSelection } from 'lexical';
import {
$getSelection,
$isElementNode,
$isRangeSelection,
COMMAND_PRIORITY_CRITICAL,
INDENT_CONTENT_COMMAND,
} from 'lexical';
import { useEffect } from 'react';

function getElementNodesInSelection(selection: RangeSelection): Set<ElementNode> {
const nodesInSelection = selection.getNodes();
// TODO: Remove this type assertion once the lexical types are updated. facebook#5710
const anchor = selection.anchor.getNode() as ElementNode;
const focus = selection.focus.getNode() as ElementNode;

if (nodesInSelection.length === 0) {
return new Set<ElementNode>([anchor.getParentOrThrow(), focus.getParentOrThrow()]);
}

return new Set(nodesInSelection.map((n) => ($isElementNode(n) ? n : n.getParentOrThrow())));
}

function shouldPreventIndent(maxDepth: number) {
const selection = $getSelection();

if (!$isRangeSelection(selection)) {
return false;
}

const elementNodesInSelection: Set<ElementNode> = getElementNodesInSelection(selection);

let totalDepth = 0;

for (const elementNode of elementNodesInSelection) {
let listNode: ListNode | null = null;

if ($isListNode(elementNode)) {
listNode = elementNode;
} else if ($isListItemNode(elementNode)) {
// TODO: Remove this type assertion once the lexical types are updated.
const parent = elementNode.getParent() as ElementNode;

if (!$isListNode(parent)) {
throw new Error(
'ListMaxIndentLevelPlugin: A ListItemNode must have a ListNode for a parent.'
);
}

listNode = parent;
}

if (listNode !== null) {
totalDepth = Math.max($getListDepth(listNode) + 1, totalDepth);
}
}

return totalDepth > maxDepth;
}

export function ListMaxIndentLevelPlugin({ maxDepth = 7 }: { maxDepth?: number }) {
const [editor] = useLexicalComposerContext();

useEffect(
() =>
editor.registerCommand(
INDENT_CONTENT_COMMAND,
() => shouldPreventIndent(maxDepth),
COMMAND_PRIORITY_CRITICAL
),
[editor, maxDepth]
);

return null;
}

0 comments on commit 8c2920d

Please sign in to comment.