Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## Next

- Add support for defining `fontSizes` [#310](https://github.com/Shopify/restyle/pull/310) by [kaltoft](https://github.com/kaltoft)

## 2.4.3 - 2023-04-18

- Fixed: clean up the project configuration for RN0.71, aligning some packages to the right version [#271](https://github.com/Shopify/restyle/pull/271) by [kelset](https://github.com/kelset) & [tido64](https://github.com/tido64)
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<div align="center">

**_This fork introduces support for defining and referencing font sizes_**

</div>

![Restyle Image](./Restyle.png)

<div align="center">
Expand Down
26 changes: 26 additions & 0 deletions documentation/docs/fundamentals/font-sizes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
id: fontSizes
title: Font Sizes
---

When working with font sizes in a design system, a common pattern is to define a scale that includes a range of sizes, from smaller to larger text. See for example the [Type Scale Tool](https://typescale.com/).

This scale should preferably not be directly included as values in the theme. Instead, the naming of font sizes in the theme object should be used to assign semantic meaning to the scale, as shown in this example:

```ts
const theme = createTheme({
fontSizes: {
title: 34,
h1: 28,
h2: 22,
h3: 20,
body: 16,
},
});
```

Defining semantic font sizes brings several advantages:

- It’s clear which font sizes are used and in what contexts throughout the app.
- If changes are made to the font scale (e.g., adjusting the base size or ratios), you only need to update the semantic size mappings instead of manually changing every reference to specific sizes like `body` across the app.
- Themes can easily be swapped at runtime, enabling dynamic adjustments like switching to a larger font scale for accessibility.
1 change: 1 addition & 0 deletions src/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {BaseTheme} from 'types';
export const ThemeContext = React.createContext({
colors: {},
spacing: {},
fontSizes: {},
});

export const ThemeProvider = ({
Expand Down
2 changes: 2 additions & 0 deletions src/createText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ColorProps,
OpacityProps,
SpacingProps,
FontSizeProps,
TextShadowProps,
TypographyProps,
VisibleProps,
Expand All @@ -27,6 +28,7 @@ type BaseTextProps<Theme extends BaseTheme> = ColorProps<Theme> &
OpacityProps<Theme> &
VisibleProps<Theme> &
TypographyProps<Theme> &
FontSizeProps<Theme> &
SpacingProps<Theme> &
LayoutProps<Theme> &
TextShadowProps<Theme> &
Expand Down
22 changes: 16 additions & 6 deletions src/restyleFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ const spacingPropertiesShorthand = {

const typographyProperties = {
fontFamily: true,
fontSize: true,
fontStyle: true,
fontWeight: true,
includeFontPadding: true,
Expand Down Expand Up @@ -199,11 +198,17 @@ export const spacingShorthand = getKeys(spacingPropertiesShorthand).map(
},
);

export const typography = getKeys(typographyProperties).map(property => {
return createRestyleFunction({
property,
});
});
export const typography = [
...getKeys(typographyProperties).map(property => {
return createRestyleFunction({
property,
});
}),
createRestyleFunction({
property: 'fontSize',
themeKey: 'fontSizes',
}),
];

export const layout = getKeys(layoutProperties).map(property => {
return createRestyleFunction({
Expand Down Expand Up @@ -322,6 +327,10 @@ export type SpacingShorthandProps<Theme extends BaseTheme> = {
>;
};

export interface FontSizeProps<Theme extends BaseTheme> {
fontSize?: ResponsiveValue<keyof Theme['fontSizes'], Theme['breakpoints']>;
}

export type TypographyProps<Theme extends BaseTheme> = {
[Key in keyof typeof typographyProperties]?: ResponsiveValue<
TextStyle[Key],
Expand Down Expand Up @@ -392,6 +401,7 @@ export type AllProps<Theme extends BaseTheme> = BackgroundColorProps<Theme> &
OpacityProps<Theme> &
SpacingProps<Theme> &
SpacingShorthandProps<Theme> &
FontSizeProps<Theme> &
TypographyProps<Theme> &
LayoutProps<Theme> &
PositionProps<Theme> &
Expand Down
6 changes: 6 additions & 0 deletions src/test/TestButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import composeRestyleFunctions from '../composeRestyleFunctions';
const theme = {
colors: {},
spacing: {},
fontSizes: {
xs: 14,
s: 16,
m: 20,
l: 24,
},
buttonVariants: {
defaults: {},
},
Expand Down
6 changes: 6 additions & 0 deletions src/test/TestContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export const theme = {
none: 0,
m: 8,
},
fontSizes: {
xs: 14,
s: 16,
m: 20,
l: 24,
},
breakpoints: {
phone: 320,
tablet: 768,
Expand Down
16 changes: 14 additions & 2 deletions src/test/composeRestyleFunctions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ const theme = {
colors: {
black: '#111111',
},
fontSizes: {
xs: 14,
s: 16,
m: 20,
l: 24,
},
spacing: {
m: 16,
},
Expand All @@ -20,20 +26,26 @@ describe('composeRestyleFunctions', () => {
const restyleFunctions = [
createRestyleFunction({property: 'color', themeKey: 'colors'}),
createRestyleFunction({property: 'margin', themeKey: 'spacing'}),
createRestyleFunction({property: 'fontSize', themeKey: 'fontSizes'}),
];

it('composes multiple restyleFunctions into one', () => {
const {buildStyle} = composeRestyleFunctions(restyleFunctions);
expect(
buildStyle({color: 'black', margin: 'm'}, {theme, dimensions}),
buildStyle(
{color: 'black', margin: 'm', fontSize: 'm'},
{theme, dimensions},
),
).toStrictEqual({
color: '#111111',
margin: 16,
fontSize: 20,
});
});

it('combines all restyle function input properties into a list', () => {
const {properties} = composeRestyleFunctions(restyleFunctions);
expect(properties).toStrictEqual(['color', 'margin']);

expect(properties).toStrictEqual(['color', 'margin', 'fontSize']);
});
});
6 changes: 6 additions & 0 deletions src/test/createRestyleComponent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ const theme = {
spacing: {
s: 8,
},
fontSizes: {
xs: 14,
s: 16,
m: 20,
l: 24,
},
breakpoints: {
phone: 0,
tablet: 376,
Expand Down
1 change: 1 addition & 0 deletions src/test/createRestyleFunction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {RNStyle} from '../types';
const theme = {
colors: {},
spacing: {},
fontSizes: {},
opacities: {
invisible: 0,
barelyVisible: 0.1,
Expand Down
31 changes: 28 additions & 3 deletions src/test/createText.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ const palette = {
grey: '#808080',
};

const fontSizes = {
xs: 12,
s: 14,
m: 18,
l: 20,
xl: 24,
xxl: 48,
};

const theme = createTheme({
colors: {
black: palette.black,
Expand All @@ -20,17 +29,18 @@ const theme = createTheme({
s: 4,
m: 8,
},
fontSizes,
textVariants: {
defaults: {
color: 'black',
},
title: {
fontSize: 48,
fontSize: 'xxl',
fontWeight: 'bold',
color: 'black',
},
subtitle: {
fontSize: 16,
fontSize: 'm',
color: 'grey',
},
},
Expand Down Expand Up @@ -65,6 +75,21 @@ describe('createText', () => {
]);
});

it('uses a font size from the theme', () => {
const {root} = render(
<ThemeProvider theme={theme}>
<Text fontSize="m">Some text</Text>
</ThemeProvider>,
);

expect(root.findByType(RNText).props.style).toStrictEqual([
{
color: palette.black,
fontSize: fontSizes.m,
},
]);
});

it('uses a spacing value from the theme', () => {
const {root} = render(
<ThemeProvider theme={theme}>
Expand Down Expand Up @@ -102,7 +127,7 @@ describe('createText', () => {
<Text
color="grey"
fontFamily="Roboto"
fontSize={18}
fontSize="m"
fontStyle="italic"
fontWeight="800"
includeFontPadding
Expand Down
37 changes: 22 additions & 15 deletions src/test/createVariant.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ const theme: BaseTheme = {
m: 16,
l: 24,
},
fontSizes: {
xs: 12,
s: 14,
m: 16,
l: 20,
xl: 24,
},
breakpoints: {
phone: 0,
tablet: 376,
Expand All @@ -21,19 +28,19 @@ const theme: BaseTheme = {
},
textVariants: {
body: {
fontSize: 14,
fontSize: 's',
lineHeight: 18,
},
subheader: {
fontSize: 16,
fontSize: 'm',
color: 'black',
},
header: {
margin: 's',
fontSize: {
phone: 22,
tablet: 28,
specific: 34,
phone: 's',
tablet: 'm',
specific: 'l',
},
fontWeight: 'bold',
color: {
Expand All @@ -45,8 +52,8 @@ const theme: BaseTheme = {
boxVariants: {
defaults: {
fontSize: {
phone: 12,
tablet: 24,
phone: 'xs',
tablet: 'xl',
},
backgroundColor: {
phone: 'black',
Expand Down Expand Up @@ -77,12 +84,12 @@ describe('createVariant', () => {
const variant = createVariant({
themeKey: 'textVariants',
defaults: {
fontSize: 10,
fontSize: 'xs',
opacity: 0.5,
},
});
expect(variant.func({}, {theme, dimensions})).toStrictEqual({
fontSize: 10,
fontSize: 12,
opacity: 0.5,
});
});
Expand All @@ -101,7 +108,7 @@ describe('createVariant', () => {
const variant = createVariant({
themeKey: 'boxVariants',
defaults: {
fontSize: 10,
fontSize: 'xl',
opacity: 0.5,
},
});
Expand All @@ -117,7 +124,7 @@ describe('createVariant', () => {
const variant = createVariant({
themeKey: 'boxVariants',
defaults: {
fontSize: 10,
fontSize: 'xl',
opacity: 0.5,
},
});
Expand Down Expand Up @@ -150,7 +157,7 @@ describe('createVariant', () => {
const variant = createVariant({
themeKey: 'textVariants',
defaults: {
fontSize: 10,
fontSize: 'xl',
opacity: 0.5,
},
});
Expand Down Expand Up @@ -193,7 +200,7 @@ describe('createVariant', () => {
{theme, dimensions: {width: 768, height: 300}},
),
).toStrictEqual({
fontSize: 28,
fontSize: 16,
margin: 8,
fontWeight: 'bold',
color: '#EEEEEE',
Expand All @@ -208,7 +215,7 @@ describe('createVariant', () => {
{theme, dimensions: {width: 768, height: 1024}},
),
).toStrictEqual({
fontSize: 34,
fontSize: 20,
margin: 8,
fontWeight: 'bold',
color: '#EEEEEE',
Expand All @@ -223,7 +230,7 @@ describe('createVariant', () => {
{theme, dimensions: {width: 375, height: 1024}},
),
).toStrictEqual({
fontSize: 22,
fontSize: 14,
margin: 8,
fontWeight: 'bold',
color: '#111111',
Expand Down
Loading
Loading