Skip to content

Commit 0335323

Browse files
authored
Merge pull request #1449 from amgleitman/0.68-dynamic-type
[0.68] Add Dynamic Type support
2 parents 2047450 + c310a18 commit 0335323

File tree

9 files changed

+193
-1
lines changed

9 files changed

+193
-1
lines changed

Libraries/Text/BaseText/RCTBaseTextViewManager.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ - (RCTShadowView *)shadowView
3636
RCT_REMAP_SHADOW_PROPERTY(fontStyle, textAttributes.fontStyle, NSString)
3737
RCT_REMAP_SHADOW_PROPERTY(fontVariant, textAttributes.fontVariant, NSArray)
3838
RCT_REMAP_SHADOW_PROPERTY(allowFontScaling, textAttributes.allowFontScaling, BOOL)
39+
RCT_REMAP_SHADOW_PROPERTY(dynamicTypeRamp, textAttributes.dynamicTypeRamp, RCTDynamicTypeRamp) // TODO(macOS GH#774)
3940
RCT_REMAP_SHADOW_PROPERTY(maxFontSizeMultiplier, textAttributes.maxFontSizeMultiplier, CGFloat)
4041
RCT_REMAP_SHADOW_PROPERTY(letterSpacing, textAttributes.letterSpacing, CGFloat)
4142
RCT_REMAP_SHADOW_PROPERTY(apple_fontSmoothing, textAttributes.fontSmoothing, RCTFontSmoothing) // TODO(OSS Candidate ISS#2710739)

Libraries/Text/RCTTextAttributes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#import <React/RCTUIKit.h> // TODO(macOS GH#774)
99

1010
#import <React/RCTTextDecorationLineType.h>
11+
#import <React/RCTDynamicTypeRamp.h> // TODO(macOS GH#774)
1112
#import <React/RCTFontSmoothing.h> // TODO(OSS Candidate ISS#2710739)
1213

1314
#import "RCTTextTransform.h"
@@ -38,6 +39,7 @@ extern NSString *const RCTTextAttributesTagAttributeName;
3839
@property (nonatomic, copy, nullable) NSString *fontStyle;
3940
@property (nonatomic, copy, nullable) NSArray<NSString *> *fontVariant;
4041
@property (nonatomic, assign) BOOL allowFontScaling;
42+
@property (nonatomic, assign) RCTDynamicTypeRamp dynamicTypeRamp; // TODO(macOS GH#774)
4143
@property (nonatomic, assign) CGFloat letterSpacing;
4244
@property (nonatomic, assign) RCTFontSmoothing fontSmoothing; // TODO(OSS Candidate ISS#2710739)
4345
@property (class, nonatomic, assign) RCTFontSmoothing fontSmoothingDefault; // TODO(OSS Candidate ISS#2710739)

Libraries/Text/RCTTextAttributes.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ - (void)applyTextAttributes:(RCTTextAttributes *)textAttributes
6363
_fontStyle = textAttributes->_fontStyle ?: _fontStyle;
6464
_fontVariant = textAttributes->_fontVariant ?: _fontVariant;
6565
_allowFontScaling = textAttributes->_allowFontScaling || _allowFontScaling; // *
66+
_dynamicTypeRamp = textAttributes->_dynamicTypeRamp != RCTDynamicTypeRampUndefined ? textAttributes->_dynamicTypeRamp : _dynamicTypeRamp; // TODO(macOS GH#774)
6667
_letterSpacing = !isnan(textAttributes->_letterSpacing) ? textAttributes->_letterSpacing : _letterSpacing;
6768
_fontSmoothing = textAttributes->_fontSmoothing != RCTFontSmoothingAuto ? textAttributes->_fontSmoothing : _fontSmoothing; // TODO(OSS Candidate ISS#2710739)
6869

@@ -223,6 +224,13 @@ - (CGFloat)effectiveFontSizeMultiplier
223224

224225
if (fontScalingEnabled) {
225226
CGFloat fontSizeMultiplier = !isnan(_fontSizeMultiplier) ? _fontSizeMultiplier : 1.0;
227+
#if !TARGET_OS_OSX // [TODO(macOS GH#774)
228+
if (_dynamicTypeRamp != RCTDynamicTypeRampUndefined) {
229+
UIFontMetrics *fontMetrics = RCTUIFontMetricsForDynamicTypeRamp(_dynamicTypeRamp);
230+
CGFloat baseSize = RCTUIBaseSizeForDynamicTypeRamp(_dynamicTypeRamp);
231+
fontSizeMultiplier = [fontMetrics scaledValueForValue:baseSize] / baseSize;
232+
}
233+
#endif // ]TODO(macOS GH#774)
226234
CGFloat maxFontSizeMultiplier = !isnan(_maxFontSizeMultiplier) ? _maxFontSizeMultiplier : 0.0;
227235
return maxFontSizeMultiplier >= 1.0 ? fminf(maxFontSizeMultiplier, fontSizeMultiplier) : fontSizeMultiplier;
228236
} else {
@@ -321,6 +329,7 @@ - (BOOL)isEqual:(RCTTextAttributes *)textAttributes
321329
RCTTextAttributesCompareObjects(_fontStyle) &&
322330
RCTTextAttributesCompareObjects(_fontVariant) &&
323331
RCTTextAttributesCompareOthers(_allowFontScaling) &&
332+
RCTTextAttributesCompareOthers(_dynamicTypeRamp) && // TODO(macOS GH#774)
324333
RCTTextAttributesCompareFloats(_letterSpacing) &&
325334
RCTTextAttributesCompareOthers(_fontSmoothing) && // TODO(OSS Candidate ISS#2710739)
326335
// Paragraph Styles
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
// TODO(macOS GH#774)
9+
10+
#import <Foundation/Foundation.h>
11+
12+
#import <React/RCTConvert.h>
13+
14+
typedef NS_ENUM(NSInteger, RCTDynamicTypeRamp) {
15+
RCTDynamicTypeRampUndefined,
16+
RCTDynamicTypeRampCaption2,
17+
RCTDynamicTypeRampCaption1,
18+
RCTDynamicTypeRampFootnote,
19+
RCTDynamicTypeRampSubhead,
20+
RCTDynamicTypeRampCallout,
21+
RCTDynamicTypeRampBody,
22+
RCTDynamicTypeRampHeadline,
23+
RCTDynamicTypeRampTitle3,
24+
RCTDynamicTypeRampTitle2,
25+
RCTDynamicTypeRampTitle1,
26+
RCTDynamicTypeRampLargeTitle
27+
};
28+
29+
@interface RCTConvert (DynamicTypeRamp)
30+
31+
+ (RCTDynamicTypeRamp)RCTDynamicTypeRamp:(nullable id)json;
32+
33+
@end
34+
35+
#if !TARGET_OS_OSX // [TODO(macOS GH#774)
36+
/// Generates a `UIFontMetrics` instance representing a particular Dynamic Type ramp.
37+
UIFontMetrics * _Nonnull RCTUIFontMetricsForDynamicTypeRamp(RCTDynamicTypeRamp dynamicTypeRamp);
38+
/// The "reference" size for a particular font scale ramp, equal to a text element's size under default text size settings.
39+
CGFloat RCTUIBaseSizeForDynamicTypeRamp(RCTDynamicTypeRamp dynamicTypeRamp);
40+
#endif // ]TODO(macOS GH#774)
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
// TODO(macOS GH#774)
9+
10+
#import <React/RCTDynamicTypeRamp.h>
11+
12+
@implementation RCTConvert (DynamicTypeRamp)
13+
14+
RCT_ENUM_CONVERTER(RCTDynamicTypeRamp, (@{
15+
@"caption2": @(RCTDynamicTypeRampCaption2),
16+
@"caption1": @(RCTDynamicTypeRampCaption1),
17+
@"footnote": @(RCTDynamicTypeRampFootnote),
18+
@"subhead": @(RCTDynamicTypeRampSubhead),
19+
@"callout": @(RCTDynamicTypeRampCallout),
20+
@"body": @(RCTDynamicTypeRampBody),
21+
@"headline": @(RCTDynamicTypeRampHeadline),
22+
@"title3": @(RCTDynamicTypeRampTitle3),
23+
@"title2": @(RCTDynamicTypeRampTitle2),
24+
@"title1": @(RCTDynamicTypeRampTitle1),
25+
@"largeTitle": @(RCTDynamicTypeRampLargeTitle),
26+
}), RCTDynamicTypeRampUndefined, integerValue)
27+
28+
@end
29+
30+
#if !TARGET_OS_OSX // [TODO(macOS GH#774)
31+
UIFontMetrics *RCTUIFontMetricsForDynamicTypeRamp(RCTDynamicTypeRamp dynamicTypeRamp) {
32+
static NSDictionary<NSNumber *, UIFontTextStyle> *mapping;
33+
static dispatch_once_t onceToken;
34+
dispatch_once(&onceToken, ^{
35+
mapping = @{
36+
@(RCTDynamicTypeRampCaption2): UIFontTextStyleCaption2,
37+
@(RCTDynamicTypeRampCaption1): UIFontTextStyleCaption1,
38+
@(RCTDynamicTypeRampFootnote): UIFontTextStyleFootnote,
39+
@(RCTDynamicTypeRampSubhead): UIFontTextStyleSubheadline,
40+
@(RCTDynamicTypeRampCallout): UIFontTextStyleCallout,
41+
@(RCTDynamicTypeRampBody): UIFontTextStyleBody,
42+
@(RCTDynamicTypeRampHeadline): UIFontTextStyleHeadline,
43+
@(RCTDynamicTypeRampTitle3): UIFontTextStyleTitle3,
44+
@(RCTDynamicTypeRampTitle2): UIFontTextStyleTitle2,
45+
@(RCTDynamicTypeRampTitle1): UIFontTextStyleTitle1,
46+
@(RCTDynamicTypeRampLargeTitle): UIFontTextStyleLargeTitle,
47+
};
48+
});
49+
50+
id textStyle = mapping[@(dynamicTypeRamp)] ?: UIFontTextStyleBody; // Default to body if we don't recognize the specified ramp
51+
return [UIFontMetrics metricsForTextStyle:textStyle];
52+
}
53+
54+
CGFloat RCTUIBaseSizeForDynamicTypeRamp(RCTDynamicTypeRamp dynamicTypeRamp) {
55+
static NSDictionary<NSNumber *, NSNumber *> *mapping;
56+
static dispatch_once_t onceToken;
57+
dispatch_once(&onceToken, ^{
58+
// Values taken from https://developer.apple.com/design/human-interface-guidelines/foundations/typography/
59+
mapping = @{
60+
@(RCTDynamicTypeRampCaption2): @11,
61+
@(RCTDynamicTypeRampCaption1): @12,
62+
@(RCTDynamicTypeRampFootnote): @13,
63+
@(RCTDynamicTypeRampSubhead): @15,
64+
@(RCTDynamicTypeRampCallout): @16,
65+
@(RCTDynamicTypeRampBody): @17,
66+
@(RCTDynamicTypeRampHeadline): @17,
67+
@(RCTDynamicTypeRampTitle3): @20,
68+
@(RCTDynamicTypeRampTitle2): @22,
69+
@(RCTDynamicTypeRampTitle1): @28,
70+
@(RCTDynamicTypeRampLargeTitle): @34,
71+
};
72+
});
73+
74+
NSNumber *baseSize = mapping[@(dynamicTypeRamp)] ?: @17; // Default to body size if we don't recognize the specified ramp
75+
return CGFLOAT_IS_DOUBLE ? [baseSize doubleValue] : [baseSize floatValue];
76+
}
77+
#endif // ]TODO(macOS GH#774)

Libraries/Text/TextNativeComponent.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export const NativeText: HostComponent<NativeTextProps> =
3434
numberOfLines: true,
3535
ellipsizeMode: true,
3636
allowFontScaling: true,
37+
dynamicTypeRamp: true,
3738
maxFontSizeMultiplier: true,
3839
disabled: true,
3940
selectable: true,

Libraries/Text/TextProps.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,23 @@ export type TextProps = $ReadOnly<{|
186186
*/
187187
adjustsFontSizeToFit?: ?boolean,
188188

189+
/**
190+
* The Dynamic Text scale ramp to apply to this element on iOS.
191+
*/
192+
dynamicTypeRamp?: ?(
193+
| 'caption2'
194+
| 'caption1'
195+
| 'footnote'
196+
| 'subhead'
197+
| 'callout'
198+
| 'body'
199+
| 'headline'
200+
| 'title3'
201+
| 'title2'
202+
| 'title1'
203+
| 'largeTitle'
204+
),
205+
189206
/**
190207
* Smallest possible scale a font can reach.
191208
*

packages/rn-tester/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ SPEC CHECKSUMS:
575575
glog: 20113a0d46931b6f096cf8302c68691d75a456ff
576576
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
577577
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
578-
RCT-Folly: 5544a3ff21f4406e70e92a8711598e97fc81517c
578+
RCT-Folly: 24c6da766832002a4a2aac5f79ee0ca50fbe8507
579579
RCTRequired: 1b5b629bc84503ce8db6c77182b5c97f10403a5d
580580
RCTTypeSafety: 27697dead471c036a8769495e3a92919d18c8b5c
581581
React: c4a2bbba51b5b3103384ceba3af0337f22f20895

packages/rn-tester/js/examples/Text/TextExample.ios.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,4 +1232,49 @@ exports.examples = [
12321232
);
12331233
},
12341234
},
1235+
{
1236+
title: 'Dynamic Text sizing (iOS only)',
1237+
render: function (): React.Node {
1238+
const boldStyle = {fontWeight: 'bold'};
1239+
const boxStyle = {
1240+
borderWidth: 1,
1241+
padding: 8,
1242+
margin: 8,
1243+
};
1244+
return (
1245+
<View style={{marginTop: 10, marginBottom: 10}}>
1246+
<Text>
1247+
Adjust text size in Accessibility settings and watch how the font
1248+
sizes change relative to each other.
1249+
</Text>
1250+
<View style={boxStyle}>
1251+
<Text style={boldStyle}>With `dynamicTypeRamp`:</Text>
1252+
<Text style={{fontSize: 34}} dynamicTypeRamp="largeTitle">
1253+
Large Title
1254+
</Text>
1255+
<Text style={{fontSize: 28}} dynamicTypeRamp="title1">
1256+
Title
1257+
</Text>
1258+
<Text style={{fontSize: 22}} dynamicTypeRamp="title2">
1259+
Title 2
1260+
</Text>
1261+
<Text style={{fontSize: 20}} dynamicTypeRamp="title3">
1262+
Title 3
1263+
</Text>
1264+
<Text style={{fontSize: 17}} dynamicTypeRamp="body">
1265+
Body
1266+
</Text>
1267+
</View>
1268+
<View style={boxStyle}>
1269+
<Text style={boldStyle}>Without `dynamicTypeRamp`:</Text>
1270+
<Text style={{fontSize: 34}}>Large Title</Text>
1271+
<Text style={{fontSize: 28}}>Title</Text>
1272+
<Text style={{fontSize: 22}}>Title 2</Text>
1273+
<Text style={{fontSize: 20}}>Title 3</Text>
1274+
<Text style={{fontSize: 17}}>Body</Text>
1275+
</View>
1276+
</View>
1277+
);
1278+
},
1279+
},
12351280
];

0 commit comments

Comments
 (0)