diff --git a/src/MarkdownTextInput.web.tsx b/src/MarkdownTextInput.web.tsx index 31bda716..a20e6c25 100644 --- a/src/MarkdownTextInput.web.tsx +++ b/src/MarkdownTextInput.web.tsx @@ -101,35 +101,11 @@ const MarkdownTextInput = React.forwardRef( const history = useRef(new MarkdownInputHistory(50)); - function parseText(target: HTMLDivElement, text: string, markdownStyles: MarkdownStyle, singleLine: boolean) { - const parsedText = ParseUtils.parseText(target, text, markdownStyles, singleLine); - history.current.debouncedAdd(parsedText); - return parsedText; - } - - const undo = (target: HTMLDivElement, markdownStyles: MarkdownStyle, singleLine: boolean) => { - const text = history.current.undo(); - if (text === null) { - return target.innerText; - } - ParseUtils.parseText(target, text, markdownStyles, singleLine, true); - return text; - }; - - const redo = (target: HTMLDivElement, markdownStyles: MarkdownStyle, singleLine: boolean) => { - const text = history.current.redo(); - if (text === null) { - return target.innerText; - } - ParseUtils.parseText(target, text, markdownStyles, singleLine, true); - return text; - }; - const processedMarkdownStyle = React.useMemo(() => { const newMarkdownStyle = StyleUtils.mergeMarkdownStyleWithDefault(markdownStyle, true); if (divRef.current) { - parseText(divRef.current, divRef.current.innerText, newMarkdownStyle, !multiline); + parseText(divRef.current, divRef.current.innerText, newMarkdownStyle); } return newMarkdownStyle; }, [markdownStyle]); @@ -142,6 +118,36 @@ const MarkdownTextInput = React.forwardRef( return value; }, [value]); + const parseText = useCallback( + (target: HTMLDivElement, text: string | null, customMarkdownStyles: MarkdownStyle, shouldMoveCursorToEnd = false, shouldAddToHistory = true) => { + if (text === null) { + return target.innerText; + } + const parsedText = ParseUtils.parseText(target, text, customMarkdownStyles, !multiline, shouldMoveCursorToEnd); + if (history.current && shouldAddToHistory) { + history.current.debouncedAdd(parsedText); + } + return parsedText; + }, + [multiline], + ); + + const undo = useCallback( + (target: HTMLDivElement) => { + const text = history.current.undo(); + return parseText(target, text, processedMarkdownStyle, true, false); + }, + [processedMarkdownStyle], + ); + + const redo = useCallback( + (target: HTMLDivElement) => { + const text = history.current.redo(); + return parseText(target, text, processedMarkdownStyle, true, false); + }, + [processedMarkdownStyle], + ); + const setEventProps = useCallback((e: NativeSyntheticEvent) => { if (divRef.current) { const text = normalizeValue(divRef.current.innerText || ''); @@ -169,11 +175,11 @@ const MarkdownTextInput = React.forwardRef( let text = ''; const nativeEvent = e.nativeEvent as MarkdownNativeEvent; if (nativeEvent.inputType === 'historyUndo') { - text = undo(divRef.current, processedMarkdownStyle, !multiline); + text = undo(divRef.current); } else if (nativeEvent.inputType === 'historyRedo') { - text = redo(divRef.current, processedMarkdownStyle, !multiline); + text = redo(divRef.current); } else { - text = parseText(divRef.current, e.target.innerText, processedMarkdownStyle, !multiline); + text = parseText(divRef.current, e.target.innerText, processedMarkdownStyle); } updateTextColor(divRef.current, e.target.innerText); @@ -356,7 +362,7 @@ const MarkdownTextInput = React.forwardRef( } const text = processedValue !== null && processedValue !== undefined ? processedValue : ''; - parseText(divRef.current, text, processedMarkdownStyle, !multiline); + parseText(divRef.current, text, processedMarkdownStyle); if ((divRef.current as unknown as TextInput).isFocused()) { contentSelection.current = { start: text.length, diff --git a/src/web/historyClass.ts b/src/web/historyClass.ts index 1c75c706..5b061c50 100644 --- a/src/web/historyClass.ts +++ b/src/web/historyClass.ts @@ -35,6 +35,10 @@ export default class MarkdownInputHistory { } add(text: string): void { + if (text === this.history[this.history.length - 1]) { + return; + } + if (this.pointerIndex < this.history.length - 1) { this.history.splice(this.pointerIndex + 1); } @@ -57,22 +61,21 @@ export default class MarkdownInputHistory { return null; } - if (this.pointerIndex >= 0) { + if (this.pointerIndex > 0) { this.pointerIndex -= 1; } return this.history[this.pointerIndex] || null; } redo(): string | null { - if (this.currentlyWritten !== null && this.timeout) { - return this.currentlyWritten; - } - if (this.history.length === 0) { + if (this.history.length === 0 || (this.currentlyWritten !== null && this.timeout)) { return null; } if (this.pointerIndex < this.history.length - 1) { this.pointerIndex += 1; + } else { + return null; } return this.history[this.pointerIndex] || null; } diff --git a/src/web/parserUtils.ts b/src/web/parserUtils.ts index 8e6b95ff..a3a3a868 100644 --- a/src/web/parserUtils.ts +++ b/src/web/parserUtils.ts @@ -167,7 +167,7 @@ function parseRangesToHTMLNodes(text: string, ranges: MarkdownRange[], markdownS return root; } -function parseText(target: HTMLElement, text: string, markdownStyle: PartialMarkdownStyle = {}, disableNewLinesInCursorPositioning = false, alwaysMoveToTheEnd = false) { +function parseText(target: HTMLElement, text: string, markdownStyle: PartialMarkdownStyle = {}, disableNewLinesInCursorPositioning = false, alwaysMoveCursorToTheEnd = false) { const targetElement = target; let cursorPosition: number | null = null; @@ -195,7 +195,7 @@ function parseText(target: HTMLElement, text: string, markdownStyle: PartialMark target.appendChild(dom); } - if (alwaysMoveToTheEnd) { + if (alwaysMoveCursorToTheEnd) { CursorUtils.moveCursorToEnd(target); } else if (isFocused && cursorPosition !== null) { CursorUtils.setCursorPosition(target, cursorPosition, disableNewLinesInCursorPositioning);