From 1c4213465bcf12385fa18f96cb6d08b80e25d618 Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Fri, 12 May 2023 13:48:14 -0700 Subject: [PATCH] Better handle multiline formatting --- ts/components/CompositionInput.tsx | 35 +++++------------------------- ts/quill/formatting/menu.tsx | 6 ++++- ts/quill/util.ts | 5 +++++ 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/ts/components/CompositionInput.tsx b/ts/components/CompositionInput.tsx index fdefa78e4d78..3e77b2842a8d 100644 --- a/ts/components/CompositionInput.tsx +++ b/ts/components/CompositionInput.tsx @@ -836,6 +836,12 @@ export function CompositionInput(props: Props): React.ReactElement { return; } setIsMouseDown(true); + + const onMouseUp = () => { + setIsMouseDown(false); + window.removeEventListener('mouseup', onMouseUp); + }; + window.addEventListener('mouseup', onMouseUp); } catch (error) { log.error( 'CompositionInput.onMouseDown: Failed to check event target', @@ -846,32 +852,6 @@ export function CompositionInput(props: Props): React.ReactElement { }, [setIsMouseDown] ); - const onMouseUp = React.useCallback( - () => setIsMouseDown(false), - [setIsMouseDown] - ); - const onMouseOut = React.useCallback( - event => { - const target = event.target as HTMLElement; - try { - // We get mouseout events for child objects of this one; filter 'em out! - if (!target.classList.contains(getClassName('__input'))) { - return; - } - setIsMouseDown(false); - } catch (error) { - log.error( - 'CompositionInput.onMouseOut: Failed to check class list', - Errors.toLogFormat(error) - ); - } - }, - [getClassName, setIsMouseDown] - ); - const onBlur = React.useCallback( - () => setIsMouseDown(false), - [setIsMouseDown] - ); return ( @@ -884,9 +864,6 @@ export function CompositionInput(props: Props): React.ReactElement { data-testid="CompositionInput" data-enabled={disabled ? 'false' : 'true'} onMouseDown={onMouseDown} - onMouseUp={onMouseUp} - onMouseOut={onMouseOut} - onBlur={onBlur} > {draftEditMessage && (
diff --git a/ts/quill/formatting/menu.tsx b/ts/quill/formatting/menu.tsx index 49abe7cc6f2a..d46b1e2c67bd 100644 --- a/ts/quill/formatting/menu.tsx +++ b/ts/quill/formatting/menu.tsx @@ -249,7 +249,11 @@ export class FormattingMenu { return; } const contents = this.quill.getContents(selection.index, selection.length); - return contents.ops.every(op => op.attributes?.[style]); + + // Note: we special-case single \n ops because Quill doesn't apply formatting to them + return contents.ops.every( + op => op.attributes?.[style] || op.insert === '\n' + ); } toggleForStyle(style: QuillFormattingStyle, context?: KeyboardContext): void { diff --git a/ts/quill/util.ts b/ts/quill/util.ts index e3774da0cbfd..905a6321981a 100644 --- a/ts/quill/util.ts +++ b/ts/quill/util.ts @@ -165,6 +165,11 @@ export const getTextAndRangesFromOps = ( }; const preTrimText = ops.reduce((acc, op) => { + // We special-case single-newline ops because Quill doesn't apply styles to them + if (op.insert === '\n') { + return acc + op.insert; + } + // Start or finish format sections as needed formats = extractAllFormats(startingBodyRanges, formats, acc.length, op);