a tool for shared writing and social publishing
at debug/datetime 73 lines 2.3 kB view raw
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}