forked from
leaflet.pub/leaflet
a tool for shared writing and social publishing
1import { Mark, MarkType } from "prosemirror-model";
2import { useUIState } from "src/useUIState";
3import { ToolbarButton } from ".";
4import { toggleMark } from "prosemirror-commands";
5import { TextSelection } from "prosemirror-state";
6import { useEditorStates } from "src/state/useEditorState";
7import { rangeHasMark } from "src/utils/prosemirror/rangeHasMark";
8import { ShortcutKey } from "components/Layout";
9import { setMark } from "src/utils/prosemirror/setMark";
10
11export function TextDecorationButton(props: {
12 mark: MarkType;
13 attrs?: any;
14 icon: React.ReactNode;
15 tooltipContent: React.ReactNode;
16}) {
17 let focusedBlock = useUIState((s) => s.focusedEntity);
18 let focusedEditor = useEditorStates((s) =>
19 focusedBlock ? s.editorStates[focusedBlock.entityID] : null,
20 );
21 let hasMark: boolean = false;
22 let mark: Mark | null = null;
23 if (focusedEditor) {
24 let { to, from, $cursor, $to, $from } = focusedEditor.editor
25 .selection as TextSelection;
26
27 mark = rangeHasMark(focusedEditor.editor, props.mark, from, to);
28 if ($cursor)
29 hasMark = !!props.mark.isInSet(
30 focusedEditor.editor.storedMarks || $cursor.marks(),
31 );
32 else {
33 hasMark = !!mark;
34 }
35 }
36
37 return (
38 <ToolbarButton
39 active={hasMark}
40 onClick={(e) => {
41 e.preventDefault();
42 e.stopPropagation();
43 toggleMarkInFocusedBlock(props.mark, props.attrs);
44 }}
45 tooltipContent={props.tooltipContent}
46 >
47 {props.icon}
48 </ToolbarButton>
49 );
50}
51
52export function toggleMarkInFocusedBlock(markT: MarkType, attrs?: any) {
53 let focusedBlock = useUIState.getState().focusedEntity;
54 let editor = focusedBlock
55 ? useEditorStates.getState().editorStates[focusedBlock?.entityID]
56 : null;
57 if (!editor) return;
58 let { view } = editor;
59 let { to, from, $cursor, $to, $from } = view.state.selection as TextSelection;
60 let mark = rangeHasMark(view.state, markT, from, to);
61 if (
62 to === from &&
63 markT?.isInSet(view.state.storedMarks || $cursor?.marks() || [])
64 ) {
65 return toggleMark(markT, attrs)(view.state, view.dispatch);
66 }
67 if (
68 mark &&
69 (!attrs || JSON.stringify(attrs) === JSON.stringify(mark.attrs))
70 ) {
71 toggleMark(markT, attrs)(view.state, view.dispatch);
72 } else setMark(markT, attrs)(view.state, view.dispatch);
73}