From fdfcb76b41bf1d96bc175bf17f5a14df2e3af008 Mon Sep 17 00:00:00 2001 From: bang9dev Date: Tue, 30 Mar 2021 22:18:45 +0900 Subject: [PATCH 1/6] feat: added line break strategy attribute and example --- .../TextInput/RCTTextInputViewConfig.js | 1 + Libraries/Components/TextInput/TextInput.js | 6 +++ .../Text/BaseText/RCTBaseTextViewManager.m | 1 + Libraries/Text/RCTTextAttributes.h | 1 + Libraries/Text/RCTTextAttributes.m | 11 +++++- Libraries/Text/TextNativeComponent.js | 1 + Libraries/Text/TextProps.js | 7 ++++ React/Base/RCTConvert.h | 1 + React/Base/RCTConvert.m | 32 +++++++++++++++ .../js/examples/Text/TextExample.ios.js | 37 ++++++++++++++++++ .../TextInput/TextInputExample.ios.js | 39 +++++++++++++++++++ 11 files changed, 136 insertions(+), 1 deletion(-) diff --git a/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/Libraries/Components/TextInput/RCTTextInputViewConfig.js index 1962d095693e..c428518d8d4c 100644 --- a/Libraries/Components/TextInput/RCTTextInputViewConfig.js +++ b/Libraries/Components/TextInput/RCTTextInputViewConfig.js @@ -149,6 +149,7 @@ const RCTTextInputViewConfig = { clearTextOnFocus: true, showSoftInputOnFocus: true, autoFocus: true, + ios_lineBreakStrategy: true, ...ConditionallyIgnoredEventHandlers({ onChange: true, onSelectionChange: true, diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index be6cab34a348..197414da7ade 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -352,6 +352,12 @@ type IOSProps = $ReadOnly<{| * @platform ios */ textContentType?: ?TextContentType, + + /** + * Set line break strategy on iOS. + * @platform ios + */ + ios_lineBreakStrategy?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), |}>; type AndroidProps = $ReadOnly<{| diff --git a/Libraries/Text/BaseText/RCTBaseTextViewManager.m b/Libraries/Text/BaseText/RCTBaseTextViewManager.m index fee8647bab15..6377a9075f82 100644 --- a/Libraries/Text/BaseText/RCTBaseTextViewManager.m +++ b/Libraries/Text/BaseText/RCTBaseTextViewManager.m @@ -42,6 +42,7 @@ - (RCTShadowView *)shadowView RCT_REMAP_SHADOW_PROPERTY(lineHeight, textAttributes.lineHeight, CGFloat) RCT_REMAP_SHADOW_PROPERTY(textAlign, textAttributes.alignment, NSTextAlignment) RCT_REMAP_SHADOW_PROPERTY(writingDirection, textAttributes.baseWritingDirection, NSWritingDirection) +RCT_REMAP_SHADOW_PROPERTY(ios_lineBreakStrategy, textAttributes.lineBreakStrategy, NSLineBreakStrategy) // Decoration RCT_REMAP_SHADOW_PROPERTY(textDecorationColor, textAttributes.textDecorationColor, UIColor) RCT_REMAP_SHADOW_PROPERTY(textDecorationStyle, textAttributes.textDecorationStyle, NSUnderlineStyle) diff --git a/Libraries/Text/RCTTextAttributes.h b/Libraries/Text/RCTTextAttributes.h index a95536d1b671..3491d598971b 100644 --- a/Libraries/Text/RCTTextAttributes.h +++ b/Libraries/Text/RCTTextAttributes.h @@ -41,6 +41,7 @@ extern NSString *const RCTTextAttributesTagAttributeName; @property (nonatomic, assign) CGFloat lineHeight; @property (nonatomic, assign) NSTextAlignment alignment; @property (nonatomic, assign) NSWritingDirection baseWritingDirection; +@property (nonatomic, assign) NSLineBreakStrategy lineBreakStrategy; // Decoration @property (nonatomic, strong, nullable) UIColor *textDecorationColor; @property (nonatomic, assign) NSUnderlineStyle textDecorationStyle; diff --git a/Libraries/Text/RCTTextAttributes.m b/Libraries/Text/RCTTextAttributes.m index 1fa15be2a5f8..e62ae29416d3 100644 --- a/Libraries/Text/RCTTextAttributes.m +++ b/Libraries/Text/RCTTextAttributes.m @@ -27,6 +27,7 @@ - (instancetype)init _maxFontSizeMultiplier = NAN; _alignment = NSTextAlignmentNatural; _baseWritingDirection = NSWritingDirectionNatural; + _lineBreakStrategy = NSLineBreakStrategyNone; _textShadowRadius = NAN; _opacity = NAN; _textTransform = RCTTextTransformUndefined; @@ -66,6 +67,7 @@ - (void)applyTextAttributes:(RCTTextAttributes *)textAttributes _baseWritingDirection = textAttributes->_baseWritingDirection != NSWritingDirectionNatural ? textAttributes->_baseWritingDirection : _baseWritingDirection; // * + _lineBreakStrategy = textAttributes->_lineBreakStrategy != NSLineBreakStrategyNone ? textAttributes->_lineBreakStrategy : _lineBreakStrategy; // Decoration _textDecorationColor = textAttributes->_textDecorationColor ?: _textDecorationColor; @@ -117,6 +119,13 @@ - (NSParagraphStyle *)effectiveParagraphStyle isParagraphStyleUsed = YES; } + if (_lineBreakStrategy != NSLineBreakStrategyNone) { + if (@available(iOS 14.0, *)) { + paragraphStyle.lineBreakStrategy = _lineBreakStrategy; + isParagraphStyleUsed = YES; + } + } + if (!isnan(_lineHeight)) { CGFloat lineHeight = _lineHeight * self.effectiveFontSizeMultiplier; paragraphStyle.minimumLineHeight = lineHeight; @@ -318,7 +327,7 @@ - (BOOL)isEqual:(RCTTextAttributes *)textAttributes RCTTextAttributesCompareFloats(_letterSpacing) && // Paragraph Styles RCTTextAttributesCompareFloats(_lineHeight) && RCTTextAttributesCompareFloats(_alignment) && - RCTTextAttributesCompareOthers(_baseWritingDirection) && + RCTTextAttributesCompareOthers(_baseWritingDirection) && RCTTextAttributesCompareOthers(_lineBreakStrategy) && // Decoration RCTTextAttributesCompareObjects(_textDecorationColor) && RCTTextAttributesCompareOthers(_textDecorationStyle) && RCTTextAttributesCompareOthers(_textDecorationLine) && diff --git a/Libraries/Text/TextNativeComponent.js b/Libraries/Text/TextNativeComponent.js index 22b29bfbab15..c1eda7b5024e 100644 --- a/Libraries/Text/TextNativeComponent.js +++ b/Libraries/Text/TextNativeComponent.js @@ -45,6 +45,7 @@ const textViewConfig = { onInlineViewLayout: true, dataDetectorType: true, android_hyphenationFrequency: true, + ios_lineBreakStrategy: true, }, directEventTypes: { topTextLayout: { diff --git a/Libraries/Text/TextProps.js b/Libraries/Text/TextProps.js index 16e4f87b25cc..8e4b8127f866 100644 --- a/Libraries/Text/TextProps.js +++ b/Libraries/Text/TextProps.js @@ -236,4 +236,11 @@ export type TextProps = $ReadOnly<{| * See https://reactnative.dev/docs/text#supperhighlighting */ suppressHighlighting?: ?boolean, + + /** + * Set line break strategy on iOS. + * + * See https://reactnative.dev/docs/text.html#ios_linebreakstrategy + */ + ios_lineBreakStrategy?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), |}>; diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index ad92515fd584..7a7cc75ebdce 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -65,6 +65,7 @@ typedef NSURL RCTFileURL; + (NSTextAlignment)NSTextAlignment:(id)json; + (NSUnderlineStyle)NSUnderlineStyle:(id)json; + (NSWritingDirection)NSWritingDirection:(id)json; ++ (NSLineBreakStrategy)NSLineBreakStrategy:(id)json; + (UITextAutocapitalizationType)UITextAutocapitalizationType:(id)json; + (UITextFieldViewMode)UITextFieldViewMode:(id)json; + (UIKeyboardType)UIKeyboardType:(id)json; diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index b44a5430db1a..1bbd8c97bf7d 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -375,6 +375,38 @@ + (NSLocale *)NSLocale:(id)json NSWritingDirectionNatural, integerValue) ++ (NSLineBreakStrategy)NSLineBreakStrategy:(id)json RCT_DYNAMIC +{ + static NSDictionary *mapping; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (@available(iOS 14.0, *)) { + mapping = @{ + @"none" : @(NSLineBreakStrategyNone), +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 + @"standard" : @(NSLineBreakStrategyStandard), + @"hangul-word" : @(NSLineBreakStrategyHangulWordPriority), + @"push-out": @(NSLineBreakStrategyPushOut) +#else + @"standard" : @(NSLineBreakStrategyNone), + @"hangul-word" : @(NSLineBreakStrategyNone), + @"push-out": @(NSLineBreakStrategyNone) +#endif + }; + } else { + mapping = @{ + @"none" : @(NSLineBreakStrategyNone), + @"standard" : @(NSLineBreakStrategyNone), + @"hangul-word" : @(NSLineBreakStrategyNone), + @"push-out": @(NSLineBreakStrategyNone) + }; + } + }); + + NSLineBreakStrategy type = RCTConvertEnumValue("NSLineBreakStrategy", mapping, @(NSLineBreakStrategyNone), json).integerValue; + return type; +} + RCT_ENUM_CONVERTER( UITextAutocapitalizationType, (@{ diff --git a/packages/rn-tester/js/examples/Text/TextExample.ios.js b/packages/rn-tester/js/examples/Text/TextExample.ios.js index 9f92af41c712..9278ceb7e7d9 100644 --- a/packages/rn-tester/js/examples/Text/TextExample.ios.js +++ b/packages/rn-tester/js/examples/Text/TextExample.ios.js @@ -1246,4 +1246,41 @@ exports.examples = [ ); }, }, + { + title: 'Line Break Strategy', + render: function (): React.Node { + const lineBreakStrategy = ['none', 'standard', 'hangul-word', 'push-out']; + const textByCode = { + en: 'lineBreakStrategy lineBreakStrategy lineBreakStrategy lineBreakStrategy', + ko: '한글개행 한글개행 한글개행 한글개행 한글개행 한글개행 한글개행 한글개행', + ja: 'かいぎょう かいぎょう かいぎょう かいぎょう かいぎょう かいぎょう', + cn: '改行 改行 改行 改行 改行 改行 改行 改行 改行 改行 改行 改行', + }; + + return ( + + {lineBreakStrategy.map(strategy => { + return ( + + {`Strategy: ${strategy}`} + {Object.keys(textByCode).map(code => { + return ( + + {`[${code}]`} + + {textByCode[code]} + + + ); + })} + + ); + })} + + ); + }, + }, ]; diff --git a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js index f507161cfa31..c9a9fcc0373a 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js @@ -862,4 +862,43 @@ exports.examples = ([ ); }, }, + { + title: 'Line Break Strategy', + render: function (): React.Node { + const lineBreakStrategy = ['none', 'standard', 'hangul-word', 'push-out']; + const textByCode = { + en: 'lineBreakStrategy lineBreakStrategy lineBreakStrategy lineBreakStrategy', + ko: '한글개행한글개행 한글개행한글개행 한글개행한글개행 한글개행한글개행 한글개행한글개행 한글개행한글개행', + ja: 'かいぎょう かいぎょう かいぎょう かいぎょう かいぎょう かいぎょう', + cn: '改行 改行 改行 改行 改行 改行 改行 改行 改行 改行 改行 改行', + }; + return ( + + {lineBreakStrategy.map(strategy => { + return ( + + {`Strategy: ${strategy}`} + {Object.keys(textByCode).map(code => { + return ( + + {`[${code}]`} + + + ); + })} + + ); + })} + + ); + }, + }, ]: Array); From a6a77b98c63b3d5e59e508470f1cd601e5bcbdc8 Mon Sep 17 00:00:00 2001 From: bang9 Date: Mon, 26 Sep 2022 15:15:55 +0900 Subject: [PATCH 2/6] chore: update TextInput.flow.js props --- Libraries/Components/TextInput/TextInput.flow.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Libraries/Components/TextInput/TextInput.flow.js b/Libraries/Components/TextInput/TextInput.flow.js index 10a53f155c07..c201fd1c565b 100644 --- a/Libraries/Components/TextInput/TextInput.flow.js +++ b/Libraries/Components/TextInput/TextInput.flow.js @@ -319,6 +319,12 @@ type IOSProps = $ReadOnly<{| * @platform ios */ textContentType?: ?TextContentType, + + /** + * Set line break strategy on iOS. + * @platform ios + */ + ios_lineBreakStrategy?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), |}>; type AndroidProps = $ReadOnly<{| From f128d26a34e434008c5c456c5c97538cb540ba84 Mon Sep 17 00:00:00 2001 From: bang9 Date: Fri, 30 Sep 2022 05:48:00 +0900 Subject: [PATCH 3/6] chore: update prop name --- Libraries/Components/TextInput/RCTTextInputViewConfig.js | 2 +- Libraries/Components/TextInput/TextInput.flow.js | 2 +- Libraries/Components/TextInput/TextInput.js | 2 +- Libraries/Text/BaseText/RCTBaseTextViewManager.m | 2 +- Libraries/Text/TextNativeComponent.js | 2 +- Libraries/Text/TextProps.js | 4 ++-- packages/rn-tester/js/examples/Text/TextExample.ios.js | 2 +- .../rn-tester/js/examples/TextInput/TextInputExample.ios.js | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/Libraries/Components/TextInput/RCTTextInputViewConfig.js index c428518d8d4c..6af9cd331c18 100644 --- a/Libraries/Components/TextInput/RCTTextInputViewConfig.js +++ b/Libraries/Components/TextInput/RCTTextInputViewConfig.js @@ -149,7 +149,7 @@ const RCTTextInputViewConfig = { clearTextOnFocus: true, showSoftInputOnFocus: true, autoFocus: true, - ios_lineBreakStrategy: true, + lineBreakStrategyIOS: true, ...ConditionallyIgnoredEventHandlers({ onChange: true, onSelectionChange: true, diff --git a/Libraries/Components/TextInput/TextInput.flow.js b/Libraries/Components/TextInput/TextInput.flow.js index c201fd1c565b..57259190f1a4 100644 --- a/Libraries/Components/TextInput/TextInput.flow.js +++ b/Libraries/Components/TextInput/TextInput.flow.js @@ -324,7 +324,7 @@ type IOSProps = $ReadOnly<{| * Set line break strategy on iOS. * @platform ios */ - ios_lineBreakStrategy?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), + lineBreakStrategyIOS?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), |}>; type AndroidProps = $ReadOnly<{| diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 197414da7ade..fa45a7b441e8 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -357,7 +357,7 @@ type IOSProps = $ReadOnly<{| * Set line break strategy on iOS. * @platform ios */ - ios_lineBreakStrategy?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), + lineBreakStrategyIOS?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), |}>; type AndroidProps = $ReadOnly<{| diff --git a/Libraries/Text/BaseText/RCTBaseTextViewManager.m b/Libraries/Text/BaseText/RCTBaseTextViewManager.m index 6377a9075f82..059f561c2f54 100644 --- a/Libraries/Text/BaseText/RCTBaseTextViewManager.m +++ b/Libraries/Text/BaseText/RCTBaseTextViewManager.m @@ -42,7 +42,7 @@ - (RCTShadowView *)shadowView RCT_REMAP_SHADOW_PROPERTY(lineHeight, textAttributes.lineHeight, CGFloat) RCT_REMAP_SHADOW_PROPERTY(textAlign, textAttributes.alignment, NSTextAlignment) RCT_REMAP_SHADOW_PROPERTY(writingDirection, textAttributes.baseWritingDirection, NSWritingDirection) -RCT_REMAP_SHADOW_PROPERTY(ios_lineBreakStrategy, textAttributes.lineBreakStrategy, NSLineBreakStrategy) +RCT_REMAP_SHADOW_PROPERTY(lineBreakStrategyIOS, textAttributes.lineBreakStrategy, NSLineBreakStrategy) // Decoration RCT_REMAP_SHADOW_PROPERTY(textDecorationColor, textAttributes.textDecorationColor, UIColor) RCT_REMAP_SHADOW_PROPERTY(textDecorationStyle, textAttributes.textDecorationStyle, NSUnderlineStyle) diff --git a/Libraries/Text/TextNativeComponent.js b/Libraries/Text/TextNativeComponent.js index c1eda7b5024e..dd687c1697bf 100644 --- a/Libraries/Text/TextNativeComponent.js +++ b/Libraries/Text/TextNativeComponent.js @@ -45,7 +45,7 @@ const textViewConfig = { onInlineViewLayout: true, dataDetectorType: true, android_hyphenationFrequency: true, - ios_lineBreakStrategy: true, + lineBreakStrategyIOS: true, }, directEventTypes: { topTextLayout: { diff --git a/Libraries/Text/TextProps.js b/Libraries/Text/TextProps.js index 8e4b8127f866..3a927ae48681 100644 --- a/Libraries/Text/TextProps.js +++ b/Libraries/Text/TextProps.js @@ -240,7 +240,7 @@ export type TextProps = $ReadOnly<{| /** * Set line break strategy on iOS. * - * See https://reactnative.dev/docs/text.html#ios_linebreakstrategy + * See https://reactnative.dev/docs/text.html#linebreakstrategyios */ - ios_lineBreakStrategy?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), + lineBreakStrategyIOS?: ?('none' | 'standard' | 'hangul-word' | 'push-out'), |}>; diff --git a/packages/rn-tester/js/examples/Text/TextExample.ios.js b/packages/rn-tester/js/examples/Text/TextExample.ios.js index 9278ceb7e7d9..b0e6572a0772 100644 --- a/packages/rn-tester/js/examples/Text/TextExample.ios.js +++ b/packages/rn-tester/js/examples/Text/TextExample.ios.js @@ -1270,7 +1270,7 @@ exports.examples = [ return ( {`[${code}]`} - + {textByCode[code]} diff --git a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js index c9a9fcc0373a..7cff25b37ada 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js @@ -887,7 +887,7 @@ exports.examples = ([ {`[${code}]`} From cc492f6d27fd74d58107d906c3fa4516e35b058f Mon Sep 17 00:00:00 2001 From: bang9 Date: Fri, 30 Sep 2022 06:31:26 +0900 Subject: [PATCH 4/6] chore: apply review --- Libraries/Text/RCTTextAttributes.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Text/RCTTextAttributes.m b/Libraries/Text/RCTTextAttributes.m index e62ae29416d3..1fb130114307 100644 --- a/Libraries/Text/RCTTextAttributes.m +++ b/Libraries/Text/RCTTextAttributes.m @@ -67,7 +67,7 @@ - (void)applyTextAttributes:(RCTTextAttributes *)textAttributes _baseWritingDirection = textAttributes->_baseWritingDirection != NSWritingDirectionNatural ? textAttributes->_baseWritingDirection : _baseWritingDirection; // * - _lineBreakStrategy = textAttributes->_lineBreakStrategy != NSLineBreakStrategyNone ? textAttributes->_lineBreakStrategy : _lineBreakStrategy; + _lineBreakStrategy = textAttributes->_lineBreakStrategy ?: _lineBreakStrategy; // Decoration _textDecorationColor = textAttributes->_textDecorationColor ?: _textDecorationColor; From cfa21fbd445e0fb258f1f79048c88efe3e99e52f Mon Sep 17 00:00:00 2001 From: bang9 Date: Fri, 30 Sep 2022 06:34:18 +0900 Subject: [PATCH 5/6] feat: apply to fabric components --- .../attributedstring/TextAttributes.cpp | 6 ++ .../attributedstring/TextAttributes.h | 2 + .../renderer/attributedstring/conversions.h | 57 +++++++++++++++++++ .../renderer/attributedstring/primitives.h | 7 +++ .../components/text/BaseTextProps.cpp | 12 ++++ .../platform/ios/RCTAttributedTextUtils.mm | 6 ++ .../ios/RCTTextPrimitivesConversions.h | 22 +++++++ 7 files changed, 112 insertions(+) diff --git a/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp b/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp index c1c657c4fbe1..24f5bbd07b80 100644 --- a/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp +++ b/ReactCommon/react/renderer/attributedstring/TextAttributes.cpp @@ -62,6 +62,9 @@ void TextAttributes::apply(TextAttributes textAttributes) { baseWritingDirection = textAttributes.baseWritingDirection.has_value() ? textAttributes.baseWritingDirection : baseWritingDirection; + lineBreakStrategy = textAttributes.lineBreakStrategy.has_value() + ? textAttributes.lineBreakStrategy + : lineBreakStrategy; // Decoration textDecorationColor = textAttributes.textDecorationColor @@ -110,6 +113,7 @@ bool TextAttributes::operator==(const TextAttributes &rhs) const { allowFontScaling, alignment, baseWritingDirection, + lineBreakStrategy, textDecorationColor, textDecorationLineType, textDecorationStyle, @@ -129,6 +133,7 @@ bool TextAttributes::operator==(const TextAttributes &rhs) const { rhs.allowFontScaling, rhs.alignment, rhs.baseWritingDirection, + rhs.lineBreakStrategy, rhs.textDecorationColor, rhs.textDecorationLineType, rhs.textDecorationStyle, @@ -187,6 +192,7 @@ SharedDebugStringConvertibleList TextAttributes::getDebugProps() const { debugStringConvertibleItem("lineHeight", lineHeight), debugStringConvertibleItem("alignment", alignment), debugStringConvertibleItem("baseWritingDirection", baseWritingDirection), + debugStringConvertibleItem("lineBreakStrategyIOS", lineBreakStrategy), // Decoration debugStringConvertibleItem("textDecorationColor", textDecorationColor), diff --git a/ReactCommon/react/renderer/attributedstring/TextAttributes.h b/ReactCommon/react/renderer/attributedstring/TextAttributes.h index 82b8547507e5..69400f2ed172 100644 --- a/ReactCommon/react/renderer/attributedstring/TextAttributes.h +++ b/ReactCommon/react/renderer/attributedstring/TextAttributes.h @@ -57,6 +57,7 @@ class TextAttributes : public DebugStringConvertible { Float lineHeight{std::numeric_limits::quiet_NaN()}; std::optional alignment{}; std::optional baseWritingDirection{}; + std::optional lineBreakStrategy{}; // Decoration SharedColor textDecorationColor{}; @@ -121,6 +122,7 @@ struct hash { textAttributes.lineHeight, textAttributes.alignment, textAttributes.baseWritingDirection, + textAttributes.lineBreakStrategy, textAttributes.textDecorationColor, textAttributes.textDecorationLineType, textAttributes.textDecorationStyle, diff --git a/ReactCommon/react/renderer/attributedstring/conversions.h b/ReactCommon/react/renderer/attributedstring/conversions.h index 96cbc0c5d7e1..e2c7eb4e5027 100644 --- a/ReactCommon/react/renderer/attributedstring/conversions.h +++ b/ReactCommon/react/renderer/attributedstring/conversions.h @@ -420,6 +420,53 @@ inline std::string toString(const WritingDirection &writingDirection) { return "auto"; } + +inline void fromRawValue( + const PropsParserContext &context, + const RawValue &value, + LineBreakStrategy &result) { + react_native_assert(value.hasType()); + if (value.hasType()) { + auto string = (std::string)value; + if (string == "none") { + result = LineBreakStrategy::None; + } else if (string == "push-out") { + result = LineBreakStrategy::PushOut; + } else if (string == "hangul-word") { + result = LineBreakStrategy::HangulWordPriority; + } else if (string == "standard") { + result = LineBreakStrategy::Standard; + } else { + LOG(ERROR) << "Unsupported LineBreakStrategy value: " << string; + react_native_assert(false); + // sane default for prod + result = LineBreakStrategy::None; + } + return; + } + + LOG(ERROR) << "Unsupported LineBreakStrategy type"; + // sane default for prod + result = LineBreakStrategy::None; +} + +inline std::string toString(const LineBreakStrategy &lineBreakStrategy) { + switch (lineBreakStrategy) { + case LineBreakStrategy::None: + return "none"; + case LineBreakStrategy::PushOut: + return "push-out"; + case LineBreakStrategy::HangulWordPriority: + return "hangul-word"; + case LineBreakStrategy::Standard: + return "standard"; + } + + LOG(ERROR) << "Unsupported LineBreakStrategy value"; + // sane default for prod + return "none"; +} + inline void fromRawValue( const PropsParserContext &context, const RawValue &value, @@ -873,6 +920,10 @@ inline folly::dynamic toDynamic(const TextAttributes &textAttributes) { _textAttributes( "baseWritingDirection", toString(*textAttributes.baseWritingDirection)); } + if (textAttributes.lineBreakStrategy.has_value()) { + _textAttributes( + "lineBreakStrategyIOS", toString(*textAttributes.lineBreakStrategy)); + } // Decoration if (textAttributes.textDecorationColor) { _textAttributes( @@ -982,6 +1033,7 @@ constexpr static MapBuffer::Key TA_KEY_TEXT_SHADOW_COLOR = 19; constexpr static MapBuffer::Key TA_KEY_IS_HIGHLIGHTED = 20; constexpr static MapBuffer::Key TA_KEY_LAYOUT_DIRECTION = 21; constexpr static MapBuffer::Key TA_KEY_ACCESSIBILITY_ROLE = 22; +constexpr static MapBuffer::Key TA_KEY_LINE_BREAK_STRATEGY = 23; // constants for ParagraphAttributes serialization constexpr static MapBuffer::Key PA_KEY_MAX_NUMBER_OF_LINES = 0; @@ -1084,6 +1136,11 @@ inline MapBuffer toMapBuffer(const TextAttributes &textAttributes) { TA_KEY_BEST_WRITING_DIRECTION, toString(*textAttributes.baseWritingDirection)); } + if (textAttributes.lineBreakStrategy.has_value()) { + builder.putString( + TA_KEY_LINE_BREAK_STRATEGY, + toString(*textAttributes.lineBreakStrategy)); + } // Decoration if (textAttributes.textDecorationColor) { builder.putInt( diff --git a/ReactCommon/react/renderer/attributedstring/primitives.h b/ReactCommon/react/renderer/attributedstring/primitives.h index 1535210aca2b..116cc24faf04 100644 --- a/ReactCommon/react/renderer/attributedstring/primitives.h +++ b/ReactCommon/react/renderer/attributedstring/primitives.h @@ -74,6 +74,13 @@ enum class WritingDirection { RightToLeft // Right to left writing direction. }; +enum class LineBreakStrategy { + None, // Don't use any line break strategies + PushOut, // Use the push out line break strategy. + HangulWordPriority, // When specified, it prohibits breaking between Hangul characters. + Standard // Use the same configuration of line break strategies that the system uses for standard UI labels. +}; + enum class TextDecorationLineType { None, Underline, diff --git a/ReactCommon/react/renderer/components/text/BaseTextProps.cpp b/ReactCommon/react/renderer/components/text/BaseTextProps.cpp index 0b4b5f88aa93..6f4741ba69c9 100644 --- a/ReactCommon/react/renderer/components/text/BaseTextProps.cpp +++ b/ReactCommon/react/renderer/components/text/BaseTextProps.cpp @@ -105,6 +105,12 @@ static TextAttributes convertRawProp( "baseWritingDirection", sourceTextAttributes.baseWritingDirection, defaultTextAttributes.baseWritingDirection); + textAttributes.lineBreakStrategy = convertRawProp( + context, + rawProps, + "lineBreakStrategyIOS", + sourceTextAttributes.lineBreakStrategy, + defaultTextAttributes.lineBreakStrategy); // Decoration textAttributes.textDecorationColor = convertRawProp( @@ -243,6 +249,12 @@ void BaseTextProps::setProp( textAttributes, baseWritingDirection, "baseWritingDirection"); + REBUILD_FIELD_SWITCH_CASE( + defaults, + value, + textAttributes, + lineBreakStrategy, + "lineBreakStrategyIOS"); REBUILD_FIELD_SWITCH_CASE( defaults, value, diff --git a/ReactCommon/react/renderer/textlayoutmanager/platform/ios/RCTAttributedTextUtils.mm b/ReactCommon/react/renderer/textlayoutmanager/platform/ios/RCTAttributedTextUtils.mm index 0a5828ab7f5d..dcd4936369bb 100644 --- a/ReactCommon/react/renderer/textlayoutmanager/platform/ios/RCTAttributedTextUtils.mm +++ b/ReactCommon/react/renderer/textlayoutmanager/platform/ios/RCTAttributedTextUtils.mm @@ -155,6 +155,12 @@ inline static CGFloat RCTEffectiveFontSizeMultiplierFromTextAttributes(const Tex RCTNSWritingDirectionFromWritingDirection(textAttributes.baseWritingDirection.value()); isParagraphStyleUsed = YES; } + + if (textAttributes.lineBreakStrategy.has_value()) { + paragraphStyle.lineBreakStrategy = + RCTNSLineBreakStrategyFromLineBreakStrategy(textAttributes.lineBreakStrategy.value()); + isParagraphStyleUsed = YES; + } if (!isnan(textAttributes.lineHeight)) { CGFloat lineHeight = textAttributes.lineHeight * RCTEffectiveFontSizeMultiplierFromTextAttributes(textAttributes); diff --git a/ReactCommon/react/renderer/textlayoutmanager/platform/ios/RCTTextPrimitivesConversions.h b/ReactCommon/react/renderer/textlayoutmanager/platform/ios/RCTTextPrimitivesConversions.h index 235137bde0c1..a5d26c929453 100644 --- a/ReactCommon/react/renderer/textlayoutmanager/platform/ios/RCTTextPrimitivesConversions.h +++ b/ReactCommon/react/renderer/textlayoutmanager/platform/ios/RCTTextPrimitivesConversions.h @@ -40,6 +40,28 @@ inline static NSWritingDirection RCTNSWritingDirectionFromWritingDirection(Writi } } +inline static NSLineBreakStrategy RCTNSLineBreakStrategyFromLineBreakStrategy(LineBreakStrategy lineBreakStrategy) +{ + switch (lineBreakStrategy) { + case LineBreakStrategy::None: + return NSLineBreakStrategyNone; + case LineBreakStrategy::PushOut: + return NSLineBreakStrategyPushOut; + case LineBreakStrategy::HangulWordPriority: + if (@available(iOS 14.0, *)) { + return NSLineBreakStrategyHangulWordPriority; + } else { + return NSLineBreakStrategyNone; + } + case LineBreakStrategy::Standard: + if (@available(iOS 14.0, *)) { + return NSLineBreakStrategyStandard; + } else { + return NSLineBreakStrategyNone; + } + } +} + inline static RCTFontStyle RCTFontStyleFromFontStyle(FontStyle fontStyle) { switch (fontStyle) { From 5fe3fa14e59e3aa2e5629b916ac29701de6eddeb Mon Sep 17 00:00:00 2001 From: bang9 Date: Sat, 8 Oct 2022 12:10:41 +0900 Subject: [PATCH 6/6] chore: apply review --- React/Base/RCTConvert.m | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 1bbd8c97bf7d..bbb1e8f21c1e 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -377,34 +377,21 @@ + (NSLocale *)NSLocale:(id)json + (NSLineBreakStrategy)NSLineBreakStrategy:(id)json RCT_DYNAMIC { - static NSDictionary *mapping; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ if (@available(iOS 14.0, *)) { - mapping = @{ - @"none" : @(NSLineBreakStrategyNone), -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 - @"standard" : @(NSLineBreakStrategyStandard), - @"hangul-word" : @(NSLineBreakStrategyHangulWordPriority), - @"push-out": @(NSLineBreakStrategyPushOut) -#else - @"standard" : @(NSLineBreakStrategyNone), - @"hangul-word" : @(NSLineBreakStrategyNone), - @"push-out": @(NSLineBreakStrategyNone) -#endif - }; + static NSDictionary *mapping; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + mapping = @{ + @"none" : @(NSLineBreakStrategyNone), + @"standard" : @(NSLineBreakStrategyStandard), + @"hangul-word" : @(NSLineBreakStrategyHangulWordPriority), + @"push-out": @(NSLineBreakStrategyPushOut) + }; + }); + return RCTConvertEnumValue("NSLineBreakStrategy", mapping, @(NSLineBreakStrategyNone), json).integerValue; } else { - mapping = @{ - @"none" : @(NSLineBreakStrategyNone), - @"standard" : @(NSLineBreakStrategyNone), - @"hangul-word" : @(NSLineBreakStrategyNone), - @"push-out": @(NSLineBreakStrategyNone) - }; + return NSLineBreakStrategyNone; } - }); - - NSLineBreakStrategy type = RCTConvertEnumValue("NSLineBreakStrategy", mapping, @(NSLineBreakStrategyNone), json).integerValue; - return type; } RCT_ENUM_CONVERTER(