Use FRNFontMetrics module in `Text` (#2269)
* Add FRNFontMetrics module * Remove debugging `console.log` statements * Use a hook to access font metrics * 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 * Delete old changefile * Regenerate lockfiles * Delete duplicate NativeFontMetrics.tsx file * Change files * allScaleFactors -> currentScaleFactors * Use pure events to update font metrics * Update package.nuspec * Use pure JS hook to make V2 Texts rerender * Change files * Update snapshot * Remove unneeded dependency * Move fontMetrics to iOS specific file * Better isolation of iOS-specific code * Add useFontMetrics.ios.ts * Remove useFontMetricsScaleFactors warning on non-iOS platforms * Move fontMetrics accesses outside of continuation, and improve typing * Fix Text rerender shallow equality test * Handle case when NativeFontMetrics isn't defined * IFontMetrics -> FontMetrics * Keep `mergedProps` spreads next to each other Co-authored-by: Adam Gleitman <adgleitm@microsoft.com>
This commit is contained in:
Родитель
bc62b6fb1d
Коммит
1b0f4b66f9
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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`)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -632,6 +638,6 @@ SPEC CHECKSUMS:
|
|||
RNSVG: 302bfc9905bd8122f08966dc2ce2d07b7b52b9f8
|
||||
Yoga: c4d61225a466f250c35c1ee78d2d0b3d41fe661c
|
||||
|
||||
PODFILE CHECKSUM: eeba196fb25cf059c631787109cecd08a4ac85a6
|
||||
PODFILE CHECKSUM: 819f14a4e3e6e335a0b1993fe37edad50db02d86
|
||||
|
||||
COCOAPODS: 1.11.3
|
||||
|
|
|
@ -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": "adgleitm@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "Add Dynamic Type support",
|
||||
"packageName": "@fluentui-react-native/tester",
|
||||
"email": "adgleitm@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "Add Dynamic Type support",
|
||||
"packageName": "@fluentui-react-native/text",
|
||||
"email": "adgleitm@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -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"/>
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
"dependencies": {
|
||||
"@uifabricshared/foundation-compose": "^1.12.22",
|
||||
"@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.21",
|
||||
"@fluentui-react-native/interactive-hooks": ">=0.21.2 <1.0.0",
|
||||
"@fluentui-react-native/theme-tokens": ">=0.21.3 <1.0.0",
|
||||
|
|
|
@ -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>) => {
|
||||
|
@ -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();
|
||||
|
||||
const textAlign = I18nManager.isRTL
|
||||
? align === 'start'
|
||||
? 'right'
|
||||
|
@ -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;
|
||||
|
||||
// override tokens from props
|
||||
[tokens, cache] = patchTokens(tokens, cache, {
|
||||
color,
|
||||
|
@ -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)
|
||||
|
||||
const isWinPlatform = Platform.OS === (('win32' as any) || 'windows');
|
||||
const filteredProps = {
|
||||
onKeyUp: isWinPlatform ? onKeyUp : undefined,
|
||||
|
@ -124,9 +144,10 @@ export const Text = compressible<TextProps, TextTokens>((props: TextProps, useTo
|
|||
...keyProps,
|
||||
...filteredProps,
|
||||
...extra,
|
||||
...(dynamicTypeVariant !== undefined && { allowFontScaling: false }), // TODO(#2268): Remove once RN Core properly supports Dynamic Type scaling
|
||||
onPress,
|
||||
numberOfLines: truncate || !wrap ? 1 : 0,
|
||||
style: mergeStyles(tokenStyle, props.style, extra?.style),
|
||||
style: mergeStyles(tokenStyle, props.style, extra?.style, scaleStyleAdjustments),
|
||||
};
|
||||
return (
|
||||
<RNText ellipsizeMode={!wrap && !truncate ? 'clip' : 'tail'} {...mergedProps}>
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
export type TextAlign = 'start' | 'center' | 'end' | 'justify';
|
||||
export type TextFont = 'base' | 'monospace' | 'numeric';
|
||||
|
|
|
@ -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',
|
||||
} 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);
|
||||
|
|
|
@ -85,7 +85,7 @@ CGFloat FRNBaseSizeForTextStyle(FRNTextStyle textStyle) {
|
|||
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) {
|
||||
|
@ -129,7 +129,7 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(scaleFactorForStyle:(NSString *)styleStri
|
|||
|
||||
- (void)onFontMetricsChanged:(NSNotification *)notification {
|
||||
if (_hasListeners) {
|
||||
[self sendEventWithName:@"onFontMetricsChanged" body:@{@"newScaleFactors": [self allScaleFactors]}];
|
||||
[self sendEventWithName:@"onFontMetricsChanged" body:@{@"newScaleFactors": [self currentScaleFactors]}];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {};
|
||||
},
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
export interface FontMetrics {
|
||||
readonly scaleFactors: ScaleFactors;
|
||||
}
|
||||
|
||||
export type ScaleFactors = { [K in TextStyle]?: number };
|
||||
|
||||
export type TextStyle =
|
||||
| 'caption2'
|
||||
| 'caption1'
|
||||
|
@ -10,5 +16,3 @@ export type TextStyle =
|
|||
| 'title2'
|
||||
| 'title1'
|
||||
| 'largeTitle';
|
||||
|
||||
export type ScaleFactors = { [K in TextStyle]?: number };
|
||||
|
|
|
@ -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;
|
|
@ -0,0 +1,3 @@
|
|||
import { FontMetrics } from './NativeFontMetrics.types';
|
||||
|
||||
export const fontMetrics = { scaleFactors: {} } as FontMetrics;
|
|
@ -1,2 +1 @@
|
|||
export * from './NativeFontMetrics';
|
||||
export * from './useFontMetrics';
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -1,29 +1,6 @@
|
|||
import { useMemo } from 'react';
|
||||
import { NativeEventEmitter, Platform } from 'react-native';
|
||||
import { useSubscription } from 'use-subscription';
|
||||
import NativeFontMetrics from './NativeFontMetrics';
|
||||
import { ScaleFactors } from './NativeFontMetrics.types';
|
||||
|
||||
const eventEmitter = new NativeEventEmitter(NativeFontMetrics as any);
|
||||
|
||||
export function useFontMetrics(): ScaleFactors {
|
||||
if (Platform.OS !== 'ios') {
|
||||
console.warn('NativeFontMetrics is only available on iOS');
|
||||
return {};
|
||||
}
|
||||
|
||||
const subscription = useMemo(
|
||||
() => ({
|
||||
getCurrentValue: () => NativeFontMetrics.allScaleFactors(),
|
||||
subscribe: (callback) => {
|
||||
const appearanceSubscription = eventEmitter.addListener('onFontMetricsChanged', callback);
|
||||
return () => {
|
||||
appearanceSubscription.remove();
|
||||
};
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
return useSubscription(subscription);
|
||||
export function useFontMetricsScaleFactors(): ScaleFactors {
|
||||
// Stubbed out for non-iOS platforms
|
||||
return {};
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче