Skip to content

Commit

Permalink
fix(react-native): border widths in the theme don't throw runtime err…
Browse files Browse the repository at this point in the history
…ors (#4227)
  • Loading branch information
dbanksdesign committed Jul 12, 2023
1 parent ea008e3 commit d3ee054
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 19 deletions.
32 changes: 32 additions & 0 deletions .changeset/cold-grapes-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
"@aws-amplify/ui-react-native": patch
"@aws-amplify/ui-react": patch
"@aws-amplify/ui": patch
---

fix(react-native): border widths, spacing, font sizes, opacities in the theme don't throw runtime errors.

These are all valid in a theme now:

```typescript
const theme: Theme = {
tokens: {
borderWidths: {
small: '4',
medium: '1rem',
large: 6,
},
opacities: {
'10': '0.2',
},
space: {
small: 4,
medium: '6',
large: '{space.small.value}',
},
fontSizes: {
small: '1rem',
},
},
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,17 @@ const MyHeader = ({
style?: StyleProp<ViewStyle>;
}) => {
const {
tokens: { colors, fontSizes },
tokens: { colors, fontSizes, borderWidths },
} = useTheme();
console.log({ borderWidths });
return (
<View style={style}>
<Text
style={{ fontSize: fontSizes.xxl, color: colors.brand.primary[80] }}
style={{
fontSize: fontSizes.xxl,
color: colors.brand.secondary[80],
borderWidth: borderWidths.large,
}}
>
{children}
</Text>
Expand All @@ -49,6 +54,11 @@ function SignOutButton() {
}

const theme: Theme = {
tokens: {
borderWidths: {
large: '1rem',
},
},
overrides: [defaultDarkModeOverride],
};

Expand Down
48 changes: 48 additions & 0 deletions packages/react-native/src/theme/__tests__/createTheme.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,54 @@ describe('createTheme', () => {
});
});

describe('number conversions', () => {
it('should convert strings to numbers where applicable', () => {
const { tokens } = createTheme({
tokens: {
borderWidths: {
small: '4',
medium: '1rem',
large: 6,
},
opacities: {
'10': '0.2',
},
space: {
small: 4,
medium: '6',
large: '{space.small.value}',
},
fontSizes: {
small: '1rem',
},
},
});
expect(tokens.borderWidths.small).toBe(4);
expect(tokens.borderWidths.medium).toBe(16);
expect(tokens.borderWidths.large).toBe(6);
expect(tokens.opacities['10']).toBe(0.2);
expect(tokens.space.small).toBe(4);
expect(tokens.space.medium).toBe(6);
expect(tokens.space.large).toBe(4);
expect(tokens.fontSizes.small).toBe(16);
});

it('should use the spaceModifier for space tokens with rem', () => {
const { tokens } = createTheme({
spaceModifier: 1.25,
tokens: {
space: {
small: 4,
medium: '1rem',
},
},
});

expect(tokens.space.small).toEqual(4);
expect(tokens.space.medium).toEqual(20);
});
});

describe('with mixture of value and no value', () => {
const { tokens } = createTheme({
tokens: {
Expand Down
41 changes: 26 additions & 15 deletions packages/react-native/src/theme/createTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ const setupComponents = ({ components, tokens }: StrictTheme) => {
}).components;
};

const shouldParseFloatValue = (pathKey: string) =>
[
'space',
'borderWidths',
'opacities',
'fontSizes',
'lineHeights',
'radii',
].includes(pathKey);

const setupToken = ({
token,
path = [],
Expand All @@ -39,27 +49,28 @@ const setupToken = ({
}): string | number => {
const { value } = token;
if (typeof value === 'string') {
// Perform transforms
if (path[0] === 'space') {
if (value.includes('rem')) {
return Math.floor(parseFloat(value) * 16 * spaceModifier);
}
}
if (value.includes('rem')) {
return Math.floor(parseFloat(value) * 16);
}
if (value.includes('px')) {
return parseInt(value, 10);
}
if (path[0] === 'opacities') {
return parseFloat(value);
}
// Remove .value from references if there is a reference
// this needs to come first so we don't get NaNs for references
if (usesReference(value)) {
return value.replace('.value', '');
}

if (shouldParseFloatValue(path[0])) {
if (value.includes('rem')) {
if (path[0] === 'space') {
return Math.floor(parseFloat(value) * 16 * spaceModifier);
}
return Math.floor(parseFloat(value) * 16);
}
if (value.includes('px')) {
return parseInt(value, 10);
}
return parseFloat(value);
}

return value;
}

// Font Weights in RN are strings
if (path[0] === 'fontWeights') {
return `${value}`;
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/theme/tokens/types/designToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export type BorderWidthValue<
> = Output extends 'required'
? Platform extends 'react-native'
? number
: SpaceValue
: SpaceValue;
: SpaceValue<Platform>
: SpaceValue<Platform>;
export type BorderValue = string;
export type BoxSizingValue = string;
export type BoxShadowValue = ShadowValue;
Expand Down

0 comments on commit d3ee054

Please sign in to comment.