]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/defaults/buttons/alignments.ts
b1c701dda4d5badd61a35ada3ea639355fb93a7d
[bookstack] / resources / js / wysiwyg / ui / defaults / buttons / alignments.ts
1 import {$isElementNode, BaseSelection, LexicalEditor} from "lexical";
2 import {EditorButtonDefinition} from "../../framework/buttons";
3 import alignLeftIcon from "@icons/editor/align-left.svg";
4 import {EditorUiContext} from "../../framework/core";
5 import alignCenterIcon from "@icons/editor/align-center.svg";
6 import alignRightIcon from "@icons/editor/align-right.svg";
7 import alignJustifyIcon from "@icons/editor/align-justify.svg";
8 import ltrIcon from "@icons/editor/direction-ltr.svg";
9 import rtlIcon from "@icons/editor/direction-rtl.svg";
10 import {
11     $getBlockElementNodesInSelection,
12     $selectionContainsAlignment, $selectionContainsDirection, $selectSingleNode, $toggleSelection, getLastSelection
13 } from "../../../utils/selection";
14 import {CommonBlockAlignment} from "../../../nodes/_common";
15 import {nodeHasAlignment} from "../../../utils/nodes";
16
17
18 function setAlignmentForSelection(editor: LexicalEditor, alignment: CommonBlockAlignment): void {
19     const selection = getLastSelection(editor);
20     const selectionNodes = selection?.getNodes() || [];
21
22     // Handle inline node selection alignment
23     if (selectionNodes.length === 1 && $isElementNode(selectionNodes[0]) && selectionNodes[0].isInline() && nodeHasAlignment(selectionNodes[0])) {
24         selectionNodes[0].setAlignment(alignment);
25         $selectSingleNode(selectionNodes[0]);
26         $toggleSelection(editor);
27         return;
28     }
29
30     // Handle normal block/range alignment
31     const elements = $getBlockElementNodesInSelection(selection);
32     for (const node of elements) {
33         if (nodeHasAlignment(node)) {
34             node.setAlignment(alignment)
35         }
36     }
37     $toggleSelection(editor);
38 }
39
40 function setDirectionForSelection(context: EditorUiContext, direction: 'ltr' | 'rtl'): void {
41     const selection = getLastSelection(context.editor);
42
43     const elements = $getBlockElementNodesInSelection(selection);
44     for (const node of elements) {
45         node.setDirection(direction);
46     }
47
48     context.manager.triggerFutureStateRefresh();
49 }
50
51 export const alignLeft: EditorButtonDefinition = {
52     label: 'Align left',
53     icon: alignLeftIcon,
54     action(context: EditorUiContext) {
55         context.editor.update(() => setAlignmentForSelection(context.editor, 'left'));
56     },
57     isActive(selection: BaseSelection|null) {
58         return $selectionContainsAlignment(selection, 'left');
59     }
60 };
61
62 export const alignCenter: EditorButtonDefinition = {
63     label: 'Align center',
64     icon: alignCenterIcon,
65     action(context: EditorUiContext) {
66         context.editor.update(() => setAlignmentForSelection(context.editor, 'center'));
67     },
68     isActive(selection: BaseSelection|null) {
69         return $selectionContainsAlignment(selection, 'center');
70     }
71 };
72
73 export const alignRight: EditorButtonDefinition = {
74     label: 'Align right',
75     icon: alignRightIcon,
76     action(context: EditorUiContext) {
77         context.editor.update(() => setAlignmentForSelection(context.editor, 'right'));
78     },
79     isActive(selection: BaseSelection|null) {
80         return $selectionContainsAlignment(selection, 'right');
81     }
82 };
83
84 export const alignJustify: EditorButtonDefinition = {
85     label: 'Align justify',
86     icon: alignJustifyIcon,
87     action(context: EditorUiContext) {
88         context.editor.update(() => setAlignmentForSelection(context.editor, 'justify'));
89     },
90     isActive(selection: BaseSelection|null) {
91         return $selectionContainsAlignment(selection, 'justify');
92     }
93 };
94
95 export const directionLTR: EditorButtonDefinition = {
96     label: 'Left to right',
97     icon: ltrIcon,
98     action(context: EditorUiContext) {
99         context.editor.update(() => setDirectionForSelection(context, 'ltr'));
100     },
101     isActive(selection: BaseSelection|null) {
102         return $selectionContainsDirection(selection, 'ltr');
103     }
104 };
105
106 export const directionRTL: EditorButtonDefinition = {
107     label: 'Right to left',
108     icon: rtlIcon,
109     action(context: EditorUiContext) {
110         context.editor.update(() => setDirectionForSelection(context, 'rtl'));
111     },
112     isActive(selection: BaseSelection|null) {
113         return $selectionContainsDirection(selection, 'rtl');
114     }
115 };