Skip to content

Commit 6d8afae

Browse files
amgleitmanAdam Gleitman
andauthored
Use alias token definitions for iOS typography (#2214)
* Use alias token definitions for iOS typography * Define `FontWeightValue` in terms of what RN says * Use theming-utils to fetch font alias tokens * Change files * Specify dynamic type ramps in mapPipelineToTheme * Add mapPipelineToTheme function * Update yarn.lock * Update Podfile.lock * Update FURN tokens version that theming-utils depends on * theming-utils tests were written for Windows Co-authored-by: Adam Gleitman <[email protected]>
1 parent 51d2c46 commit 6d8afae

10 files changed

+208
-103
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Use alias token definitions for iOS typography",
4+
"packageName": "@fluentui-react-native/apple-theme",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Use alias token definitions for iOS typography",
4+
"packageName": "@fluentui-react-native/tester",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Define `FontWeightValue` in terms of what RN says",
4+
"packageName": "@fluentui-react-native/theme-types",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "minor",
3+
"comment": "Use theming-utils to fetch font alias tokens",
4+
"packageName": "@fluentui-react-native/theming-utils",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

packages/theming/apple-theme/src/appleTypography.ios.ts

Lines changed: 2 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
import globalTokens from '@fluentui-react-native/design-tokens-ios/light/tokens-global.json';
2-
31
import { FontSize, FontSizes, FontWeightValue, Typography, Variants } from '@fluentui-react-native/theme-types';
4-
5-
const fontTokens = globalTokens.font;
2+
import { createFontAliasTokens } from './createFontAliasTokens.ios';
63

74
// The sizes are taken for the Dynamic Type Size "Large", which is the system default
85
export function appleTypography(): Typography {
@@ -50,102 +47,7 @@ export function appleTypography(): Typography {
5047
heroLargeStandard: { face: 'primary', size: 'heroLarge', weight: '400' },
5148
heroLargeSemibold: { face: 'primary', size: 'heroLarge', weight: '600' },
5249
// iOS styles
53-
caption2: {
54-
face: fontTokens.family.base,
55-
size: fontTokens.size100,
56-
weight: fontTokens.weight.regular,
57-
lineHeight: fontTokens.lineHeight100,
58-
letterSpacing: 0,
59-
dynamicTypeRamp: 'caption1', // Not a typo, this corresponds to UIFontTextStypeCaption1
60-
},
61-
caption1: {
62-
face: fontTokens.family.base,
63-
size: fontTokens.size200,
64-
weight: fontTokens.weight.regular,
65-
lineHeight: fontTokens.lineHeight200,
66-
letterSpacing: -0.08,
67-
dynamicTypeRamp: 'footnote',
68-
},
69-
caption1Strong: {
70-
face: fontTokens.family.base,
71-
size: fontTokens.size200,
72-
weight: fontTokens.weight.semibold,
73-
lineHeight: fontTokens.lineHeight200,
74-
letterSpacing: -0.08,
75-
dynamicTypeRamp: 'footnote',
76-
},
77-
body2: {
78-
face: fontTokens.family.base,
79-
size: fontTokens.size300,
80-
weight: fontTokens.weight.regular,
81-
lineHeight: fontTokens.lineHeight300,
82-
letterSpacing: -0.23,
83-
dynamicTypeRamp: 'subheadline',
84-
},
85-
body2Strong: {
86-
face: fontTokens.family.base,
87-
size: fontTokens.size300,
88-
weight: fontTokens.weight.semibold,
89-
lineHeight: fontTokens.lineHeight300,
90-
letterSpacing: -0.23,
91-
dynamicTypeRamp: 'subheadline',
92-
},
93-
body1: {
94-
face: fontTokens.family.base,
95-
size: fontTokens.size400,
96-
weight: fontTokens.weight.regular,
97-
lineHeight: fontTokens.lineHeight400,
98-
letterSpacing: -0.43,
99-
dynamicTypeRamp: 'body',
100-
},
101-
body1Strong: {
102-
face: fontTokens.family.base,
103-
size: fontTokens.size400,
104-
weight: fontTokens.weight.semibold,
105-
lineHeight: fontTokens.lineHeight400,
106-
letterSpacing: -0.43,
107-
dynamicTypeRamp: 'body',
108-
},
109-
title3: {
110-
face: fontTokens.family.base,
111-
size: fontTokens.size500,
112-
weight: fontTokens.weight.semibold,
113-
lineHeight: fontTokens.lineHeight500,
114-
letterSpacing: -0.45,
115-
dynamicTypeRamp: 'title3',
116-
},
117-
title2: {
118-
face: fontTokens.family.base,
119-
size: fontTokens.size600,
120-
weight: fontTokens.weight.semibold,
121-
lineHeight: fontTokens.lineHeight600,
122-
letterSpacing: -0.26,
123-
dynamicTypeRamp: 'title2',
124-
},
125-
title1: {
126-
face: fontTokens.family.base,
127-
size: fontTokens.size700,
128-
weight: fontTokens.weight.bold,
129-
lineHeight: fontTokens.lineHeight700,
130-
letterSpacing: 0.38,
131-
dynamicTypeRamp: 'title1',
132-
},
133-
largeTitle: {
134-
face: fontTokens.family.base,
135-
size: fontTokens.size800,
136-
weight: fontTokens.weight.bold,
137-
lineHeight: fontTokens.lineHeight800,
138-
letterSpacing: 0.4,
139-
dynamicTypeRamp: 'largeTitle',
140-
},
141-
display: {
142-
face: fontTokens.family.base,
143-
size: fontTokens.size900,
144-
weight: fontTokens.weight.bold,
145-
lineHeight: fontTokens.lineHeight900,
146-
letterSpacing: 0.26,
147-
dynamicTypeRamp: 'largeTitle',
148-
},
50+
...createFontAliasTokens(),
14951
} as Variants,
15052
};
15153

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import aliasTokens from '@fluentui-react-native/design-tokens-ios/light/tokens-aliases.json'; // Font alias tokens should be the same for all color styles
2+
import { Variants } from '@fluentui-react-native/theme-types';
3+
import { memoize } from '@fluentui-react-native/memo-cache';
4+
import { mapFontPipelineToTheme } from '@fluentui-react-native/theming-utils';
5+
6+
function createFontAliasTokensWorker(): Partial<Variants> {
7+
return mapFontPipelineToTheme(aliasTokens);
8+
}
9+
10+
export const createFontAliasTokens = memoize(createFontAliasTokensWorker);

packages/theming/theme-types/src/Typography.types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { TextStyle } from 'react-native';
2+
13
/**
24
* A font family designation, made up of one or more font names or groupings
35
* (comma-separated):
@@ -70,7 +72,7 @@ export type FontSize = keyof FontSizes | FontSizeValuePoints;
7072
* Smaller numbers yield a thinner, lighter font. Larger numbers yield a thicker, darker
7173
* font.
7274
*/
73-
export type FontWeightValue = '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
75+
export type FontWeightValue = TextStyle['fontWeight'];
7476

7577
/**
7678
* A collection of named font weights.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
const { configureReactNativeJest } = require('@fluentui-react-native/scripts');
2-
module.exports = configureReactNativeJest('ios');
2+
module.exports = configureReactNativeJest('windows');

packages/theming/theming-utils/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"prettier-fix": "fluentui-scripts prettier --fix true"
2727
},
2828
"dependencies": {
29-
"@fluentui-react-native/theme-types": ">=0.27.1 <1.0.0"
29+
"@fluentui-react-native/theme-types": ">=0.27.1 <1.0.0",
30+
"@fluentui-react-native/tokens": ">=0.20.0 <1.0.0"
3031
},
3132
"devDependencies": {
3233
"@fluentui-react-native/design-tokens-win32": "^0.36.0",
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { AliasColorTokens, Variants, VariantValue } from '@fluentui-react-native/theme-types';
2+
import { FontStyleTokens } from '@fluentui-react-native/tokens';
3+
4+
export function mapPipelineToTheme(pipelineOutput: any): AliasColorTokens {
5+
return {
6+
neutralForeground1: pipelineOutput.neutralForeground1.fillColorRest,
7+
neutralForeground1Hover: pipelineOutput.neutralForeground1.fillColorHover,
8+
neutralForeground1Pressed: pipelineOutput.neutralForeground1.fillColorPressed,
9+
neutralForeground1Selected: pipelineOutput.neutralForeground1.fillColorSelected,
10+
neutralForeground2: pipelineOutput.neutralForeground2.fillColorRest,
11+
neutralForeground2Hover: pipelineOutput.neutralForeground2.fillColorHover,
12+
neutralForeground2Pressed: pipelineOutput.neutralForeground2.fillColorPressed,
13+
neutralForeground2Selected: pipelineOutput.neutralForeground2.fillColorSelected,
14+
neutralForeground2BrandHover: pipelineOutput.neutralForeground2.fillColorBrandHover,
15+
neutralForeground2BrandPressed: pipelineOutput.neutralForeground2.fillColorBrandPressed,
16+
neutralForeground2BrandSelected: pipelineOutput.neutralForeground2.fillColorBrandSelected,
17+
neutralForeground3: pipelineOutput.neutralForeground3.fillColorRest,
18+
neutralForeground3Hover: pipelineOutput.neutralForeground3.fillColorHover,
19+
neutralForeground3Pressed: pipelineOutput.neutralForeground3.fillColorPressed,
20+
neutralForeground3Selected: pipelineOutput.neutralForeground3.fillColorSelected,
21+
neutralForeground3BrandHover: pipelineOutput.neutralForeground3.fillColorBrandHover,
22+
neutralForeground3BrandPressed: pipelineOutput.neutralForeground3.fillColorBrandPressed,
23+
neutralForeground3BrandSelected: pipelineOutput.neutralForeground3.fillColorBrandSelected,
24+
neutralForeground4: pipelineOutput.neutralForeground4.fillColorRest,
25+
neutralForegroundDisabled: pipelineOutput.neutralForegroundDisabled.fillColorRest,
26+
27+
brandForegroundLink: pipelineOutput.brandForegroundLink.fillColorRest,
28+
brandForegroundLinkHover: pipelineOutput.brandForegroundLink.fillColorHover,
29+
brandForegroundLinkPressed: pipelineOutput.brandForegroundLink.fillColorPressed,
30+
brandForegroundLinkSelected: pipelineOutput.brandForegroundLink.fillColorSelected,
31+
compoundBrandForeground1: pipelineOutput.compoundBrandForeground1.fillColorRest,
32+
compoundBrandForeground1Hover: pipelineOutput.compoundBrandForeground1.fillColorHover,
33+
compoundBrandForeground1Pressed: pipelineOutput.compoundBrandForeground1.fillColorPressed,
34+
brandForeground1: pipelineOutput.brandForeground1.fillColorRest,
35+
brandForeground1Disabled: pipelineOutput.brandForeground1.fillColorDisabled,
36+
brandForeground1Pressed: pipelineOutput.brandForeground1.fillColorPressed,
37+
brandForeground2: pipelineOutput.brandForeground2.fillColorRest,
38+
39+
neutralForegroundInverted: pipelineOutput.neutralForegroundInverted.fillColorRest,
40+
neutralForegroundOnBrand: pipelineOutput.neutralForegroundOnBrand.fillColorRest,
41+
neutralForegroundOnBrandHover: pipelineOutput.neutralForegroundOnBrand.fillColorHover,
42+
neutralForegroundOnBrandPressed: pipelineOutput.neutralForegroundOnBrand.fillColorPressed,
43+
neutralForegroundOnBrandSelected: pipelineOutput.neutralForegroundOnBrand.fillColorSelected,
44+
neutralForegroundInvertedLink: pipelineOutput.neutralForegroundInvertedLink.fillColorRest,
45+
neutralForegroundInvertedLinkHover: pipelineOutput.neutralForegroundInvertedLink.fillColorHover,
46+
neutralForegroundInvertedLinkPressed: pipelineOutput.neutralForegroundInvertedLink.fillColorPressed,
47+
neutralForegroundInvertedLinkSelected: pipelineOutput.neutralForegroundInvertedLink.fillColorSelected,
48+
49+
neutralBackground1: pipelineOutput.neutralBackground1.fillColorRest,
50+
neutralBackground1Hover: pipelineOutput.neutralBackground1.fillColorHover,
51+
neutralBackground1Pressed: pipelineOutput.neutralBackground1.fillColorPressed,
52+
neutralBackground1Selected: pipelineOutput.neutralBackground1.fillColorSelected,
53+
neutralBackground2: pipelineOutput.neutralBackground2.fillColorRest,
54+
neutralBackground2Hover: pipelineOutput.neutralBackground2.fillColorHover,
55+
neutralBackground2Pressed: pipelineOutput.neutralBackground2.fillColorPressed,
56+
neutralBackground2Selected: pipelineOutput.neutralBackground2.fillColorSelected,
57+
neutralBackground3: pipelineOutput.neutralBackground3.fillColorRest,
58+
neutralBackground3Hover: pipelineOutput.neutralBackground3.fillColorHover,
59+
neutralBackground3Pressed: pipelineOutput.neutralBackground3.fillColorPressed,
60+
neutralBackground3Selected: pipelineOutput.neutralBackground3.fillColorSelected,
61+
neutralBackground4: pipelineOutput.neutralBackground4.fillColorRest,
62+
neutralBackground4Hover: pipelineOutput.neutralBackground4.fillColorHover,
63+
neutralBackground4Pressed: pipelineOutput.neutralBackground4.fillColorPressed,
64+
neutralBackground4Selected: pipelineOutput.neutralBackground4.fillColorSelected,
65+
neutralBackground5: pipelineOutput.neutralBackground5.fillColorRest,
66+
neutralBackground5Hover: pipelineOutput.neutralBackground5.fillColorHover,
67+
neutralBackground5Pressed: pipelineOutput.neutralBackground5.fillColorPressed,
68+
neutralBackground5Selected: pipelineOutput.neutralBackground5.fillColorSelected,
69+
neutralBackground6: pipelineOutput.neutralBackground6.fillColorRest,
70+
neutralBackgroundInverted: pipelineOutput.neutralBackgroundInverted.fillColorRest,
71+
72+
subtleBackground: pipelineOutput.subtleBackground.fillColorRest,
73+
subtleBackgroundHover: pipelineOutput.subtleBackground.fillColorHover,
74+
subtleBackgroundPressed: pipelineOutput.subtleBackground.fillColorPressed,
75+
subtleBackgroundSelected: pipelineOutput.subtleBackground.fillColorSelected,
76+
77+
transparentBackground: pipelineOutput.transparentBackground.fillColorRest,
78+
transparentBackgroundHover: pipelineOutput.transparentBackground.fillColorHover,
79+
transparentBackgroundPressed: pipelineOutput.transparentBackground.fillColorPressed,
80+
transparentBackgroundSelected: pipelineOutput.transparentBackground.fillColorSelected,
81+
82+
neutralBackgroundDisabled: pipelineOutput.neutralBackgroundDisabled.fillColorRest,
83+
84+
neutralStencil1: pipelineOutput.neutralStencil1.fillColorRest,
85+
neutralStencil2: pipelineOutput.neutralStencil2.fillColorRest,
86+
87+
brandBackground: pipelineOutput.brandBackground.fillColorRest,
88+
brandBackgroundHover: pipelineOutput.brandBackground.fillColorHover,
89+
brandBackgroundPressed: pipelineOutput.brandBackground.fillColorPressed,
90+
brandBackgroundDisabled: pipelineOutput.brandBackground.fillColorDisabled,
91+
brandBackgroundSelected: pipelineOutput.brandBackground.fillColorSelected,
92+
compoundBrandBackground1: pipelineOutput.compoundBrandBackground1.fillColorRest,
93+
compoundBrandBackground1Hover: pipelineOutput.compoundBrandBackground1.fillColorHover,
94+
compoundBrandBackground1Pressed: pipelineOutput.compoundBrandBackground1.fillColorPressed,
95+
96+
brandBackgroundStatic: pipelineOutput.brandBackgroundStatic.fillColorRest,
97+
brandBackground2: pipelineOutput.brandBackground2.fillColorRest,
98+
99+
neutralStrokeAccessible: pipelineOutput.neutralStrokeAccessible.strokeColorRest,
100+
neutralStrokeAccessibleHover: pipelineOutput.neutralStrokeAccessible.strokeColorHover,
101+
neutralStrokeAccessiblePressed: pipelineOutput.neutralStrokeAccessible.strokeColorPressed,
102+
neutralStrokeAccessibleSelected: pipelineOutput.neutralStrokeAccessible.strokeColorSelected,
103+
neutralStroke1: pipelineOutput.neutralStroke1.strokeColorRest,
104+
neutralStroke1Hover: pipelineOutput.neutralStroke1.strokeColorHover,
105+
neutralStroke1Pressed: pipelineOutput.neutralStroke1.strokeColorPressed,
106+
neutralStroke1Selected: pipelineOutput.neutralStroke1.strokeColorSelected,
107+
neutralStroke2: pipelineOutput.neutralStroke2.strokeColorRest,
108+
neutralStroke3: pipelineOutput.neutralStroke3.strokeColorRest,
109+
brandStroke1: pipelineOutput.brandStroke1.strokeColorRest,
110+
brandStroke2: pipelineOutput.brandStroke2.strokeColorRest,
111+
compoundBrandStroke1: pipelineOutput.compoundBrandStroke1.strokeColorRest,
112+
compoundBrandStroke1Hover: pipelineOutput.compoundBrandStroke1.strokeColorHover,
113+
compoundBrandStroke1Pressed: pipelineOutput.compoundBrandStroke1.strokeColorPressed,
114+
neutralStrokeDisabled: pipelineOutput.neutralStrokeDisabled.strokeColorRest,
115+
116+
transparentStroke: pipelineOutput.transparentStroke.strokeColorRest,
117+
transparentStrokeInteractive: pipelineOutput.transparentStroke.strokeColorHover,
118+
transparentStrokeDisabled: pipelineOutput.transparentStroke.strokeColorDisabled,
119+
120+
strokeFocus1: pipelineOutput.strokeFocus1.strokeColorRest,
121+
strokeFocus2: pipelineOutput.strokeFocus2.strokeColorRest,
122+
123+
redBackground1: pipelineOutput.redBackground1.fillColorRest,
124+
redBackground2: pipelineOutput.redBackground2.fillColorRest,
125+
redBackground3: pipelineOutput.redBackground3.fillColorRest,
126+
redForeground1: pipelineOutput.redForeground1.fillColorRest,
127+
redForeground2: pipelineOutput.redBackground2.fillColorRest,
128+
redForeground3: pipelineOutput.redBackground3.fillColorRest,
129+
redBorderActive: pipelineOutput.redBorderActive.strokeColorRest,
130+
redBorder1: pipelineOutput.redBorder1.strokeColorRest,
131+
redBorder2: pipelineOutput.redBorder2.strokeColorRest,
132+
};
133+
}
134+
135+
export function mapFontPipelineToTheme(pipelineOutput: any): Partial<Variants> {
136+
return {
137+
caption2: convertAliasFont(pipelineOutput.caption2 as FontStyleTokens, 'caption1'),
138+
caption1: convertAliasFont(pipelineOutput.caption1 as FontStyleTokens, 'footnote'),
139+
caption1Strong: convertAliasFont(pipelineOutput.caption1Strong as FontStyleTokens, 'footnote'),
140+
body2: convertAliasFont(pipelineOutput.body2 as FontStyleTokens, 'subheadline'),
141+
body2Strong: convertAliasFont(pipelineOutput.body2Strong as FontStyleTokens, 'subheadline'),
142+
body1: convertAliasFont(pipelineOutput.body1 as FontStyleTokens, 'body'),
143+
body1Strong: convertAliasFont(pipelineOutput.body1Strong as FontStyleTokens, 'body'),
144+
title3: convertAliasFont(pipelineOutput.title3 as FontStyleTokens, 'title3'),
145+
title2: convertAliasFont(pipelineOutput.title2 as FontStyleTokens, 'title2'),
146+
title1: convertAliasFont(pipelineOutput.title1 as FontStyleTokens, 'title1'),
147+
largeTitle: convertAliasFont(pipelineOutput.largeTitle as FontStyleTokens, 'largeTitle'),
148+
display: convertAliasFont(pipelineOutput.display as FontStyleTokens, 'largeTitle'),
149+
};
150+
}
151+
152+
// TODO: Dynamic Type ramps should eventually be pulled from the pipeline
153+
function convertAliasFont(aliasFont: FontStyleTokens, dynamicTypeRamp: string): VariantValue {
154+
return {
155+
face: aliasFont.fontFamily,
156+
size: aliasFont.fontSize,
157+
weight: aliasFont.fontWeight,
158+
lineHeight: aliasFont.fontLineHeight,
159+
letterSpacing: aliasFont.fontLetterSpacing,
160+
dynamicTypeRamp,
161+
};
162+
}

0 commit comments

Comments
 (0)