2018-01-24 07:17:57 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
*
|
2018-02-17 02:24:55 +00:00
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
2018-01-24 07:17:57 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#import "RCTTextAttributes.h"
|
|
|
|
|
|
|
|
#import <React/RCTAssert.h>
|
|
|
|
#import <React/RCTFont.h>
|
|
|
|
#import <React/RCTLog.h>
|
|
|
|
|
|
|
|
NSString *const RCTTextAttributesIsHighlightedAttributeName = @"RCTTextAttributesIsHighlightedAttributeName";
|
|
|
|
NSString *const RCTTextAttributesTagAttributeName = @"RCTTextAttributesTagAttributeName";
|
|
|
|
|
|
|
|
@implementation RCTTextAttributes
|
|
|
|
|
|
|
|
- (instancetype)init
|
|
|
|
{
|
|
|
|
if (self = [super init]) {
|
|
|
|
_fontSize = NAN;
|
|
|
|
_letterSpacing = NAN;
|
Adds _lineHeight = NAN; to RCTTextAttributes
Summary:
<!--
Thank you for sending the PR! We appreciate you spending the time to work on these changes.
Help us understand your motivation by explaining why you decided to make this change.
You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html
Happy contributing!
-->
On iOS, when the parent Text contains the `lineHeight` style prop, and the children are also Text components they don't inherit the lineHeight prop.
This is for **iOS** only.
Create a react-native project with React Native 0.54.0 or 0.54.1 and change the app to:
```js
import React, { Component } from 'react';
import { StyleSheet, Text, View } from 'react-native';
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={styles.container}>
<Text style={{ fontWeight: 'bold', lineHeight: 40 }}>
<Text style={{ color: 'orange' }}>I am bold and orange, </Text>
<Text style={{ color: 'red' }}>I am bold and red, </Text>
<Text style={{ color: 'blue' }}>I am bold and blue, </Text>
<Text style={{ color: 'purple' }}>I am bold and purple, </Text>
<Text style={{ color: 'yellow' }}>I am bold and yellow, </Text>
<Text style={{ color: 'pink' }}>I am bold and pink</Text>
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'black',
flex: 1,
justifyContent: 'center',
padding: 50,
},
});
```
It displays:
![iphone - 2018-03-12 at 21 51 53](https://user-images.githubusercontent.com/480605/37308941-b56f082e-263f-11e8-9c23-892f77077169.png)
But should look like:
![iphone - 2018-03-12 at 21 48 15](https://user-images.githubusercontent.com/480605/37308784-4efaddf2-263f-11e8-992b-ee0b6bb9a97b.png)
New <Text> iOS https://github.com/facebook/react-native/commit/2716f53
<!--
Help reviewers and the release process by writing your own release notes
**INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.**
CATEGORY
[----------] TYPE
[ CLI ] [-------------] LOCATION
[ DOCS ] [ BREAKING ] [-------------]
[ GENERAL ] [ BUGFIX ] [-{Component}-]
[ INTERNAL ] [ ENHANCEMENT ] [ {File} ]
[ IOS ] [ FEATURE ] [ {Directory} ] |-----------|
[ ANDROID ] [ MINOR ] [ {Framework} ] - | {Message} |
[----------] [-------------] [-------------] |-----------|
[CATEGORY] [TYPE] [LOCATION] - MESSAGE
EXAMPLES:
[IOS] [BREAKING] [FlatList] - Change a thing that breaks other things
[ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput
[CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with
[DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word
[GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position
[INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see
-->
[IOS] [MINOR] [Text] - Inherit lineheight
Closes https://github.com/facebook/react-native/pull/18340
Differential Revision: D7276655
Pulled By: shergin
fbshipit-source-id: 0fe26536bb74da77be8405911fc699a622bc0b2f
2018-03-14 20:04:41 +00:00
|
|
|
_lineHeight = NAN;
|
2018-01-24 07:17:57 +00:00
|
|
|
_textDecorationStyle = NSUnderlineStyleSingle;
|
|
|
|
_fontSizeMultiplier = NAN;
|
|
|
|
_alignment = NSTextAlignmentNatural;
|
|
|
|
_baseWritingDirection = NSWritingDirectionNatural;
|
|
|
|
_textShadowRadius = NAN;
|
|
|
|
_opacity = NAN;
|
2018-04-16 15:59:26 +00:00
|
|
|
_textTransform = RCTTextTransformUndefined;
|
2018-01-24 07:17:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)applyTextAttributes:(RCTTextAttributes *)textAttributes
|
|
|
|
{
|
|
|
|
// Note: All lines marked with `*` does not use explicit/correct rules to compare old and new values becuase
|
|
|
|
// their types do not have special designated value representing undefined/unspecified/inherit meaning.
|
|
|
|
// We will address this in the future.
|
|
|
|
|
|
|
|
// Color
|
|
|
|
_foregroundColor = textAttributes->_foregroundColor ?: _foregroundColor;
|
|
|
|
_backgroundColor = textAttributes->_backgroundColor ?: _backgroundColor;
|
|
|
|
_opacity = !isnan(textAttributes->_opacity) ? (isnan(_opacity) ? 1.0 : _opacity) * textAttributes->_opacity : _opacity;
|
|
|
|
|
|
|
|
// Font
|
|
|
|
_fontFamily = textAttributes->_fontFamily ?: _fontFamily;
|
|
|
|
_fontSize = !isnan(textAttributes->_fontSize) ? textAttributes->_fontSize : _fontSize;
|
|
|
|
_fontSizeMultiplier = !isnan(textAttributes->_fontSizeMultiplier) ? textAttributes->_fontSizeMultiplier : _fontSizeMultiplier;
|
|
|
|
_fontWeight = textAttributes->_fontWeight ?: _fontWeight;
|
|
|
|
_fontStyle = textAttributes->_fontStyle ?: _fontStyle;
|
|
|
|
_fontVariant = textAttributes->_fontVariant ?: _fontVariant;
|
|
|
|
_allowFontScaling = textAttributes->_allowFontScaling || _allowFontScaling; // *
|
|
|
|
_letterSpacing = !isnan(textAttributes->_letterSpacing) ? textAttributes->_letterSpacing : _letterSpacing;
|
|
|
|
|
|
|
|
// Paragraph Styles
|
|
|
|
_lineHeight = !isnan(textAttributes->_lineHeight) ? textAttributes->_lineHeight : _lineHeight;
|
|
|
|
_alignment = textAttributes->_alignment != NSTextAlignmentNatural ? textAttributes->_alignment : _alignment; // *
|
|
|
|
_baseWritingDirection = textAttributes->_baseWritingDirection != NSWritingDirectionNatural ? textAttributes->_baseWritingDirection : _baseWritingDirection; // *
|
|
|
|
|
|
|
|
// Decoration
|
|
|
|
_textDecorationColor = textAttributes->_textDecorationColor ?: _textDecorationColor;
|
|
|
|
_textDecorationStyle = textAttributes->_textDecorationStyle != NSUnderlineStyleSingle ? textAttributes->_textDecorationStyle : _textDecorationStyle; // *
|
|
|
|
_textDecorationLine = textAttributes->_textDecorationLine != RCTTextDecorationLineTypeNone ? textAttributes->_textDecorationLine : _textDecorationLine; // *
|
|
|
|
|
|
|
|
// Shadow
|
|
|
|
_textShadowOffset = !CGSizeEqualToSize(textAttributes->_textShadowOffset, CGSizeZero) ? textAttributes->_textShadowOffset : _textShadowOffset; // *
|
|
|
|
_textShadowRadius = !isnan(textAttributes->_textShadowRadius) ? textAttributes->_textShadowRadius : _textShadowRadius;
|
|
|
|
_textShadowColor = textAttributes->_textShadowColor ?: _textShadowColor;
|
|
|
|
|
|
|
|
// Special
|
|
|
|
_isHighlighted = textAttributes->_isHighlighted || _isHighlighted; // *
|
|
|
|
_tag = textAttributes->_tag ?: _tag;
|
|
|
|
_layoutDirection = textAttributes->_layoutDirection != UIUserInterfaceLayoutDirectionLeftToRight ? textAttributes->_layoutDirection : _layoutDirection;
|
2018-04-16 15:59:26 +00:00
|
|
|
_textTransform = textAttributes->_textTransform != RCTTextTransformUndefined ? textAttributes->_textTransform : _textTransform;
|
2018-01-24 07:17:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary<NSAttributedStringKey, id> *)effectiveTextAttributes
|
|
|
|
{
|
|
|
|
NSMutableDictionary<NSAttributedStringKey, id> *attributes =
|
|
|
|
[NSMutableDictionary dictionaryWithCapacity:10];
|
|
|
|
|
|
|
|
// Font
|
|
|
|
UIFont *font = self.effectiveFont;
|
|
|
|
if (font) {
|
|
|
|
attributes[NSFontAttributeName] = font;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Colors
|
|
|
|
UIColor *effectiveForegroundColor = self.effectiveForegroundColor;
|
|
|
|
|
|
|
|
if (_foregroundColor || !isnan(_opacity)) {
|
|
|
|
attributes[NSForegroundColorAttributeName] = effectiveForegroundColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_backgroundColor || !isnan(_opacity)) {
|
|
|
|
attributes[NSBackgroundColorAttributeName] = self.effectiveBackgroundColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Kerning
|
|
|
|
if (!isnan(_letterSpacing)) {
|
|
|
|
attributes[NSKernAttributeName] = @(_letterSpacing);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Paragraph Style
|
|
|
|
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
|
|
|
|
BOOL isParagraphStyleUsed = NO;
|
|
|
|
if (_alignment != NSTextAlignmentNatural) {
|
|
|
|
NSTextAlignment alignment = _alignment;
|
|
|
|
if (_layoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
|
|
|
|
if (alignment == NSTextAlignmentRight) {
|
|
|
|
alignment = NSTextAlignmentLeft;
|
|
|
|
} else if (alignment == NSTextAlignmentLeft) {
|
|
|
|
alignment = NSTextAlignmentRight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
paragraphStyle.alignment = alignment;
|
|
|
|
isParagraphStyleUsed = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_baseWritingDirection != NSWritingDirectionNatural) {
|
|
|
|
paragraphStyle.baseWritingDirection = _baseWritingDirection;
|
|
|
|
isParagraphStyleUsed = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isnan(_lineHeight)) {
|
|
|
|
CGFloat lineHeight = _lineHeight * self.effectiveFontSizeMultiplier;
|
|
|
|
paragraphStyle.minimumLineHeight = lineHeight;
|
|
|
|
paragraphStyle.maximumLineHeight = lineHeight;
|
|
|
|
isParagraphStyleUsed = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isParagraphStyleUsed) {
|
|
|
|
attributes[NSParagraphStyleAttributeName] = paragraphStyle;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decoration
|
|
|
|
BOOL isTextDecorationEnabled = NO;
|
|
|
|
if (_textDecorationLine == RCTTextDecorationLineTypeUnderline ||
|
|
|
|
_textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough) {
|
|
|
|
isTextDecorationEnabled = YES;
|
|
|
|
attributes[NSUnderlineStyleAttributeName] = @(_textDecorationStyle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_textDecorationLine == RCTTextDecorationLineTypeStrikethrough ||
|
|
|
|
_textDecorationLine == RCTTextDecorationLineTypeUnderlineStrikethrough){
|
|
|
|
isTextDecorationEnabled = YES;
|
|
|
|
attributes[NSStrikethroughStyleAttributeName] = @(_textDecorationStyle);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_textDecorationColor || isTextDecorationEnabled) {
|
|
|
|
attributes[NSStrikethroughColorAttributeName] = _textDecorationColor ?: effectiveForegroundColor;
|
|
|
|
attributes[NSUnderlineColorAttributeName] = _textDecorationColor ?: effectiveForegroundColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shadow
|
|
|
|
if (!CGSizeEqualToSize(_textShadowOffset, CGSizeZero)) {
|
|
|
|
NSShadow *shadow = [NSShadow new];
|
|
|
|
shadow.shadowOffset = _textShadowOffset;
|
|
|
|
shadow.shadowBlurRadius = _textShadowRadius;
|
|
|
|
shadow.shadowColor = _textShadowColor;
|
|
|
|
attributes[NSShadowAttributeName] = shadow;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special
|
|
|
|
if (_isHighlighted) {
|
|
|
|
attributes[RCTTextAttributesIsHighlightedAttributeName] = @YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_tag) {
|
|
|
|
attributes[RCTTextAttributesTagAttributeName] = _tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
return [attributes copy];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (UIFont *)effectiveFont
|
|
|
|
{
|
|
|
|
// FIXME: RCTFont has thread-safety issues and must be rewritten.
|
|
|
|
return [RCTFont updateFont:nil
|
|
|
|
withFamily:_fontFamily
|
|
|
|
size:@(isnan(_fontSize) ? 0 : _fontSize)
|
|
|
|
weight:_fontWeight
|
|
|
|
style:_fontStyle
|
|
|
|
variant:_fontVariant
|
|
|
|
scaleMultiplier:self.effectiveFontSizeMultiplier];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (CGFloat)effectiveFontSizeMultiplier
|
|
|
|
{
|
2018-02-16 20:08:59 +00:00
|
|
|
return !RCTHasFontHandlerSet() && _allowFontScaling && !isnan(_fontSizeMultiplier) ? _fontSizeMultiplier : 1.0;
|
2018-01-24 07:17:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (UIColor *)effectiveForegroundColor
|
|
|
|
{
|
|
|
|
UIColor *effectiveForegroundColor = _foregroundColor ?: [UIColor blackColor];
|
|
|
|
|
|
|
|
if (!isnan(_opacity)) {
|
|
|
|
effectiveForegroundColor = [effectiveForegroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveForegroundColor.CGColor) * _opacity];
|
|
|
|
}
|
|
|
|
|
|
|
|
return effectiveForegroundColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (UIColor *)effectiveBackgroundColor
|
|
|
|
{
|
|
|
|
UIColor *effectiveBackgroundColor = _backgroundColor;// ?: [[UIColor whiteColor] colorWithAlphaComponent:0];
|
|
|
|
|
|
|
|
if (effectiveBackgroundColor && !isnan(_opacity)) {
|
|
|
|
effectiveBackgroundColor = [effectiveBackgroundColor colorWithAlphaComponent:CGColorGetAlpha(effectiveBackgroundColor.CGColor) * _opacity];
|
|
|
|
}
|
|
|
|
|
|
|
|
return effectiveBackgroundColor ?: [UIColor clearColor];
|
|
|
|
}
|
|
|
|
|
2018-04-16 15:59:26 +00:00
|
|
|
- (NSString *)applyTextAttributesToText:(NSString *)text
|
|
|
|
{
|
|
|
|
switch (_textTransform) {
|
|
|
|
case RCTTextTransformUndefined:
|
|
|
|
case RCTTextTransformNone:
|
|
|
|
return text;
|
|
|
|
case RCTTextTransformLowercase:
|
|
|
|
return [text lowercaseString];
|
|
|
|
case RCTTextTransformUppercase:
|
|
|
|
return [text uppercaseString];
|
|
|
|
case RCTTextTransformCapitalize:
|
|
|
|
return [text capitalizedString];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-24 07:17:57 +00:00
|
|
|
- (RCTTextAttributes *)copyWithZone:(NSZone *)zone
|
|
|
|
{
|
|
|
|
RCTTextAttributes *textAttributes = [RCTTextAttributes new];
|
|
|
|
[textAttributes applyTextAttributes:self];
|
|
|
|
return textAttributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - NSObject
|
|
|
|
|
|
|
|
- (BOOL)isEqual:(RCTTextAttributes *)textAttributes
|
|
|
|
{
|
|
|
|
if (self == textAttributes) {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define RCTTextAttributesCompareFloats(a) ((a == textAttributes->a) || (isnan(a) && isnan(textAttributes->a)))
|
|
|
|
#define RCTTextAttributesCompareSize(a) CGSizeEqualToSize(a, textAttributes->a)
|
|
|
|
#define RCTTextAttributesCompareObjects(a) ((a == textAttributes->a) || [a isEqual:textAttributes->a])
|
|
|
|
#define RCTTextAttributesCompareStrings(a) ((a == textAttributes->a) || [a isEqualToString:textAttributes->a])
|
|
|
|
#define RCTTextAttributesCompareOthers(a) (a == textAttributes->a)
|
|
|
|
|
|
|
|
return
|
|
|
|
RCTTextAttributesCompareObjects(_foregroundColor) &&
|
|
|
|
RCTTextAttributesCompareObjects(_backgroundColor) &&
|
|
|
|
RCTTextAttributesCompareFloats(_opacity) &&
|
|
|
|
// Font
|
|
|
|
RCTTextAttributesCompareObjects(_fontFamily) &&
|
|
|
|
RCTTextAttributesCompareFloats(_fontSize) &&
|
|
|
|
RCTTextAttributesCompareFloats(_fontSizeMultiplier) &&
|
|
|
|
RCTTextAttributesCompareStrings(_fontWeight) &&
|
|
|
|
RCTTextAttributesCompareObjects(_fontStyle) &&
|
|
|
|
RCTTextAttributesCompareObjects(_fontVariant) &&
|
|
|
|
RCTTextAttributesCompareOthers(_allowFontScaling) &&
|
|
|
|
RCTTextAttributesCompareFloats(_letterSpacing) &&
|
|
|
|
// Paragraph Styles
|
|
|
|
RCTTextAttributesCompareFloats(_lineHeight) &&
|
|
|
|
RCTTextAttributesCompareFloats(_alignment) &&
|
|
|
|
RCTTextAttributesCompareOthers(_baseWritingDirection) &&
|
|
|
|
// Decoration
|
|
|
|
RCTTextAttributesCompareObjects(_textDecorationColor) &&
|
|
|
|
RCTTextAttributesCompareOthers(_textDecorationStyle) &&
|
|
|
|
RCTTextAttributesCompareOthers(_textDecorationLine) &&
|
|
|
|
// Shadow
|
|
|
|
RCTTextAttributesCompareSize(_textShadowOffset) &&
|
|
|
|
RCTTextAttributesCompareFloats(_textShadowRadius) &&
|
|
|
|
RCTTextAttributesCompareObjects(_textShadowColor) &&
|
|
|
|
// Special
|
|
|
|
RCTTextAttributesCompareOthers(_isHighlighted) &&
|
|
|
|
RCTTextAttributesCompareObjects(_tag) &&
|
2018-04-16 15:59:26 +00:00
|
|
|
RCTTextAttributesCompareOthers(_layoutDirection) &&
|
|
|
|
RCTTextAttributesCompareOthers(_textTransform);
|
2018-01-24 07:17:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|