From 5f7cb35ec4c3ce5021e1cf70f0065ba029f3a977 Mon Sep 17 00:00:00 2001 From: Fabrizio Bertoglio Date: Sun, 4 Feb 2024 09:54:56 +0800 Subject: [PATCH 1/2] add back postinstall --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4619a5b..d31f21c 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "prepare": "bob build", "release": "release-it", "patch": "node src/patch.js", - "patch-dev": "node src/patch-dev.js" + "patch-dev": "node src/patch-dev.js", + "postinstall": "yarn patch-dev" }, "keywords": [ "react-native", From d4b55c819e5e749500e2503284e1e5ac8074e4aa Mon Sep 17 00:00:00 2001 From: Fabrizio Bertoglio Date: Thu, 29 Feb 2024 14:51:57 +0800 Subject: [PATCH 2/2] changes requested in code review --- .../text/ReactTextViewImprovedShadowNode.java | 52 +++-- example/src/RNTesterAppShared.js | 210 ++---------------- 2 files changed, 54 insertions(+), 208 deletions(-) diff --git a/android/src/main/java/com/text/ReactTextViewImprovedShadowNode.java b/android/src/main/java/com/text/ReactTextViewImprovedShadowNode.java index 6dc17d9..01dddc3 100644 --- a/android/src/main/java/com/text/ReactTextViewImprovedShadowNode.java +++ b/android/src/main/java/com/text/ReactTextViewImprovedShadowNode.java @@ -5,13 +5,21 @@ */ package com.text; +import static android.text.Layout.BREAK_STRATEGY_HIGH_QUALITY; +import static android.text.Layout.BREAK_STRATEGY_SIMPLE; +import static android.text.Layout.HYPHENATION_FREQUENCY_NONE; + +import android.graphics.text.LineBreaker; import android.os.Build; import android.text.BoringLayout; import android.text.Layout; import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; +import android.text.TextUtils; import android.view.Gravity; import androidx.annotation.Nullable; import com.facebook.infer.annotation.Assertions; @@ -42,6 +50,9 @@ import com.facebook.yoga.YogaMeasureOutput; import com.facebook.yoga.YogaNode; import java.util.ArrayList; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ReactTextViewImprovedShadowNode extends ReactTextShadowNode { // It's important to pass the ANTI_ALIAS_FLAG flag to the constructor rather than setting it @@ -128,13 +139,17 @@ public long measure( if (widthMode == YogaMeasureMode.EXACTLY) { layoutWidth = width; } else { - for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) { - boolean endsWithNewLine = - text.length() > 0 && text.charAt(layout.getLineEnd(lineIndex) - 1) == '\n'; - float lineWidth = - endsWithNewLine ? layout.getLineMax(lineIndex) : layout.getLineWidth(lineIndex); - if (lineWidth > layoutWidth) { - layoutWidth = lineWidth; + if (lineCount == 1) { + layoutWidth = (int) layout.getEllipsizedWidth(); + } else { + for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) { + boolean endsWithNewLine = + text.length() > 0 && text.charAt(layout.getLineEnd(lineIndex) - 1) == '\n'; + float lineWidth = + endsWithNewLine ? layout.getLineMax(lineIndex) : layout.getLineWidth(lineIndex); + if (lineWidth > layoutWidth) { + layoutWidth = lineWidth; + } } } if (widthMode == YogaMeasureMode.AT_MOST && layoutWidth > width) { @@ -195,11 +210,6 @@ private Layout measureSpannedText(Spannable text, float width, YogaMeasureMode w Layout layout; BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint); float desiredWidth = boring == null ? Layout.getDesiredWidth(text, textPaint) : Float.NaN; - // StaticLayout#getLineWidth does not work with single-line text. - boolean overrideTextBreakStrategySingleLine = - boring == null - ? false - : mNumberOfLines == 1 && !mAdjustsFontSizeToFit && boring.width > width; // technically, width should never be negative, but there is currently a bug in boolean unconstrainedWidth = widthMode == YogaMeasureMode.UNDEFINED || width < 0; @@ -240,7 +250,7 @@ private Layout measureSpannedText(Spannable text, float width, YogaMeasureMode w layout = builder.build(); } else if (boring != null - && (unconstrainedWidth || boring.width <= width || overrideTextBreakStrategySingleLine)) { + && (unconstrainedWidth || boring.width <= width)) { // Is used for single-line, boring text when the width is either unknown or bigger // than the width of the text. layout = @@ -261,15 +271,13 @@ private Layout measureSpannedText(Spannable text, float width, YogaMeasureMode w if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) { width = (float) Math.ceil(width); } - - StaticLayout.Builder builder = - StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, (int) width) - .setAlignment(alignment) - .setLineSpacing(0.f, 1.f) - .setIncludePad(mIncludeFontPadding) - .setBreakStrategy(mTextBreakStrategy) - .setHyphenationFrequency(mHyphenationFrequency); - + StaticLayout.Builder builder = + StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, (int) width) + .setAlignment(alignment) + .setLineSpacing(0.f, 1.f) + .setIncludePad(mIncludeFontPadding) + .setBreakStrategy(mTextBreakStrategy) + .setHyphenationFrequency(mHyphenationFrequency); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { builder.setUseLineSpacingFromFallbacks(true); } diff --git a/example/src/RNTesterAppShared.js b/example/src/RNTesterAppShared.js index 3cd8e9d..ee7a543 100644 --- a/example/src/RNTesterAppShared.js +++ b/example/src/RNTesterAppShared.js @@ -1,200 +1,38 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -import {RNTesterEmptyBookmarksState} from './components/RNTesterEmptyBookmarksState'; -import RNTesterModuleContainer from './components/RNTesterModuleContainer'; -import RNTesterModuleList from './components/RNTesterModuleList'; -import RNTesterNavBar, {navBarHeight} from './components/RNTesterNavbar'; -import {RNTesterThemeContext, themes} from './components/RNTesterTheme'; -import RNTTitleBar from './components/RNTTitleBar'; -import RNTesterList from './utils/RNTesterList'; -import { - RNTesterNavigationActionsType, - RNTesterNavigationReducer, -} from './utils/RNTesterNavigationReducer'; -import { - Screens, - getExamplesListWithBookmarksAndRecentlyUsed, - initialNavigationState, -} from './utils/testerStateUtils'; import * as React from 'react'; -import {BackHandler, StyleSheet, View, useColorScheme} from 'react-native'; - -// RNTester App currently uses in memory storage for storing navigation state - -const RNTesterApp = (): React.Node => { - const [state, dispatch] = React.useReducer( - RNTesterNavigationReducer, - initialNavigationState, - ); - const colorScheme = useColorScheme(); - - const { - activeModuleKey, - activeModuleTitle, - activeModuleExampleKey, - screen, - bookmarks, - recentlyUsed, - } = state; - - const examplesList = React.useMemo( - () => - getExamplesListWithBookmarksAndRecentlyUsed({bookmarks, recentlyUsed}), - [bookmarks, recentlyUsed], - ); - - const handleBackPress = React.useCallback(() => { - if (activeModuleKey != null) { - dispatch({type: RNTesterNavigationActionsType.BACK_BUTTON_PRESS}); - } - }, [dispatch, activeModuleKey]); - - // Setup hardware back button press listener - React.useEffect(() => { - const handleHardwareBackPress = () => { - if (activeModuleKey) { - handleBackPress(); - return true; - } - return false; - }; - - BackHandler.addEventListener('hardwareBackPress', handleHardwareBackPress); - - return () => { - BackHandler.removeEventListener( - 'hardwareBackPress', - handleHardwareBackPress, - ); - }; - }, [activeModuleKey, handleBackPress]); - - const handleModuleCardPress = React.useCallback( - ({exampleType, key, title}: any) => { - dispatch({ - type: RNTesterNavigationActionsType.MODULE_CARD_PRESS, - data: {exampleType, key, title}, - }); - }, - [dispatch], - ); - - const handleModuleExampleCardPress = React.useCallback( - (exampleName: string) => { - dispatch({ - type: RNTesterNavigationActionsType.EXAMPLE_CARD_PRESS, - data: {key: exampleName}, - }); - }, - [dispatch], - ); - - const toggleBookmark = React.useCallback( - ({exampleType, key}: any) => { - dispatch({ - type: RNTesterNavigationActionsType.BOOKMARK_PRESS, - data: {exampleType, key}, - }); - }, - [dispatch], - ); - - const handleNavBarPress = React.useCallback( - (args: {screen: string}) => { - dispatch({ - type: RNTesterNavigationActionsType.NAVBAR_PRESS, - data: {screen: args.screen}, - }); - }, - [dispatch], - ); - - const theme = colorScheme === 'dark' ? themes.dark : themes.light; - - if (examplesList === null) { - return null; - } - const activeModule = - activeModuleKey != null ? RNTesterList.Modules[activeModuleKey] : null; - const activeModuleExample = - activeModuleExampleKey != null - ? activeModule?.examples.find(e => e.name === activeModuleExampleKey) - : null; - const title = - activeModuleTitle != null - ? activeModuleTitle - : screen === Screens.COMPONENTS - ? 'Components' - : screen === Screens.APIS - ? 'APIs' - : 'Bookmarks'; - - const activeExampleList = - screen === Screens.COMPONENTS - ? examplesList.components - : screen === Screens.APIS - ? examplesList.apis - : examplesList.bookmarks; +import { View, StyleSheet, Text, TextInput } from 'react-native'; +export default function App() { + const email = + 'From vincenzoddragon+five@gmail.com From vincenzoddrlxagon+five@gmail.com'; return ( - - - - {activeModule != null ? ( - - ) : screen === Screens.BOOKMARKS && - examplesList.bookmarks.length === 0 ? ( - - ) : ( - - )} - - - + <> + + + + {email} + + - + ); -}; - -export default RNTesterApp; +} const styles = StyleSheet.create({ container: { flex: 1, + justifyContent: 'center', + padding: 8, + backgroundColor: 'yellow', }, - bottomNavbar: { - height: navBarHeight, + flexBrokenStyle: { + flexDirection: 'row', }, - hidden: { - display: 'none', + parentText: { + backgroundColor: 'red', }, });