mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
feat(iOS): added lineBreakStrategy attribute to Text/TextInput (#31272)
Summary: iOS did not support the implementation of Korean word-wrap(line-break) before iOS14. If the attribute applied, the word-wrap of Korean will works. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [iOS] [Added] - Line break strategy for Text and TextInput components Pull Request resolved: https://github.com/facebook/react-native/pull/31272 Test Plan: 1. Test build and run on above iOS 14. 2. Test it does not affect existing text components when set default(none) strategy. 3. Test whether word-wrap works with Korean when set hangul-word strategy. <img src="https://user-images.githubusercontent.com/26326015/112963967-d7f70c00-9182-11eb-9a34-8c758b80c219.png" width="300" height="" style="max-width:100%;"> Reviewed By: javache Differential Revision: D39824809 Pulled By: lunaleaps fbshipit-source-id: 42cb0385221a38c84e80d3494d1bfc1934ecf32b
This commit is contained in:
committed by
Facebook GitHub Bot
parent
a0ee6fae5e
commit
048194849b
@@ -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),
|
||||
|
||||
@@ -57,6 +57,7 @@ class TextAttributes : public DebugStringConvertible {
|
||||
Float lineHeight{std::numeric_limits<Float>::quiet_NaN()};
|
||||
std::optional<TextAlignment> alignment{};
|
||||
std::optional<WritingDirection> baseWritingDirection{};
|
||||
std::optional<LineBreakStrategy> lineBreakStrategy{};
|
||||
|
||||
// Decoration
|
||||
SharedColor textDecorationColor{};
|
||||
@@ -121,6 +122,7 @@ struct hash<facebook::react::TextAttributes> {
|
||||
textAttributes.lineHeight,
|
||||
textAttributes.alignment,
|
||||
textAttributes.baseWritingDirection,
|
||||
textAttributes.lineBreakStrategy,
|
||||
textAttributes.textDecorationColor,
|
||||
textAttributes.textDecorationLineType,
|
||||
textAttributes.textDecorationStyle,
|
||||
|
||||
@@ -420,6 +420,52 @@ 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<std::string>());
|
||||
if (value.hasType<std::string>()) {
|
||||
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 +919,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 +1032,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 +1135,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(
|
||||
|
||||
@@ -74,6 +74,15 @@ 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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -156,6 +156,12 @@ NSDictionary<NSAttributedStringKey, id> *RCTNSTextAttributesFromTextAttributes(T
|
||||
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);
|
||||
paragraphStyle.minimumLineHeight = lineHeight;
|
||||
|
||||
+22
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user