7 files changed,
+111,
-96
+3,
-1
1@@ -128,7 +128,9 @@ function App(props) {
2 JsxRuntime.jsx(FloatingMenu.make, {
3 doc: doc
4 }),
5- JsxRuntime.jsx(FormattingMenu.make, {})
6+ JsxRuntime.jsx(FormattingMenu.make, {
7+ doc: doc
8+ })
9 ],
10 disabled: Primitive_option.some(minimized),
11 hidden: Primitive_option.some(minimized),
+47,
-56
1@@ -1,63 +1,16 @@
2 // Generated by ReScript, PLEASE EDIT WITH CARE
3
4+import * as State from "../State.res.mjs";
5 import * as LucidePreact from "lucide-preact";
6 import * as Signals from "@preact/signals";
7+import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
8 import * as JsxRuntime from "preact/jsx-runtime";
9 import * as Menus from "@tiptap/react/menus";
10
11-let state = {
12- editor: null,
13- range: null
14-};
15-
16-function setEditor(e, from, to) {
17- state.editor = e;
18- state.range = {
19- from: from,
20- to: to
21- };
22- if (to > from && e.isFocused) {
23- return e.isEditable;
24- } else {
25- return false;
26- }
27-}
28-
29-function toggle(mark) {
30- let match = state.editor;
31- let match$1 = state.range;
32- if (!(match == null) && !(match$1 == null)) {
33- match.commands.toggleMark(mark);
34- match.commands.setTextSelection(match$1.to);
35- return;
36- }
37-}
38-
39-function remove() {
40- let match = state.editor;
41- let match$1 = state.range;
42- if (!(match == null) && !(match$1 == null)) {
43- match.commands.unsetAllMarks();
44- match.commands.setTextSelection(match$1.to);
45- return;
46- }
47-}
48-
49-function heading(level) {
50- let match = state.editor;
51- let match$1 = state.range;
52- if (!(match == null) && !(match$1 == null)) {
53- match.commands.toggleHeading({
54- level: level
55- });
56- match.commands.setTextSelection(match$1.to);
57- return;
58- }
59-}
60-
61 let submenu = Signals.signal(false);
62
63 function FormattingMenu(props) {
64+ let doc = props.doc;
65 let btn = [
66 "p-1 bg-[var(--color-paper)]",
67 "hover:bg-[var(--color-bg-2)]",
68@@ -65,8 +18,51 @@ function FormattingMenu(props) {
69 "cursor-pointer",
70 "text-sm box-border"
71 ];
72+ let toggle = mark => {
73+ let editor = State.Editor.get(doc);
74+ if (editor === undefined) {
75+ return;
76+ }
77+ let editor$1 = Primitive_option.valFromOption(editor);
78+ let editorState = editor$1.state;
79+ let selection = editorState.selection;
80+ if (!selection.empty) {
81+ editor$1.commands.toggleMark(mark);
82+ editor$1.commands.setTextSelection(selection.to);
83+ return;
84+ }
85+ };
86+ let remove = () => {
87+ let editor = State.Editor.get(doc);
88+ if (editor === undefined) {
89+ return;
90+ }
91+ let editor$1 = Primitive_option.valFromOption(editor);
92+ let editorState = editor$1.state;
93+ let selection = editorState.selection;
94+ if (!selection.empty) {
95+ editor$1.commands.unsetAllMarks();
96+ editor$1.commands.setTextSelection(selection.to);
97+ return;
98+ }
99+ };
100+ let heading = level => {
101+ let editor = State.Editor.get(doc);
102+ if (editor === undefined) {
103+ return;
104+ }
105+ let editor$1 = Primitive_option.valFromOption(editor);
106+ let editorState = editor$1.state;
107+ let selection = editorState.selection;
108+ if (!selection.empty) {
109+ editor$1.commands.toggleHeading({
110+ level: level
111+ });
112+ editor$1.commands.setTextSelection(selection.to);
113+ return;
114+ }
115+ };
116 return JsxRuntime.jsxs(Menus.BubbleMenu, {
117- shouldShow: evt => setEditor(evt.editor, evt.from, evt.to),
118 className: "p-[2px] ring-2 ring-[var(--color-blue)] rounded-sm cursor-pointer box-border",
119 children: [
120 JsxRuntime.jsx("button", {
121@@ -156,11 +152,6 @@ function FormattingMenu(props) {
122 let make = FormattingMenu;
123
124 export {
125- state,
126- setEditor,
127- toggle,
128- remove,
129- heading,
130 submenu,
131 make,
132 }
1@@ -233,7 +233,7 @@ function Summary(props) {
2 ],
3 className: "flex flex-row justify-between"
4 }),
5- className: Preact.cls("fixed box-border bottom-0 left-0 w-full max-w-(--sheet-width) rounded-sm shadow-xl", {
6+ className: Preact.cls("fixed box-border bottom-0 left-0 w-[100cqw] rounded-sm shadow-xl", {
7 "border-t-2 border-gray-300": !Panel.isMinimized.value
8 }),
9 id: `summary-` + doc
+1,
-1
1@@ -100,7 +100,7 @@ let make = (~doc: string) => {
2 <Editor doc={doc} disabled={minimized} hidden={minimized} className="w-full h-full">
3 <Editor.Content />
4 <FloatingMenu doc={doc} />
5- <FormattingMenu />
6+ <FormattingMenu doc={doc} />
7 </Editor>
8 </Panel>
9 </>
+13,
-0
1@@ -91,6 +91,19 @@ external isFocused: t => bool = "isFocused"
2 @get
3 external isDestroyed: t => bool = "isDestroyed"
4
5+// Access editor state and current selection
6+// Used by formatting actions that need to read the live selection range
7+type selection = {
8+ from: int,
9+ to: int,
10+ empty: bool,
11+}
12+
13+type editorState = {selection: selection}
14+
15+@get
16+external state: t => editorState = "state"
17+
18 // Focus and blur commands are in the Commands module
19
20 // Set the editable state
+45,
-36
1@@ -1,42 +1,9 @@
2-type t = {mutable editor: nullable<Editor.t>, mutable range: nullable<{from: int, to: int}>}
3-let state = {editor: Nullable.null, range: Nullable.null}
4-let setEditor = (e: Editor.t, from: int, to: int) => {
5- state.editor = Nullable.make(e)
6- state.range = Nullable.make({from, to})
7- to > from && e->Tiptap.isFocused && e->Tiptap.isEditable
8-}
9-let toggle = (mark: string) => {
10- switch (state.editor->Nullable.toOption, state.range->Nullable.toOption) {
11- | (Some(e), Some(range)) => {
12- e->Tiptap.Commands.toggleMark(mark)
13- e->Tiptap.Commands.setTextSelectionToPosition(range.to)
14- }
15- | (_, _) => ()
16- }
17-}
18-let remove = () => {
19- switch (state.editor->Nullable.toOption, state.range->Nullable.toOption) {
20- | (Some(e), Some(range)) => {
21- e->Tiptap.Commands.unsetAllMarks
22- e->Tiptap.Commands.setTextSelectionToPosition(range.to)
23- }
24- | (_, _) => ()
25- }
26-}
27-let heading = (level: int) => {
28- switch (state.editor->Nullable.toOption, state.range->Nullable.toOption) {
29- | (Some(e), Some(range)) => {
30- e->Tiptap.Commands.toggleHeading({"level": level})
31- e->Tiptap.Commands.setTextSelectionToPosition(range.to)
32- }
33- | (_, _) => ()
34- }
35-}
36+open Tiptap
37
38 let submenu = Preact.Signal.make(false)
39
40 @jsx.component
41-let make = () => {
42+let make = (~doc: string) => {
43 let btn = [
44 "p-1 bg-[var(--color-paper)]",
45 "hover:bg-[var(--color-bg-2)]",
46@@ -44,8 +11,50 @@ let make = () => {
47 "cursor-pointer",
48 "text-sm box-border",
49 ]
50+
51+ let toggle = (mark: string) => {
52+ switch State.Editor.get(doc) {
53+ | Some(editor) => {
54+ let editorState = editor->Tiptap.state
55+ let selection = editorState.selection
56+ if !selection.empty {
57+ editor->Tiptap.Commands.toggleMark(mark)
58+ editor->Tiptap.Commands.setTextSelectionToPosition(selection.to)
59+ }
60+ }
61+ | None => ()
62+ }
63+ }
64+
65+ let remove = () => {
66+ switch State.Editor.get(doc) {
67+ | Some(editor) => {
68+ let editorState = editor->Tiptap.state
69+ let selection = editorState.selection
70+ if !selection.empty {
71+ editor->Tiptap.Commands.unsetAllMarks
72+ editor->Tiptap.Commands.setTextSelectionToPosition(selection.to)
73+ }
74+ }
75+ | None => ()
76+ }
77+ }
78+
79+ let heading = (level: int) => {
80+ switch State.Editor.get(doc) {
81+ | Some(editor) => {
82+ let editorState = editor->Tiptap.state
83+ let selection = editorState.selection
84+ if !selection.empty {
85+ editor->Tiptap.Commands.toggleHeading({"level": level})
86+ editor->Tiptap.Commands.setTextSelectionToPosition(selection.to)
87+ }
88+ }
89+ | None => ()
90+ }
91+ }
92+
93 <Editor.BubbleMenu
94- shouldShow={evt => setEditor(evt.editor, evt.from, evt.to)}
95 className="p-[2px] ring-2 ring-[var(--color-blue)] rounded-sm cursor-pointer box-border"
96 >
97 <button
+1,
-1
1@@ -67,7 +67,7 @@ let make = (~doc: string) => {
2 <div
3 id={`summary-${doc}`}
4 className={Preact.cls(
5- "fixed box-border bottom-0 left-0 w-full max-w-(--sheet-width) rounded-sm shadow-xl",
6+ "fixed box-border bottom-0 left-0 w-[100cqw] rounded-sm shadow-xl",
7 dict{"border-t-2 border-gray-300": !(Panel.isMinimized->Preact.Signal.get)},
8 )}
9 >