1 import {$createCustomListItemNode, $isCustomListItemNode, CustomListItemNode} from "../nodes/custom-list-item";
2 import {$createCustomListNode, $isCustomListNode} from "../nodes/custom-list";
3 import {BaseSelection, LexicalEditor} from "lexical";
4 import {$getBlockElementNodesInSelection, $selectNodes, $toggleSelection, getLastSelection} from "./selection";
5 import {nodeHasInset} from "./nodes";
8 export function $nestListItem(node: CustomListItemNode) {
9 const list = node.getParent();
10 if (!$isCustomListNode(list)) {
14 const listItems = list.getChildren() as CustomListItemNode[];
15 const nodeIndex = listItems.findIndex((n) => n.getKey() === node.getKey());
16 const isFirst = nodeIndex === 0;
18 const newListItem = $createCustomListItemNode();
19 const newList = $createCustomListNode(list.getListType());
20 newList.append(newListItem);
21 newListItem.append(...node.getChildren());
26 const prevListItem = listItems[nodeIndex - 1];
27 prevListItem.append(newList);
32 export function $unnestListItem(node: CustomListItemNode) {
33 const list = node.getParent();
34 const parentListItem = list?.getParent();
35 const outerList = parentListItem?.getParent();
36 if (!$isCustomListNode(list) || !$isCustomListNode(outerList) || !$isCustomListItemNode(parentListItem)) {
40 parentListItem.insertAfter(node);
41 if (list.getChildren().length === 0) {
45 if (parentListItem.getChildren().length === 0) {
46 parentListItem.remove();
50 function getListItemsForSelection(selection: BaseSelection|null): (CustomListItemNode|null)[] {
51 const nodes = selection?.getNodes() || [];
52 const listItemNodes = [];
54 outer: for (const node of nodes) {
55 if ($isCustomListItemNode(node)) {
56 listItemNodes.push(node);
60 const parents = node.getParents();
61 for (const parent of parents) {
62 if ($isCustomListItemNode(parent)) {
63 listItemNodes.push(parent);
68 listItemNodes.push(null);
74 function $reduceDedupeListItems(listItems: (CustomListItemNode|null)[]): CustomListItemNode[] {
75 const listItemMap: Record<string, CustomListItemNode> = {};
77 for (const item of listItems) {
82 const key = item.getKey();
83 if (typeof listItemMap[key] === 'undefined') {
84 listItemMap[key] = item;
88 return Object.values(listItemMap);
91 export function $setInsetForSelection(editor: LexicalEditor, change: number): void {
92 const selection = getLastSelection(editor);
94 const listItemsInSelection = getListItemsForSelection(selection);
95 const isListSelection = listItemsInSelection.length > 0 && !listItemsInSelection.includes(null);
97 if (isListSelection) {
98 const listItems = $reduceDedupeListItems(listItemsInSelection);
100 for (const listItem of listItems) {
101 $nestListItem(listItem);
103 } else if (change < 0) {
104 for (const listItem of [...listItems].reverse()) {
105 $unnestListItem(listItem);
109 $selectNodes(listItems);
113 const elements = $getBlockElementNodesInSelection(selection);
114 for (const node of elements) {
115 if (nodeHasInset(node)) {
116 const currentInset = node.getInset();
117 const newInset = Math.min(Math.max(currentInset + change, 0), 500);
118 node.setInset(newInset)
122 $toggleSelection(editor);