]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/defaults/buttons/lists.ts
Lexical: Added block indenting capability
[bookstack] / resources / js / wysiwyg / ui / defaults / buttons / lists.ts
1 import {$isListNode, ListNode, ListType} from "@lexical/list";
2 import {EditorButtonDefinition} from "../../framework/buttons";
3 import {EditorUiContext} from "../../framework/core";
4 import {
5     BaseSelection,
6     LexicalEditor,
7     LexicalNode,
8 } from "lexical";
9 import listBulletIcon from "@icons/editor/list-bullet.svg";
10 import listNumberedIcon from "@icons/editor/list-numbered.svg";
11 import listCheckIcon from "@icons/editor/list-check.svg";
12 import indentIncreaseIcon from "@icons/editor/indent-increase.svg";
13 import indentDecreaseIcon from "@icons/editor/indent-decrease.svg";
14 import {
15     $getBlockElementNodesInSelection,
16     $selectionContainsNodeType,
17     $toggleSelection,
18     getLastSelection
19 } from "../../../utils/selection";
20 import {toggleSelectionAsList} from "../../../utils/formats";
21 import {nodeHasInset} from "../../../utils/nodes";
22
23
24 function buildListButton(label: string, type: ListType, icon: string): EditorButtonDefinition {
25     return {
26         label,
27         icon,
28         action(context: EditorUiContext) {
29             toggleSelectionAsList(context.editor, type);
30         },
31         isActive(selection: BaseSelection|null): boolean {
32             return $selectionContainsNodeType(selection, (node: LexicalNode | null | undefined): boolean => {
33                 return $isListNode(node) && (node as ListNode).getListType() === type;
34             });
35         }
36     };
37 }
38
39 export const bulletList: EditorButtonDefinition = buildListButton('Bullet list', 'bullet', listBulletIcon);
40 export const numberList: EditorButtonDefinition = buildListButton('Numbered list', 'number', listNumberedIcon);
41 export const taskList: EditorButtonDefinition = buildListButton('Task list', 'check', listCheckIcon);
42
43
44 function setInsetForSelection(editor: LexicalEditor, change: number): void {
45     const selection = getLastSelection(editor);
46
47     const elements = $getBlockElementNodesInSelection(selection);
48     for (const node of elements) {
49         if (nodeHasInset(node)) {
50             const currentInset = node.getInset();
51             const newInset = Math.min(Math.max(currentInset + change, 0), 500);
52             node.setInset(newInset)
53         }
54     }
55
56     $toggleSelection(editor);
57 }
58
59 export const indentIncrease: EditorButtonDefinition = {
60     label: 'Increase indent',
61     icon: indentIncreaseIcon,
62     action(context: EditorUiContext) {
63         context.editor.update(() => {
64             setInsetForSelection(context.editor, 40);
65         });
66     },
67     isActive() {
68         return false;
69     }
70 };
71
72 export const indentDecrease: EditorButtonDefinition = {
73     label: 'Decrease indent',
74     icon: indentDecreaseIcon,
75     action(context: EditorUiContext) {
76         context.editor.update(() => {
77             setInsetForSelection(context.editor, -40);
78         });
79     },
80     isActive() {
81         return false;
82     }
83 };