From c8948f8fbb9aea1581ce48b6fc587be5676e902e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= <39538890+Skalakid@users.noreply.github.com> Date: Fri, 12 Apr 2024 10:57:50 +0200 Subject: [PATCH] Add onContentSizeChange prop (#290) --- src/MarkdownTextInput.web.tsx | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/MarkdownTextInput.web.tsx b/src/MarkdownTextInput.web.tsx index 3d39d001..891b6b9c 100644 --- a/src/MarkdownTextInput.web.tsx +++ b/src/MarkdownTextInput.web.tsx @@ -8,6 +8,7 @@ import type { TextInputProps, TextInputKeyPressEventData, TextInputFocusEventData, + TextInputContentSizeChangeEventData, } from 'react-native'; import React, {useEffect, useRef, useCallback, useMemo, useLayoutEffect} from 'react'; import type {CSSProperties, MutableRefObject, ReactEventHandler, FocusEventHandler, MouseEvent, KeyboardEvent, SyntheticEvent} from 'react'; @@ -68,6 +69,11 @@ type Selection = { end: number; }; +type Dimensions = { + width: number; + height: number; +}; + let focusTimeout: NodeJS.Timeout | null = null; // Removes one '\n' from the end of the string that were added by contentEditable div @@ -154,6 +160,7 @@ const MarkdownTextInput = React.forwardRef( style = {}, value, autoFocus = false, + onContentSizeChange, }, ref, ) => { @@ -164,6 +171,8 @@ const MarkdownTextInput = React.forwardRef( const contentSelection = useRef(null); const className = `react-native-live-markdown-input-${multiline ? 'multiline' : 'singleline'}`; const history = useRef(); + const dimensions = React.useRef(null); + if (!history.current) { history.current = new InputHistory(100); } @@ -296,6 +305,26 @@ const MarkdownTextInput = React.forwardRef( [handleSelectionChange, updateRefSelectionVariables], ); + const handleContentSizeChange = useCallback(() => { + if (!divRef.current || !multiline || !onContentSizeChange) { + return; + } + + const hostNode = (divRef.current.firstChild as HTMLElement) ?? divRef.current; + const newWidth = hostNode.offsetWidth; + const newHeight = hostNode.offsetHeight; + + if (newHeight !== dimensions.current?.height || newWidth !== dimensions.current.width) { + dimensions.current = {height: newHeight, width: newWidth}; + + onContentSizeChange({ + nativeEvent: { + contentSize: dimensions.current, + }, + } as NativeSyntheticEvent); + } + }, [multiline, onContentSizeChange]); + const handleOnChangeText = useCallback( (e: SyntheticEvent) => { if (!divRef.current || !(e.target instanceof HTMLElement)) { @@ -336,8 +365,10 @@ const MarkdownTextInput = React.forwardRef( const normalizedText = normalizeValue(text); onChangeText(normalizedText); } + + handleContentSizeChange(); }, - [updateSelection, updateTextColor, onChange, onChangeText, undo, redo, parseText, processedMarkdownStyle, setEventProps], + [updateTextColor, handleContentSizeChange, onChange, onChangeText, undo, redo, parseText, processedMarkdownStyle, updateSelection, setEventProps], ); const handleKeyPress = useCallback( @@ -552,6 +583,8 @@ const MarkdownTextInput = React.forwardRef( } const currentValue = value ?? ''; history.current.add(currentValue, currentValue.length); + + handleContentSizeChange(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []);