diff --git a/src/components/atoms/CustomizedMarkdownPreviewer.tsx b/src/components/atoms/CustomizedMarkdownPreviewer.tsx index 6564dbc129..4c50361d27 100644 --- a/src/components/atoms/CustomizedMarkdownPreviewer.tsx +++ b/src/components/atoms/CustomizedMarkdownPreviewer.tsx @@ -7,11 +7,13 @@ import { ObjectMap, Attachment } from '../../lib/db/types' interface CustomizedMarkdownPreviewer { content: string attachmentMap?: ObjectMap + updateContent: (newValue: string) => void } const CustomizedMarkdownPreviewer = ({ content, attachmentMap, + updateContent, }: CustomizedMarkdownPreviewer) => { const { preferences } = usePreferences() const { previewStyle } = usePreviewStyle() @@ -23,6 +25,7 @@ const CustomizedMarkdownPreviewer = ({ codeBlockTheme={preferences['markdown.codeBlockTheme']} theme={preferences['general.theme']} style={previewStyle} + updateContent={updateContent} /> ) } diff --git a/src/components/atoms/MarkdownPreviewer.tsx b/src/components/atoms/MarkdownPreviewer.tsx index 309e83da71..b341133f02 100644 --- a/src/components/atoms/MarkdownPreviewer.tsx +++ b/src/components/atoms/MarkdownPreviewer.tsx @@ -163,6 +163,7 @@ interface MarkdownPreviewerProps { style?: string theme?: string attachmentMap?: ObjectMap + updateContent: (newValue: string) => void } const MarkdownPreviewer = ({ @@ -171,6 +172,7 @@ const MarkdownPreviewer = ({ style, theme, attachmentMap = {}, + updateContent, }: MarkdownPreviewerProps) => { const forceUpdate = useForceUpdate() const [rendering, setRendering] = useState(false) @@ -180,6 +182,47 @@ const MarkdownPreviewer = ({ const markdownProcessor = useMemo(() => { const options = { codeBlockTheme } + let checkboxIndexes = 0 + + const renderInput = (props: React.HTMLProps) => { + const onChange = (e: React.ChangeEvent) => { + const lines = content.split('\n') + const id = e.target.getAttribute('id') + if (id === null) return + const checkboxIndex = Number(id.replace(/^checkbox|(\[|\])/gi, '')) + + let current = 0 + + for (let index = 0; index < lines.length; index++) { + const line = lines[index] + // Matches both checked + unchecked + const matches = line.match(/^(\s*>?)*\s*[+\-*] (\[x]|\[ ])/i) + if (matches) { + if (current === checkboxIndex) { + const isChecked = /^(\s*>?)*\s*[+\-*] \[x]/i.test(matches[0]) + lines[index] = line.replace( + isChecked ? '[x]' : '[ ]', + isChecked ? '[ ]' : '[x]' + ) + // Bail out early since we're done + break + } else { + current++ + } + } + } + updateContent(lines.join('\n')) + } + return ( + + ) + } return unified() .use(remarkParse) @@ -219,9 +262,10 @@ const MarkdownPreviewer = ({ ) }, + input: renderInput, }, }) - }, [codeBlockTheme, attachmentMap]) + }, [codeBlockTheme, attachmentMap, content, updateContent]) const renderContent = useCallback( async (content: string) => { diff --git a/src/components/organisms/NoteDetail/NoteDetail.tsx b/src/components/organisms/NoteDetail/NoteDetail.tsx index bc53c42a7d..bacc07f76c 100644 --- a/src/components/organisms/NoteDetail/NoteDetail.tsx +++ b/src/components/organisms/NoteDetail/NoteDetail.tsx @@ -473,6 +473,7 @@ export default class NoteDetail extends React.Component< )