Skip to content

Commit 1c37d18

Browse files
amgleitmanAdam Gleitman
andauthored
Add font metrics package to FURN (#2298)
* Add NativeFontMetrics package * Remove unneeded API * Fix spacing * Change files * Add @types/use-subscription dependency * Update yarn.lock * Add use-subscription as a dependency * Update yarn.lock again * NativeFontMetrics.tsx -> NativeFontMetrics.ts * Make NativeFontMetrics iOS only, part 1 * Stub out NativeFontMetrics for non-iOS platforms * Keep use-subscription version consistent with react-native and react-native-macos * Remove core-android capability * id -> UIFontTextStyle * hasListeners -> _hasListeners * Revert "Remove core-android capability" This reverts commit 0c97508. * Revert "Revert "Remove core-android capability"" This reverts commit 794c41c. Co-authored-by: Adam Gleitman <[email protected]>
1 parent 6f086d9 commit 1c37d18

17 files changed

+345
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Add NativeFontMetrics package",
4+
"packageName": "@fluentui-react-native/experimental-native-font-metrics",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

packages/experimental/NativeFontMetrics/CHANGELOG.json

Whitespace-only changes.

packages/experimental/NativeFontMetrics/CHANGELOG.md

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require 'json'
2+
3+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4+
5+
Pod::Spec.new do |s|
6+
s.name = 'FRNFontMetrics'
7+
s.version = package['version']
8+
s.summary = package['description']
9+
s.license = package['license']
10+
11+
s.authors = package['author']
12+
s.homepage = "https://github.com/microsoft/fluentui-react-native"
13+
14+
s.source = { :git => "https://github.com/microsoft/fluentui-react-native.git", :tag => "#{s.version}" }
15+
s.swift_version = "5"
16+
17+
s.dependency 'React'
18+
19+
s.ios.deployment_target = "14.0"
20+
s.ios.source_files = "ios/*.{swift,h,m}"
21+
22+
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('@fluentui-react-native/scripts/babel.config');
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#import <React/RCTBridgeModule.h>
2+
#import <React/RCTEventEmitter.h>
3+
4+
@interface FRNFontMetrics : RCTEventEmitter <RCTBridgeModule>
5+
@end
6+
7+
#import <React/RCTConvert.h>
8+
9+
typedef NS_ENUM(NSInteger, FRNTextStyle) {
10+
FRNTextStyleUndefined,
11+
FRNTextStyleCaption2,
12+
FRNTextStyleCaption1,
13+
FRNTextStyleFootnote,
14+
FRNTextStyleSubheadline,
15+
FRNTextStyleCallout,
16+
FRNTextStyleBody,
17+
FRNTextStyleHeadline,
18+
FRNTextStyleTitle3,
19+
FRNTextStyleTitle2,
20+
FRNTextStyleTitle1,
21+
FRNTextStyleLargeTitle
22+
};
23+
24+
@interface RCTConvert (FRNFontMetrics)
25+
26+
+ (FRNTextStyle)FRNTextStyle:(nullable id)json;
27+
28+
@end
29+
30+
UIFontMetrics *_Nonnull FRNUIFontMetricsForTextStyle(FRNTextStyle textStyle);
31+
CGFloat FRNBaseSizeForTextStyle(FRNTextStyle textStyle);
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#import "FRNFontMetrics.h"
2+
3+
static NSDictionary<NSString *, NSNumber *> *FRNRecognizedTextStyles() {
4+
static NSDictionary<NSString *, NSNumber *> *styles;
5+
static dispatch_once_t onceToken;
6+
dispatch_once(&onceToken, ^{
7+
styles = @{
8+
@"caption1": @(FRNTextStyleCaption1),
9+
@"caption2": @(FRNTextStyleCaption2),
10+
@"footnote": @(FRNTextStyleFootnote),
11+
@"subheadline": @(FRNTextStyleSubheadline),
12+
@"callout": @(FRNTextStyleCallout),
13+
@"body": @(FRNTextStyleBody),
14+
@"headline": @(FRNTextStyleHeadline),
15+
@"title3": @(FRNTextStyleTitle3),
16+
@"title2": @(FRNTextStyleTitle2),
17+
@"title1": @(FRNTextStyleTitle1),
18+
@"largeTitle": @(FRNTextStyleLargeTitle),
19+
};
20+
});
21+
return styles;
22+
}
23+
24+
@implementation RCTConvert (FRNTextStyle)
25+
26+
RCT_ENUM_CONVERTER(FRNTextStyle, FRNRecognizedTextStyles(), FRNTextStyleUndefined, integerValue)
27+
28+
@end
29+
30+
NS_ASSUME_NONNULL_BEGIN
31+
32+
UIFontMetrics *FRNUIFontMetricsForTextStyle(FRNTextStyle textStyle) {
33+
static NSDictionary<NSNumber *, UIFontTextStyle> *mapping;
34+
static dispatch_once_t onceToken;
35+
dispatch_once(&onceToken, ^{
36+
mapping = @{
37+
@(FRNTextStyleCaption2): UIFontTextStyleCaption2,
38+
@(FRNTextStyleCaption1): UIFontTextStyleCaption1,
39+
@(FRNTextStyleFootnote): UIFontTextStyleFootnote,
40+
@(FRNTextStyleSubheadline): UIFontTextStyleSubheadline,
41+
@(FRNTextStyleCallout): UIFontTextStyleCallout,
42+
@(FRNTextStyleBody): UIFontTextStyleBody,
43+
@(FRNTextStyleHeadline): UIFontTextStyleHeadline,
44+
@(FRNTextStyleTitle3): UIFontTextStyleTitle3,
45+
@(FRNTextStyleTitle2): UIFontTextStyleTitle2,
46+
@(FRNTextStyleTitle1): UIFontTextStyleTitle1,
47+
@(FRNTextStyleLargeTitle): UIFontTextStyleLargeTitle,
48+
};
49+
});
50+
51+
UIFontTextStyle uiFontTextStyle = mapping[@(textStyle)] ?: UIFontTextStyleBody; // Default to body if we don't recognize the specified ramp
52+
return [UIFontMetrics metricsForTextStyle:uiFontTextStyle];
53+
}
54+
55+
CGFloat FRNBaseSizeForTextStyle(FRNTextStyle textStyle) {
56+
static NSDictionary<NSNumber *, NSNumber *> *mapping;
57+
static dispatch_once_t onceToken;
58+
dispatch_once(&onceToken, ^{
59+
// Values taken from https://developer.apple.com/design/human-interface-guidelines/foundations/typography/#specifications
60+
mapping = @{
61+
@(FRNTextStyleCaption2): @11,
62+
@(FRNTextStyleCaption1): @12,
63+
@(FRNTextStyleFootnote): @13,
64+
@(FRNTextStyleSubheadline): @15,
65+
@(FRNTextStyleCallout): @16,
66+
@(FRNTextStyleBody): @17,
67+
@(FRNTextStyleHeadline): @17,
68+
@(FRNTextStyleTitle3): @20,
69+
@(FRNTextStyleTitle2): @22,
70+
@(FRNTextStyleTitle1): @28,
71+
@(FRNTextStyleLargeTitle): @34,
72+
};
73+
});
74+
75+
NSNumber *baseSize = mapping[@(textStyle)] ?: @17; // Default to body size if we don't recognize the specified ramp
76+
return CGFLOAT_IS_DOUBLE ? [baseSize doubleValue] : [baseSize floatValue];
77+
}
78+
79+
@implementation FRNFontMetrics {
80+
BOOL _hasListeners;
81+
}
82+
83+
+ (BOOL)requiresMainQueueSetup
84+
{
85+
return YES;
86+
}
87+
88+
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(allScaleFactors)
89+
{
90+
NSMutableDictionary *result = [NSMutableDictionary new];
91+
[FRNRecognizedTextStyles() enumerateKeysAndObjectsUsingBlock:^(NSString * styleString, __unused NSNumber * boxedTextStyle, __unused BOOL * stop) {
92+
result[styleString] = [self scaleFactorForStyle:styleString];
93+
}];
94+
return result;
95+
}
96+
97+
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(scaleFactorForStyle:(NSString *)styleString)
98+
{
99+
FRNTextStyle style = [RCTConvert FRNTextStyle:styleString];
100+
UIFontMetrics *fontMetrics = FRNUIFontMetricsForTextStyle(style);
101+
CGFloat baseSize = FRNBaseSizeForTextStyle(style);
102+
CGFloat scaleFactor = [fontMetrics scaledValueForValue:baseSize] / baseSize;
103+
return @(scaleFactor);
104+
}
105+
106+
#pragma mark - RCTEventEmitter
107+
108+
- (NSArray<NSString *> *)supportedEvents
109+
{
110+
return @[ @"onFontMetricsChanged" ];
111+
}
112+
113+
- (void)startObserving
114+
{
115+
_hasListeners = YES;
116+
[[NSNotificationCenter defaultCenter] addObserver:self
117+
selector:@selector(onFontMetricsChanged:)
118+
name:UIContentSizeCategoryDidChangeNotification
119+
object:nil];
120+
}
121+
122+
- (void)stopObserving
123+
{
124+
_hasListeners = NO;
125+
[[NSNotificationCenter defaultCenter] removeObserver:self];
126+
}
127+
128+
#pragma mark - Event processing
129+
130+
- (void)onFontMetricsChanged:(NSNotification *)notification {
131+
if (_hasListeners) {
132+
[self sendEventWithName:@"onFontMetricsChanged" body:@{@"newScaleFactors": [self allScaleFactors]}];
133+
}
134+
}
135+
136+
RCT_EXPORT_MODULE();
137+
138+
@end
139+
140+
NS_ASSUME_NONNULL_END
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// This dummy project file is required for @react-native-community/cli <8.0 to recognize this package as a native module
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const { preset } = require('@fluentui-react-native/scripts');
2+
3+
preset();
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"name": "@fluentui-react-native/experimental-native-font-metrics",
3+
"version": "0.1.0",
4+
"description": "A temporary partial wrapper for UIFontMetrics.",
5+
"license": "MIT",
6+
"author": "Microsoft <[email protected]>",
7+
"homepage": "https://github.com/microsoft/fluentui-react-native",
8+
"main": "src/index.ts",
9+
"module": "src/index.ts",
10+
"typings": "lib/index.d.ts",
11+
"onPublish": {
12+
"main": "lib-commonjs/index.js",
13+
"module": "lib/index.js"
14+
},
15+
"scripts": {
16+
"build": "fluentui-scripts build",
17+
"just": "fluentui-scripts",
18+
"clean": "fluentui-scripts clean",
19+
"lint": "fluentui-scripts eslint",
20+
"depcheck": "fluentui-scripts depcheck",
21+
"test": "fluentui-scripts jest",
22+
"update-snapshots": "fluentui-scripts jest -u",
23+
"prettier": "fluentui-scripts prettier",
24+
"prettier-fix": "fluentui-scripts prettier --fix true"
25+
},
26+
"repository": {
27+
"type": "git",
28+
"url": "https://github.com/microsoft/fluentui-react-native.git",
29+
"directory": "packages/experimental/NativeFontMetrics"
30+
},
31+
"devDependencies": {
32+
"@fluentui-react-native/eslint-config-rules": "^0.1.1",
33+
"@fluentui-react-native/scripts": "^0.1.1",
34+
"@types/react-native": "^0.68.0",
35+
"@types/use-subscription": "1.0.0",
36+
"react": "17.0.2",
37+
"react-native": "^0.68.0",
38+
"use-subscription": ">=1.0.0 <1.6.0"
39+
},
40+
"peerDependencies": {
41+
"react": "17.0.2",
42+
"react-native": "^0.68.0"
43+
},
44+
"rnx-kit": {
45+
"reactNativeVersion": "^0.68",
46+
"reactNativeDevVersion": "^0.68",
47+
"kitType": "library",
48+
"capabilities": [
49+
"core",
50+
"core-ios",
51+
"react"
52+
]
53+
}
54+
}

0 commit comments

Comments
 (0)