Add maximumFontSize (#2389)
* Add maximumSize * Remove extra LimitedDisplay customization * Change files * Simplify maximumFontSize math * grammar * Add comment about iOS-only FontStyleTokens props * Add documentation for custom TextTokens * TODO(#2268) -> GH #2268 * Add MaximumFontSize test element * Organize imports * Change files Co-authored-by: Adam Gleitman <adgleitm@microsoft.com>
This commit is contained in:
Родитель
3500d25b49
Коммит
ac1a77d965
|
@ -10,7 +10,7 @@ PODS:
|
|||
- React-jsi (= 0.68.5)
|
||||
- ReactCommon/turbomodule/core (= 0.68.5)
|
||||
- fmt (6.2.1)
|
||||
- FRNAvatar (0.16.25):
|
||||
- FRNAvatar (0.16.26):
|
||||
- MicrosoftFluentUI (= 0.8.3)
|
||||
- React
|
||||
- FRNDatePicker (0.7.3):
|
||||
|
@ -453,7 +453,7 @@ PODS:
|
|||
- React-jsi (= 0.68.5)
|
||||
- React-logger (= 0.68.5)
|
||||
- React-perflogger (= 0.68.5)
|
||||
- ReactTestApp-DevSupport (2.1.0):
|
||||
- ReactTestApp-DevSupport (2.1.1):
|
||||
- React-Core
|
||||
- React-jsi
|
||||
- ReactTestApp-Resources (1.0.0-dev)
|
||||
|
@ -600,7 +600,7 @@ SPEC CHECKSUMS:
|
|||
FBLazyVector: 2b47ff52037bd9ae07cc9b051c9975797814b736
|
||||
FBReactNativeSpec: dd89c4a5591e20015aa55c6efbf9c7740a83efbf
|
||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||
FRNAvatar: 0c18045ffd13fb317f27c4111c5de6f4ad0ab1a8
|
||||
FRNAvatar: b34747d6662c3c556970518a0f3d886eca2205b8
|
||||
FRNDatePicker: 241cd55b8d2b63d4427d782951f31504f09fbe1a
|
||||
FRNFontMetrics: c756b9bb1627909a7673b68caf7a7b14239c212e
|
||||
glog: 476ee3e89abb49e07f822b48323c51c57124b572
|
||||
|
@ -632,7 +632,7 @@ SPEC CHECKSUMS:
|
|||
React-RCTVibration: 9819a3bf6230e4b2a99877c21268b0b2416157a1
|
||||
React-runtimeexecutor: b1f1995089b90696dbc2a7ffe0059a80db5c8eb1
|
||||
ReactCommon: 149e2c0acab9bac61378da0db5b2880a1b5ff59b
|
||||
ReactTestApp-DevSupport: bc72bbe8928c428f73e23d740fb13161609d9b9d
|
||||
ReactTestApp-DevSupport: 7ca8e4d798fce59f47adedd8f05a94d41d312921
|
||||
ReactTestApp-Resources: ecba662266ac5af3e30e1e3004c0fa8c0298b61a
|
||||
RNCPicker: 0bf8ef8f7800524f32d2bb2a8bcadd53eda0ecd1
|
||||
RNSVG: 302bfc9905bd8122f08966dc2ce2d07b7b52b9f8
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import * as React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { Stack } from '@fluentui-react-native/stack';
|
||||
import { stackStyle } from '../Common/styles';
|
||||
import { Caption1, Title2, Title3 } from '@fluentui-react-native/text';
|
||||
import { Separator } from '@fluentui/react-native';
|
||||
|
||||
const maximumFontSizeStyle = { maximumFontSize: 36 };
|
||||
|
||||
const CappedTitle2 = Title2.customize(maximumFontSizeStyle);
|
||||
const CappedTitle3 = Title3.customize(maximumFontSizeStyle);
|
||||
|
||||
export const MaximumFontSizeUsage: React.FunctionComponent = () => {
|
||||
return (
|
||||
<View>
|
||||
<Stack style={stackStyle} gap={5}>
|
||||
<Caption1>Play with the preferred content size. The marked elements should not grow larger than 36 points.</Caption1>
|
||||
<Separator />
|
||||
<Title2>Title2</Title2>
|
||||
<Title3>Title3</Title3>
|
||||
<CappedTitle2>Title2 (capped)</CappedTitle2>
|
||||
<CappedTitle3>Title3 (capped)</CappedTitle3>
|
||||
<Text allowFontScaling={false} style={{ fontSize: 36, fontWeight: '600' }}>
|
||||
This is 36 pt
|
||||
</Text>
|
||||
</Stack>
|
||||
</View>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
import * as React from 'react';
|
||||
import { Text } from 'react-native';
|
||||
|
||||
export const MaximumFontSizeUsage: React.FunctionComponent = () => {
|
||||
return <Text>Only available on iOS.</Text>;
|
||||
};
|
|
@ -1,11 +1,12 @@
|
|||
import * as React from 'react';
|
||||
import { StandardUsage } from './StandardUsage';
|
||||
import { V2Usage } from './V2Usage';
|
||||
import { MaximumFontSizeUsage } from './MaximumFontSize';
|
||||
import { CustomizeUsage } from './CustomizeUsage';
|
||||
import { PressableUsage } from './PressableUsage';
|
||||
import { Test, TestSection, PlatformStatus } from '../Test';
|
||||
import { E2EExperimentalTextTest } from './ExperimentalTextE2ETest';
|
||||
import { EXPERIMENTAL_TEXT_TESTPAGE } from './consts';
|
||||
import { V2Usage } from './V2Usage';
|
||||
|
||||
const textSections: TestSection[] = [
|
||||
{
|
||||
|
@ -17,6 +18,10 @@ const textSections: TestSection[] = [
|
|||
name: 'V2/V1 Comparison',
|
||||
component: V2Usage,
|
||||
},
|
||||
{
|
||||
name: 'Maximum Font Size Usage',
|
||||
component: MaximumFontSizeUsage,
|
||||
},
|
||||
{
|
||||
name: 'Customize Usage',
|
||||
component: CustomizeUsage,
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "patch",
|
||||
"comment": "Add maximumSize",
|
||||
"packageName": "@fluentui-react-native/button",
|
||||
"email": "adgleitm@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "Add maximumSize",
|
||||
"packageName": "@fluentui-react-native/tester",
|
||||
"email": "adgleitm@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "Add maximumSize",
|
||||
"packageName": "@fluentui-react-native/text",
|
||||
"email": "adgleitm@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "Add MaximumFontSize test element",
|
||||
"packageName": "@fluentui-react-native/theme-types",
|
||||
"email": "adgleitm@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "minor",
|
||||
"comment": "Add maximumSize",
|
||||
"packageName": "@fluentui-react-native/tokens",
|
||||
"email": "adgleitm@microsoft.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
|
@ -107,6 +107,7 @@ exports[`Button component tests Button composed 1`] = `
|
|||
"marginEnd": 0,
|
||||
"marginStart": 0,
|
||||
"marginTop": 0,
|
||||
"maximumFontSize": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
|
|
|
@ -50,7 +50,7 @@ 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
|
||||
// GH #2268: Remove once RN Core properly supports Dynamic Type scaling
|
||||
const fontMetricsScaleFactors = useFontMetricsScaleFactors();
|
||||
|
||||
const textAlign = I18nManager.isRTL
|
||||
|
@ -88,6 +88,7 @@ export const Text = compressible<TextProps, TextTokens>((props: TextProps, useTo
|
|||
color,
|
||||
variant,
|
||||
fontFamily: font == 'base' ? 'primary' : font,
|
||||
fontMaximumSize: tokens.maximumFontSize,
|
||||
fontSize: globalTokens.font['size' + size],
|
||||
fontWeight: globalTokens.font.weight[weight] as FontWeightValue,
|
||||
// leave it undefined for tokens to be set by user
|
||||
|
@ -110,21 +111,24 @@ 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
|
||||
// [GH #2268: Remove once RN Core properly supports Dynamic Type scaling
|
||||
const dynamicTypeVariant = Platform.OS === 'ios' ? tokenStyle.dynamicTypeRamp : undefined;
|
||||
const maximumFontSize = tokenStyle.maximumFontSize ?? Number.POSITIVE_INFINITY;
|
||||
|
||||
// [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;
|
||||
const requestedScaleFactor = fontMetricsScaleFactors[dynamicTypeVariant] ?? 1;
|
||||
const maximumScaleFactor = maximumFontSize / tokenStyle.fontSize;
|
||||
const scaleFactor = Math.min(requestedScaleFactor, maximumScaleFactor);
|
||||
|
||||
scaleStyleAdjustments = {
|
||||
fontSize: tokenStyle.fontSize * scaleFactor,
|
||||
lineHeight: tokenStyle.lineHeight * scaleFactor,
|
||||
lineHeight: tokenStyle.lineHeight * scaleFactor, // scale accordingly with fontSize
|
||||
};
|
||||
}
|
||||
// ]TODO(#2268)
|
||||
// ]GH #2268
|
||||
|
||||
const isWinPlatform = Platform.OS === (('win32' as any) || 'windows');
|
||||
const filteredProps = {
|
||||
|
@ -144,12 +148,16 @@ 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
|
||||
...(dynamicTypeVariant !== undefined && { allowFontScaling: false }), // GH #2268: Remove once RN Core properly supports Dynamic Type scaling
|
||||
onPress,
|
||||
numberOfLines: truncate || !wrap ? 1 : 0,
|
||||
style: mergeStyles(tokenStyle, props.style, extra?.style, scaleStyleAdjustments),
|
||||
};
|
||||
delete (mergedProps.style as TextTokens).dynamicTypeRamp; // TODO(#2268): RN Text doesn't recognize dynamicTypeRamp yet, so don't let it leak through or RN will complain about it being an invalid prop
|
||||
|
||||
// GH #2268: RN Text doesn't recognize these properties yet, so don't let them leak through or RN will complain about invalid props
|
||||
delete (mergedProps.style as TextTokens).dynamicTypeRamp;
|
||||
delete (mergedProps.style as TextTokens).maximumFontSize;
|
||||
|
||||
return (
|
||||
<RNText ellipsizeMode={!wrap && !truncate ? 'clip' : 'tail'} {...mergedProps}>
|
||||
{children}
|
||||
|
|
|
@ -11,7 +11,18 @@ export const textName = 'Text';
|
|||
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
|
||||
// GH #2268: Remove these once RN Core properly supports Dynamic Type scaling
|
||||
/**
|
||||
* (iOS only) The Dynamic Type ramp that a Text element should follow as the user changes their
|
||||
* preferred content size.
|
||||
*/
|
||||
dynamicTypeRamp?: string;
|
||||
|
||||
/**
|
||||
* (iOS only) The maximum font size that a Text element will grow to as the user changes their
|
||||
* preferred content size.
|
||||
*/
|
||||
maximumFontSize?: number;
|
||||
};
|
||||
|
||||
export type TextAlign = 'start' | 'center' | 'end' | 'justify';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Text } from './Text';
|
||||
|
||||
// TODO(#2268): Remove "as any" designations once RN Core properly supports Dynamic Type scaling
|
||||
// GH #2268: Remove "as any" designations once RN Core properly supports Dynamic Type scaling
|
||||
|
||||
export const Caption1 = Text.customize({
|
||||
variant: 'caption1',
|
||||
|
|
|
@ -104,7 +104,7 @@ export type FontLetterSpacing = number;
|
|||
/**
|
||||
* On iOS, the Dynamic Type ramp that this variant should conform to.
|
||||
*/
|
||||
export type FontDynamicTypeRamp = string; // TODO(#2268): Import type from RN directly
|
||||
export type FontDynamicTypeRamp = string; // GH #2268: Import type from RN directly
|
||||
|
||||
/**
|
||||
* A font variant value.
|
||||
|
|
|
@ -14,14 +14,16 @@ export interface FontStyleTokens {
|
|||
fontWeight?: keyof Typography['weights'] | TextStyle['fontWeight'];
|
||||
fontLineHeight?: TextStyle['lineHeight'];
|
||||
fontLetterSpacing?: TextStyle['letterSpacing'];
|
||||
fontDynamicTypeRamp?: string; // TODO(#2268): Import type from RN directly
|
||||
// Props below are used on iOS only. GH #2268: Import these from RN directly
|
||||
fontDynamicTypeRamp?: string;
|
||||
fontMaximumSize?: number;
|
||||
}
|
||||
|
||||
export type FontTokens = FontStyleTokens & FontVariantTokens;
|
||||
|
||||
export const fontStyles: TokenBuilder<FontTokens> = {
|
||||
from: (
|
||||
{ fontDynamicTypeRamp, fontFamily, fontLetterSpacing, fontLineHeight, fontSize, fontWeight, variant }: FontTokens,
|
||||
{ fontDynamicTypeRamp, fontFamily, fontLetterSpacing, fontLineHeight, fontMaximumSize, fontSize, fontWeight, variant }: FontTokens,
|
||||
{ typography }: Theme,
|
||||
) => {
|
||||
const { families, sizes, weights, variants } = typography;
|
||||
|
@ -30,6 +32,7 @@ export const fontStyles: TokenBuilder<FontTokens> = {
|
|||
fontFamily !== undefined ||
|
||||
fontLetterSpacing !== undefined ||
|
||||
fontLineHeight !== undefined ||
|
||||
fontMaximumSize !== undefined ||
|
||||
fontSize !== undefined ||
|
||||
fontWeight !== undefined ||
|
||||
variant !== undefined
|
||||
|
@ -41,12 +44,22 @@ export const fontStyles: TokenBuilder<FontTokens> = {
|
|||
lineHeight: fontLineHeight ?? variants[variant]?.lineHeight,
|
||||
letterSpacing: fontLetterSpacing ?? variants[variant]?.letterSpacing,
|
||||
dynamicTypeRamp: fontDynamicTypeRamp ?? variants[variant]?.dynamicTypeRamp,
|
||||
maximumFontSize: fontMaximumSize,
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
},
|
||||
keys: ['fontDynamicTypeRamp', 'fontFamily', 'fontLineHeight', 'fontLetterSpacing', 'fontSize', 'fontWeight', 'variant'],
|
||||
keys: [
|
||||
'fontDynamicTypeRamp',
|
||||
'fontFamily',
|
||||
'fontLineHeight',
|
||||
'fontLetterSpacing',
|
||||
'fontMaximumSize',
|
||||
'fontSize',
|
||||
'fontWeight',
|
||||
'variant',
|
||||
],
|
||||
};
|
||||
|
||||
function _buildTextStyles(tokens: FontTokens, theme: Theme): ITextProps {
|
||||
|
|
Загрузка…
Ссылка в новой задаче