Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 178
Use FRNFontMetrics module in Text#2269
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
b7dd30e0e07035f1aa83c52b4fcf708530acbcff5af57023d98d8e1296e09be4b9eabc37191a34743422f6f5b17245fd82a4f879f2a250720c97508ef44158c4c60152a9b9661e5c687caa76880b4f3df25671417ac2160c855df3cf11e47bc4cb87a84bcebb4cfea8205976bee4eedf4b88f7114dc48bf4f7b91b075082eda4c622d46157ce812bc1bfe8a5374106388a099d7871a01File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| 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": "adgleitm@microsoft.com", | ||
| "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": "adgleitm@microsoft.com", | ||
| "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": "adgleitm@microsoft.com", | ||
| "dependentChangeType": "patch" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
amgleitman marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| // 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) | ||
amgleitman marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| 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}> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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.
Uh oh!There was an error while loading. Please reload this page. | ||
| }; | ||
| export type TextAlign = 'start' | 'center' | 'end' | 'justify'; | ||
| export type TextFont = 'base' | 'monospace' | 'numeric'; | ||
| 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.
Uh oh!There was an error while loading. Please reload this page. | ||
| } 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 |
|---|---|---|
| @@ -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; |
| 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; |
| 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); | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.