FormattingMenu.res

 1open Tiptap
 2
 3let submenu = Preact.Signal.make(false)
 4
 5@jsx.component
 6let make = (~doc: string) => {
 7  let btn = [
 8    "p-1 bg-[var(--color-paper)]",
 9    "hover:bg-[var(--color-bg-2)]",
10    "rounded-sm",
11    "cursor-pointer",
12    "text-sm box-border",
13  ]
14
15  let toggle = (mark: string) => {
16    switch State.Editor.get(doc) {
17    | Some(editor) => {
18        let editorState = editor->Tiptap.state
19        let selection = editorState.selection
20        if !selection.empty {
21          editor->Tiptap.Commands.toggleMark(mark)
22          editor->Tiptap.Commands.setTextSelectionToPosition(selection.to)
23        }
24      }
25    | None => ()
26    }
27  }
28
29  let remove = () => {
30    switch State.Editor.get(doc) {
31    | Some(editor) => {
32        let editorState = editor->Tiptap.state
33        let selection = editorState.selection
34        if !selection.empty {
35          editor->Tiptap.Commands.unsetAllMarks
36          editor->Tiptap.Commands.setTextSelectionToPosition(selection.to)
37        }
38      }
39    | None => ()
40    }
41  }
42
43  let heading = (level: int) => {
44    switch State.Editor.get(doc) {
45    | Some(editor) => {
46        let editorState = editor->Tiptap.state
47        let selection = editorState.selection
48        if !selection.empty {
49          editor->Tiptap.Commands.toggleHeading({"level": level})
50          editor->Tiptap.Commands.setTextSelectionToPosition(selection.to)
51        }
52      }
53    | None => ()
54    }
55  }
56
57  <Editor.BubbleMenu
58    className="p-[2px] ring-2 ring-[var(--color-blue)] rounded-sm cursor-pointer box-border"
59  >
60    <button
61      className={btn->Array.join(" ")}
62      onClick={_evt => submenu->Preact.Signal.set(!(submenu->Preact.Signal.get))}
63    >
64      <div className="flex flex-row">
65        <Icons.Heading className="p-[2px]" />
66        <Icons.Triangle className="w-2 rotate-90" />
67      </div>
68    </button>
69    {submenu->Preact.Signal.get
70      ? <>
71          <button className={btn->Array.join(" ")} onClick={_evt => heading(1)}>
72            <Icons.Heading1 className="p-[3px]" />
73          </button>
74          <button className={btn->Array.join(" ")} onClick={_evt => heading(2)}>
75            <Icons.Heading2 className="p-[3px]" />
76          </button>
77          <button className={btn->Array.join(" ")} onClick={_evt => heading(3)}>
78            <Icons.Heading3 className="p-[3px]" />
79          </button>
80          <button className={btn->Array.join(" ")} onClick={_evt => heading(4)}>
81            <Icons.Heading4 className="p-[3px]" />
82          </button>
83        </>
84      : <>
85          <button className={btn->Array.join(" ")} onClick={_evt => toggle("bold")}>
86            <Icons.Bold className="p-[2px]" />
87          </button>
88          <button className={btn->Array.join(" ")} onClick={_evt => toggle("italic")}>
89            <Icons.Italic className="p-[2px]" />
90          </button>
91          <button className={btn->Array.join(" ")} onClick={_evt => toggle("underline")}>
92            <Icons.Underline className="p-[2px]" />
93          </button>
94          <button className={btn->Array.join(" ")} onClick={_evt => remove()}>
95            <Icons.RemoveFormatting className="p-[2px]" />
96          </button>
97        </>}
98  </Editor.BubbleMenu>
99}