Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use FRNFontMetrics module in Text #2269

Merged
merged 43 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b7dd30e
Add FRNFontMetrics module
Oct 24, 2022
0e07035
Remove debugging `console.log` statements
Oct 24, 2022
f1aa83c
Use a hook to access font metrics
Nov 2, 2022
52b4fcf
Merge branch 'main' into furn-font-metrics
Nov 2, 2022
708530a
Add NativeFontMetrics package
Nov 2, 2022
cbcff5a
Remove unneeded API
Nov 3, 2022
f57023d
Fix spacing
Nov 3, 2022
98d8e12
Change files
Nov 3, 2022
96e09be
Add @types/use-subscription dependency
Nov 3, 2022
4b9eabc
Update yarn.lock
Nov 3, 2022
37191a3
Add use-subscription as a dependency
Nov 3, 2022
4743422
Update yarn.lock again
Nov 3, 2022
f6f5b17
NativeFontMetrics.tsx -> NativeFontMetrics.ts
Nov 3, 2022
245fd82
Make NativeFontMetrics iOS only, part 1
Nov 3, 2022
a4f879f
Stub out NativeFontMetrics for non-iOS platforms
Nov 3, 2022
2a25072
Keep use-subscription version consistent with react-native and react-…
Nov 3, 2022
0c97508
Remove core-android capability
Nov 4, 2022
ef44158
id -> UIFontTextStyle
Nov 4, 2022
c4c6015
Merge branch 'furn-font-metrics-package' into furn-font-metrics
Nov 4, 2022
2a9b966
Merge branch 'main' into furn-font-metrics
Nov 8, 2022
1e5c687
Delete old changefile
Nov 8, 2022
caa7688
Regenerate lockfiles
Nov 8, 2022
0b4f3df
Delete duplicate NativeFontMetrics.tsx file
Nov 8, 2022
2567141
Change files
Nov 8, 2022
7ac2160
allScaleFactors -> currentScaleFactors
Nov 11, 2022
c855df3
Use pure events to update font metrics
Nov 11, 2022
cf11e47
Update package.nuspec
Nov 11, 2022
bc4cb87
Merge branch 'main' into furn-font-metrics
Nov 11, 2022
a84bceb
Use pure JS hook to make V2 Texts rerender
Nov 16, 2022
b4cfea8
Merge branch 'main' into furn-font-metrics
Nov 17, 2022
205976b
Change files
Nov 17, 2022
ee4eedf
Update snapshot
Nov 17, 2022
4b88f71
Remove unneeded dependency
Nov 17, 2022
14dc48b
Move fontMetrics to iOS specific file
Nov 18, 2022
f4f7b91
Better isolation of iOS-specific code
Nov 18, 2022
b075082
Add useFontMetrics.ios.ts
Nov 19, 2022
eda4c62
Remove useFontMetricsScaleFactors warning on non-iOS platforms
Nov 21, 2022
2d46157
Move fontMetrics accesses outside of continuation, and improve typing
Nov 22, 2022
ce812bc
Fix Text rerender shallow equality test
Nov 22, 2022
1bfe8a5
Handle case when NativeFontMetrics isn't defined
Nov 22, 2022
3741063
IFontMetrics -> FontMetrics
Nov 22, 2022
88a099d
Keep `mergedProps` spreads next to each other
Nov 28, 2022
7871a01
Merge branch 'main' into furn-font-metrics
Nov 28, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/fluent-tester/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ use_test_app! do |target|
target.app do
platform :ios, '14.0'

# There is a bug where autolinking isn't working, do specify these manually.
pod 'FRNFontMetrics', :path => '../../../packages/experimental/NativeFontMetrics/FRNFontMetrics.podspec'

script_phase name: 'Start Packager',
script: start_packager_script,
execution_position: :before_compile
Expand Down
16 changes: 11 additions & 5 deletions apps/fluent-tester/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ PODS:
- React-jsi (= 0.68.5)
- ReactCommon/turbomodule/core (= 0.68.5)
- fmt (6.2.1)
- FRNAvatar (0.16.20):
- FRNAvatar (0.16.24):
- MicrosoftFluentUI (= 0.8.3)
- React
- FRNDatePicker (0.7.3):
- MicrosoftFluentUI (= 0.8.3)
- React
- FRNFontMetrics (0.2.0):
- React
- glog (0.3.5)
- MicrosoftFluentUI (0.8.3):
- MicrosoftFluentUI/ActivityIndicator_ios (= 0.8.3)
Expand Down Expand Up @@ -384,7 +386,7 @@ PODS:
- glog
- react-native-menu (0.1.2):
- React
- react-native-slider (4.3.2):
- react-native-slider (4.3.3):
- React-Core
- React-perflogger (0.68.5)
- React-RCTActionSheet (0.68.5):
Expand Down Expand Up @@ -468,6 +470,7 @@ DEPENDENCIES:
- FBReactNativeSpec (from `../../../node_modules/react-native/React/FBReactNativeSpec`)
- FRNAvatar (from `../../../packages/experimental/Avatar`)
- FRNDatePicker (from `../../../packages/experimental/NativeDatePicker`)
- FRNFontMetrics (from `../../../packages/experimental/NativeFontMetrics/FRNFontMetrics.podspec`)
- glog (from `../../../node_modules/react-native/third-party-podspecs/glog.podspec`)
- RCT-Folly (from `../../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTRequired (from `../../../node_modules/react-native/Libraries/RCTRequired`)
Expand Down Expand Up @@ -522,6 +525,8 @@ EXTERNAL SOURCES:
:path: "../../../packages/experimental/Avatar"
FRNDatePicker:
:path: "../../../packages/experimental/NativeDatePicker"
FRNFontMetrics:
:path: "../../../packages/experimental/NativeFontMetrics/FRNFontMetrics.podspec"
glog:
:podspec: "../../../node_modules/react-native/third-party-podspecs/glog.podspec"
RCT-Folly:
Expand Down Expand Up @@ -595,8 +600,9 @@ SPEC CHECKSUMS:
FBLazyVector: 2b47ff52037bd9ae07cc9b051c9975797814b736
FBReactNativeSpec: dd89c4a5591e20015aa55c6efbf9c7740a83efbf
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
FRNAvatar: de1aec8a9011ade478f2148677b4f2c076d77110
FRNAvatar: 3911021ed95a08f19e0ee696712aa48b6dff010a
FRNDatePicker: 241cd55b8d2b63d4427d782951f31504f09fbe1a
FRNFontMetrics: 472e7952e454ece364a91babd8bb2a32219676e7
glog: 476ee3e89abb49e07f822b48323c51c57124b572
MicrosoftFluentUI: e30487dd18aba04beeed4caf1ce1988073f8b03a
RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8
Expand All @@ -613,7 +619,7 @@ SPEC CHECKSUMS:
React-jsinspector: eb202e43b3879aba9a14f3f65788aec85d4e1ea9
React-logger: 98f663b292a60967ebbc6d803ae96c1381183b6d
react-native-menu: 9fe07f72e075b250295eeae25425490cc9608951
react-native-slider: e540525ea731783850802b7af457d8551edb0711
react-native-slider: 7d19220da2f2ae7cbb9aa80127cb73c597fa221f
React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f
React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9
React-RCTAnimation: 732ce66878d4aa151d56a0d142b1105aa12fd313
Expand All @@ -632,6 +638,6 @@ SPEC CHECKSUMS:
RNSVG: 302bfc9905bd8122f08966dc2ce2d07b7b52b9f8
Yoga: c4d61225a466f250c35c1ee78d2d0b3d41fe661c

PODFILE CHECKSUM: eeba196fb25cf059c631787109cecd08a4ac85a6
PODFILE CHECKSUM: 819f14a4e3e6e335a0b1993fe37edad50db02d86

COCOAPODS: 1.11.3
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Send new font metrics information through a JS event",
"packageName": "@fluentui-react-native/experimental-native-font-metrics",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Add Dynamic Type support",
"packageName": "@fluentui-react-native/tester",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Add Dynamic Type support",
"packageName": "@fluentui-react-native/text",
"email": "[email protected]",
"dependentChangeType": "patch"
}
2 changes: 2 additions & 0 deletions package.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
<!-- iOS device ship -->
<file src="DerivedData\Build\Products\Release-iphoneos\FRNAvatar\libFRNAvatar.a" target="Ship-iphoneos"/>
<file src="DerivedData\Build\Products\Release-iphoneos\FRNDatePicker\libFRNDatePicker.a" target="Ship-iphoneos"/>
<file src="DerivedData\Build\Products\Release-iphoneos\FRNFontMetrics\libFRNFontMetrics.a" target="Ship-iphoneos"/>

<!-- iOS simulator ship -->
<file src="DerivedData\Build\Products\Release-iphonesimulator\FRNAvatar\libFRNAvatar.a" target="Ship-iphonesimulator"/>
<file src="DerivedData\Build\Products\Release-iphonesimulator\FRNDatePicker\libFRNDatePicker.a" target="Ship-iphonesimulator"/>
<file src="DerivedData\Build\Products\Release-iphonesimulator\FRNFontMetrics\libFRNFontMetrics.a" target="Ship-iphoneos"/>

<!-- macOS ship -->
<file src="DerivedData\Build\Products\Release\FRNAvatar\libFRNAvatar.a" target="Ship-macosx"/>
Expand Down
1 change: 1 addition & 0 deletions packages/components/text/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"dependencies": {
"@uifabricshared/foundation-compose": "^1.12.21",
"@fluentui-react-native/adapters": ">=0.10.0 <1.0.0",
"@fluentui-react-native/experimental-native-font-metrics": "^0.2.0",
"@fluentui-react-native/framework": "0.8.20",
"@fluentui-react-native/interactive-hooks": ">=0.21.1 <1.0.0",
"@fluentui-react-native/theme-tokens": ">=0.21.3 <1.0.0",
Expand Down
23 changes: 22 additions & 1 deletion packages/components/text/src/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { I18nManager, Platform, Text as RNText } from 'react-native';
import { textName, TextProps, TextTokens } from './Text.types';
import { useTextTokens } from './TextTokens';
import React from 'react';
import { useFontMetricsScaleFactors } from '@fluentui-react-native/experimental-native-font-metrics';

const emptyProps = {};
export const Text = compressible<TextProps, TextTokens>((props: TextProps, useTokens: UseTokens<TextTokens>) => {
Expand Down Expand Up @@ -49,6 +50,9 @@ export const Text = compressible<TextProps, TextTokens>((props: TextProps, useTo
// get the tokens from the theme
let [tokens, cache] = useTokens(theme);

// TODO(#2268): Remove once RN Core properly supports Dynamic Type scaling
const fontMetricsScaleFactors = useFontMetricsScaleFactors();

amgleitman marked this conversation as resolved.
Show resolved Hide resolved
const textAlign = I18nManager.isRTL
? align === 'start'
? 'right'
Expand Down Expand Up @@ -79,6 +83,9 @@ export const Text = compressible<TextProps, TextTokens>((props: TextProps, useTo
[onPress, onAccessibilityTap],
);

// TODO(#2268): Remove once RN Core properly supports Dynamic Type scaling
const dynamicTypeVariant = Platform.OS === 'ios' ? tokens.dynamicTypeRamp : undefined;

amgleitman marked this conversation as resolved.
Show resolved Hide resolved
// override tokens from props
[tokens, cache] = patchTokens(tokens, cache, {
color,
Expand Down Expand Up @@ -106,6 +113,19 @@ export const Text = compressible<TextProps, TextTokens>((props: TextProps, useTo
['color', 'fontStyle', 'textAlign', 'textDecorationLine', ...fontStyles.keys],
);

// [TODO(#2268): Remove once RN Core properly supports Dynamic Type scaling
let scaleStyleAdjustments: TextTokens = emptyProps;
// tokenStyle.fontSize and tokenStyle.lineHeight can also be strings (e.g., "14px").
// Therefore, we only support scaling for number-based size values in order to avoid any messy calculations.
if (dynamicTypeVariant !== undefined && typeof tokenStyle.fontSize === 'number' && typeof tokenStyle.lineHeight === 'number') {
const scaleFactor = fontMetricsScaleFactors[dynamicTypeVariant] ?? 1;
scaleStyleAdjustments = {
fontSize: tokenStyle.fontSize * scaleFactor,
lineHeight: tokenStyle.lineHeight * scaleFactor,
};
}
// ]TODO(#2268)
amgleitman marked this conversation as resolved.
Show resolved Hide resolved

const isWinPlatform = Platform.OS === (('win32' as any) || 'windows');
const filteredProps = {
onKeyUp: isWinPlatform ? onKeyUp : undefined,
Expand All @@ -126,7 +146,8 @@ export const Text = compressible<TextProps, TextTokens>((props: TextProps, useTo
...extra,
onPress,
numberOfLines: truncate || !wrap ? 1 : 0,
style: mergeStyles(tokenStyle, props.style, extra?.style),
style: mergeStyles(tokenStyle, props.style, extra?.style, scaleStyleAdjustments),
...(dynamicTypeVariant !== undefined && { allowFontScaling: false }), // TODO(#2268): Remove once RN Core properly supports Dynamic Type scaling
amgleitman marked this conversation as resolved.
Show resolved Hide resolved
};
return (
<RNText ellipsizeMode={!wrap && !truncate ? 'clip' : 'tail'} {...mergedProps}>
Expand Down
6 changes: 5 additions & 1 deletion packages/components/text/src/Text.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ export const textName = 'Text';
* Text tokens, these are the internally configurable values for Text elements. In particular these
* drive decisions on how to build the styles
*/
export type TextTokens = Omit<FontTokens, 'fontFamily'> & IForegroundColorTokens & Omit<TextStyle, 'fontSize' | 'fontWeight' | 'color'>;
export type TextTokens = Omit<FontTokens, 'fontFamily'> &
IForegroundColorTokens &
Omit<TextStyle, 'fontSize' | 'fontWeight' | 'color'> & {
dynamicTypeRamp?: string; // TODO(#2268): Remove once RN Core properly supports Dynamic Type scaling
amgleitman marked this conversation as resolved.
Show resolved Hide resolved
};

export type TextAlign = 'start' | 'center' | 'end' | 'justify';
export type TextFont = 'base' | 'monospace' | 'numeric';
Expand Down
38 changes: 26 additions & 12 deletions packages/components/text/src/Variants.ios.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,57 @@
import { Text } from './Text';

// TODO(#2268): Remove "as any" designations once RN Core properly supports Dynamic Type scaling

export const Caption1 = Text.customize({
variant: 'caption1',
});
dynamicTypeRamp: 'footnote',
amgleitman marked this conversation as resolved.
Show resolved Hide resolved
} as any);
export const Caption1Strong = Text.customize({
variant: 'caption1Strong',
});
dynamicTypeRamp: 'footnote',
} as any);
export const Caption2 = Text.customize({
variant: 'caption2',
});
dynamicTypeRamp: 'caption1',
} as any);
export const Body1 = Text.customize({
variant: 'body1',
});
dynamicTypeRamp: 'body',
} as any);
export const Body1Strong = Text.customize({
variant: 'body1Strong',
});
dynamicTypeRamp: 'body',
} as any);
export const Body2 = Text.customize({
variant: 'body2',
});
dynamicTypeRamp: 'subheadline',
} as any);
export const Body2Strong = Text.customize({
variant: 'body2Strong',
});
dynamicTypeRamp: 'subheadline',
} as any);
export const Subtitle1 = null; // Not supported on iOS
export const Subtitle1Strong = null; // Not supported on iOS
export const Subtitle2 = null; // Not supported on iOS
export const Subtitle2Strong = null; // Not supported on iOS
export const Title1 = Text.customize({
variant: 'title1',
});
dynamicTypeRamp: 'title1',
} as any);
export const Title1Strong = null; // Not supported on iOS
export const Title2 = Text.customize({
variant: 'title2',
});
dynamicTypeRamp: 'title2',
} as any);
export const Title3 = Text.customize({
variant: 'title3',
});
dynamicTypeRamp: 'title3',
} as any);
export const LargeTitle = Text.customize({
variant: 'largeTitle',
});
dynamicTypeRamp: 'largeTitle',
} as any);
export const Display = Text.customize({
variant: 'display',
});
dynamicTypeRamp: 'largeTitle',
} as any);
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ + (BOOL)requiresMainQueueSetup
return YES;
}

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(allScaleFactors)
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(currentScaleFactors)
{
NSMutableDictionary *result = [NSMutableDictionary new];
[FRNRecognizedTextStyles() enumerateKeysAndObjectsUsingBlock:^(NSString * styleString, __unused NSNumber * boxedTextStyle, __unused BOOL * stop) {
Expand Down Expand Up @@ -129,7 +129,7 @@ - (void)stopObserving

- (void)onFontMetricsChanged:(NSNotification *)notification {
if (_hasListeners) {
[self sendEventWithName:@"onFontMetricsChanged" body:@{@"newScaleFactors": [self allScaleFactors]}];
[self sendEventWithName:@"onFontMetricsChanged" body:@{@"newScaleFactors": [self currentScaleFactors]}];
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { ScaleFactors, TextStyle } from './NativeFontMetrics.types';
export const NativeFontMetrics = NativeModules.FRNFontMetrics;

interface NativeFontMetricsInterface {
allScaleFactors(): ScaleFactors;
currentScaleFactors(): ScaleFactors;
scaleFactorForStyle(style: TextStyle): number;
}

export default NativeFontMetrics as NativeFontMetricsInterface;
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { ScaleFactors, TextStyle } from './NativeFontMetrics.types';
import { TextStyle } from './NativeFontMetrics.types';

interface NativeFontMetricsInterface {
allScaleFactors(): ScaleFactors;
scaleFactorForStyle(style: TextStyle): number;
}

const NativeFontMetrics: NativeFontMetricsInterface = {
allScaleFactors: () => {
const NativeFontMetrics = {
// eslint-disable-next-line @typescript-eslint/no-empty-function
addListener: (_: string) => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
removeListeners: (_: number) => {},
currentScaleFactors: () => {
console.warn('NativeFontMetrics is only available on iOS');
return {};
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
export interface FontMetrics {
readonly scaleFactors: ScaleFactors;
}

export type ScaleFactors = { [K in TextStyle]?: number };

export type TextStyle =
| 'caption2'
| 'caption1'
Expand All @@ -10,5 +16,3 @@ export type TextStyle =
| 'title2'
| 'title1'
| 'largeTitle';

export type ScaleFactors = { [K in TextStyle]?: number };
25 changes: 25 additions & 0 deletions packages/experimental/NativeFontMetrics/src/fontMetrics.ios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { NativeEventEmitter } from 'react-native';
import NativeFontMetrics from './NativeFontMetrics';
import { FontMetrics, ScaleFactors } from './NativeFontMetrics.types';

class FontMetricsImpl implements FontMetrics {
_scaleFactors: ScaleFactors;

constructor() {
if (NativeFontMetrics) {
this._scaleFactors = NativeFontMetrics.currentScaleFactors();
const eventEmitter = new NativeEventEmitter(NativeFontMetrics as any);
eventEmitter.addListener('onFontMetricsChanged', ({ newScaleFactors }) => {
this._scaleFactors = newScaleFactors;
});
} else {
this._scaleFactors = {};
}
}

get scaleFactors(): ScaleFactors {
return this._scaleFactors;
}
}

export const fontMetrics = new FontMetricsImpl() as FontMetrics;
3 changes: 3 additions & 0 deletions packages/experimental/NativeFontMetrics/src/fontMetrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { FontMetrics } from './NativeFontMetrics.types';

export const fontMetrics = { scaleFactors: {} } as FontMetrics;
1 change: 0 additions & 1 deletion packages/experimental/NativeFontMetrics/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './NativeFontMetrics';
export * from './useFontMetrics';
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useMemo } from 'react';
import { NativeEventEmitter } from 'react-native';
import { useSubscription } from 'use-subscription';
import { fontMetrics } from './fontMetrics';
import NativeFontMetrics from './NativeFontMetrics';
import { ScaleFactors } from './NativeFontMetrics.types';

const eventEmitter = NativeFontMetrics ? new NativeEventEmitter(NativeFontMetrics as any) : undefined;

export function useFontMetricsScaleFactors(): ScaleFactors {
if (!eventEmitter) {
return {};
}

const subscription = useMemo(
() => ({
getCurrentValue: () => fontMetrics.scaleFactors,
subscribe: (callback) => {
const appearanceSubscription = eventEmitter.addListener('onFontMetricsChanged', callback);
return () => {
appearanceSubscription.remove();
};
},
}),
[],
);

return useSubscription(subscription);
}
Loading