1 import {$createCustomListItemNode, $isCustomListItemNode, CustomListItemNode} from "../nodes/custom-list-item";
2 import {$createCustomListNode, $isCustomListNode} from "../nodes/custom-list";
3 import {$getSelection, BaseSelection, LexicalEditor} from "lexical";
4 import {$getBlockElementNodesInSelection, $selectNodes, $toggleSelection} from "./selection";
5 import {nodeHasInset} from "./nodes";
8 export function $nestListItem(node: CustomListItemNode): 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);
34 export function $unnestListItem(node: CustomListItemNode): CustomListItemNode {
35 const list = node.getParent();
36 const parentListItem = list?.getParent();
37 const outerList = parentListItem?.getParent();
38 if (!$isCustomListNode(list) || !$isCustomListNode(outerList) || !$isCustomListItemNode(parentListItem)) {
42 parentListItem.insertAfter(node);
43 if (list.getChildren().length === 0) {
47 if (parentListItem.getChildren().length === 0) {
48 parentListItem.remove();
54 function getListItemsForSelection(selection: BaseSelection|null): (CustomListItemNode|null)[] {
55 const nodes = selection?.getNodes() || [];
56 const listItemNodes = [];
58 outer: for (const node of nodes) {
59 if ($isCustomListItemNode(node)) {
60 listItemNodes.push(node);
64 const parents = node.getParents();
65 for (const parent of parents) {
66 if ($isCustomListItemNode(parent)) {
67 listItemNodes.push(parent);
72 listItemNodes.push(null);
78 function $reduceDedupeListItems(listItems: (CustomListItemNode|null)[]): CustomListItemNode[] {
79 const listItemMap: Record<string, CustomListItemNode> = {};
81 for (const item of listItems) {
86 const key = item.getKey();
87 if (typeof listItemMap[key] === 'undefined') {
88 listItemMap[key] = item;
92 return Object.values(listItemMap);
95 export function $setInsetForSelection(editor: LexicalEditor, change: number): void {
96 const selection = $getSelection();
97 const listItemsInSelection = getListItemsForSelection(selection);
98 const isListSelection = listItemsInSelection.length > 0 && !listItemsInSelection.includes(null);
100 if (isListSelection) {
101 const alteredListItems = [];
102 const listItems = $reduceDedupeListItems(listItemsInSelection);
104 for (const listItem of listItems) {
105 alteredListItems.push($nestListItem(listItem));
107 } else if (change < 0) {
108 for (const listItem of [...listItems].reverse()) {
109 alteredListItems.push($unnestListItem(listItem));
111 alteredListItems.reverse();
114 $selectNodes(alteredListItems);
118 const elements = $getBlockElementNodesInSelection(selection);
119 for (const node of elements) {
120 if (nodeHasInset(node)) {
121 const currentInset = node.getInset();
122 const newInset = Math.min(Math.max(currentInset + change, 0), 500);
123 node.setInset(newInset)
127 $toggleSelection(editor);