Skip to content

Commit

Permalink
chore: Remove style-dictionary dependency from React Native package (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
esauerbo authored Oct 5, 2024
1 parent 2f9911d commit 0d86485
Show file tree
Hide file tree
Showing 16 changed files with 733 additions and 100 deletions.
6 changes: 6 additions & 0 deletions .changeset/sharp-kiwis-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@aws-amplify/ui-react-native": patch
"@aws-amplify/ui": patch
---

chore: Copy `style-dictionary` functions to ui package and export from there. Remove `style-dictionary` dependency from React Native package.
3 changes: 1 addition & 2 deletions packages/react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@
"dependencies": {
"@aws-amplify/ui": "6.6.2",
"@aws-amplify/ui-react-core": "3.0.26",
"@aws-amplify/ui-react-core-notifications": "2.0.26",
"style-dictionary": "3.9.1"
"@aws-amplify/ui-react-core-notifications": "2.0.26"
},
"peerDependencies": {
"aws-amplify": "^6.6.0",
Expand Down
31 changes: 13 additions & 18 deletions packages/react-native/src/theme/createTheme.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import deepExtend from 'style-dictionary/lib/utils/deepExtend';
import resolveObject from 'style-dictionary/lib/utils/resolveObject';
import usesReference from 'style-dictionary/lib/utils/references/usesReference';
import { deepExtend, resolveObject, usesReference } from '@aws-amplify/ui';
import { isFunction, setupTokens } from '@aws-amplify/ui';
import {
Theme,
Expand All @@ -15,13 +13,15 @@ import { defaultTheme } from './defaultTheme';
// calling the component theme function with the already resolved base tokens
// OR
// resolving the component theme object
interface TokensAndComponents {
components: Components;
tokens: StrictTokens;
}

const setupComponents = ({
components,
tokens,
}: {
components: Components;
tokens: StrictTokens;
}) => {
}: TokensAndComponents): Components => {
const output = components
? Object.entries(components).reduce(
(acc, [key, value]) => ({
Expand All @@ -32,7 +32,7 @@ const setupComponents = ({
)
: {};

return resolveObject({
return resolveObject<TokensAndComponents>({
...tokens,
components: output,
}).components;
Expand Down Expand Up @@ -103,12 +103,7 @@ export const createTheme = (
): StrictTheme => {
// merge custom `theme` param and `StrictTheme` to get the merged theme.
// `deepExtend` is a Style Dictionary method that performs a deep merge on n objects.
const mergedTheme = deepExtend([
{},
defaultTheme,
theme,
// cast to `StrictTheme` as `deepExtend` returns a generic object
]) as StrictTheme;
const mergedTheme = deepExtend<StrictTheme>([{}, defaultTheme, theme]);

let { tokens: mergedTokens } = mergedTheme;
const { spaceModifier = 1 } = mergedTheme;
Expand All @@ -119,11 +114,11 @@ export const createTheme = (
if (theme?.overrides?.length) {
theme.overrides.forEach((override) => {
if (override?.colorMode === colorMode) {
mergedTokens = deepExtend([
mergedTokens = deepExtend<StrictTheme['tokens']>([
{},
mergedTokens,
override.tokens,
]) as StrictTheme['tokens'];
]);
}
// more overrides in the future could happen here
});
Expand All @@ -132,13 +127,13 @@ export const createTheme = (
// Setup the tokens:
// - each token will have a raw value
// - references to tokens (strings wrapped in curly braces) are replaced by raw values
const tokens = resolveObject(
const tokens = resolveObject<StrictTheme['tokens']>(
setupTokens({
tokens: mergedTokens,
setupToken: ({ token, path }) => {
return setupToken({ token, path, spaceModifier });
},
}) as StrictTheme['tokens']
})
);

let components;
Expand Down
2 changes: 0 additions & 2 deletions packages/ui/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ const config: Config = {
'!<rootDir>/src/index.ts',
// ignore internal `debugUtils` from coverage thresholds
'!<rootDir>/**/debugUtils.ts',
// ignore coverage for style-dictionary type declaration file
'!<rootDir>/src/theme/types/style-dictionary.d.ts',
],
coverageThreshold: {
global: {
Expand Down
269 changes: 269 additions & 0 deletions packages/ui/src/theme/createTheme/__tests__/resolveObject.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
import { resolveObject } from '../resolveObject';

describe('resolveObject', () => {
it('should not mutate the original object', () => {
const original = {
test: '1',
a: {
b: {
c: 1,
d: '{e.f.g}',
},
},
e: {
f: {
g: 2,
h: '{a.b.c}',
},
},
i: '{e.f.g}',
};
const test = resolveObject(original);
expect(original).toHaveProperty('a.b.d', '{e.f.g}');
expect(test).toHaveProperty('a.b.d', 2);
});

it('should do simple references', () => {
const test = resolveObject({
foo: 'bar',
bar: '{foo}',
});
expect(test).toHaveProperty('bar', 'bar');
});

it('should do simple interpolation for both strings and numbers', () => {
const test = resolveObject({
a: 'test1 value',
b: 123,
c: '{a} text after',
d: 'text before {a}',
e: 'text before {a} text after',
f: '{b} text after',
g: 'text before {b}',
h: 'text before {b} text after',
});
expect(test).toHaveProperty('c', 'test1 value text after');
expect(test).toHaveProperty('d', 'text before test1 value');
expect(test).toHaveProperty('e', 'text before test1 value text after');
expect(test).toHaveProperty('f', '123 text after');
expect(test).toHaveProperty('g', 'text before 123');
expect(test).toHaveProperty('h', 'text before 123 text after');
});

it('should do nested references', () => {
const obj = {
test: '1',
a: {
b: {
c: 1,
d: '{e.f.g}',
},
},
e: {
f: {
g: 2,
h: '{a.b.c}',
},
},
i: '{e.f.g}',
};
const test = resolveObject(obj);
expect(test).toHaveProperty('i', 2);
expect(test).toHaveProperty('a.b.d', 2);
expect(test).toHaveProperty('e.f.h', 1);
});

it('should handle nested pointers', () => {
const test = resolveObject({
a: 1,
b: '{a}',
c: '{b}',
d: '{e}',
e: '{c}',
});
expect(test).toHaveProperty('b', 1);
expect(test).toHaveProperty('c', 1);
});

it('should handle deep nested pointers', () => {
const test = resolveObject({
a: '{b}',
b: '{c}',
c: '{d}',
d: '{e}',
e: '{f}',
f: '{g}',
g: 1,
});
expect(test).toHaveProperty('a', 1);
expect(test).toHaveProperty('b', 1);
expect(test).toHaveProperty('c', 1);
expect(test).toHaveProperty('d', 1);
expect(test).toHaveProperty('e', 1);
expect(test).toHaveProperty('f', 1);
expect(test).toHaveProperty('g', 1);
});

it('should handle deep nested pointers with string interpolation', () => {
const test = resolveObject({
a: '{b} bar',
b: '{c} baz',
c: '{d} bla',
d: '{e} boo',
e: '{f} bae',
f: '{g} bee',
g: 'foo bon',
});
expect(test).toHaveProperty('a', 'foo bon bee bae boo bla baz bar');
expect(test).toHaveProperty('b', 'foo bon bee bae boo bla baz');
expect(test).toHaveProperty('c', 'foo bon bee bae boo bla');
expect(test).toHaveProperty('d', 'foo bon bee bae boo');
expect(test).toHaveProperty('e', 'foo bon bee bae');
expect(test).toHaveProperty('f', 'foo bon bee');
expect(test).toHaveProperty('g', 'foo bon');
});

it('should handle deep nested pointers and nested references', () => {
const test = resolveObject({
a: {
a: {
a: '{b.b.b}',
},
},
b: {
b: {
b: '{c.c.c}',
},
},
c: {
c: {
c: '{d.d.d}',
},
},
d: {
d: {
d: '{e.e.e}',
},
},
e: {
e: {
e: '{f.f.f}',
},
},
f: {
f: {
f: '{g.g.g}',
},
},
g: {
g: {
g: 1,
},
},
});
expect(test).toHaveProperty('a.a.a', 1);
expect(test).toHaveProperty('b.b.b', 1);
expect(test).toHaveProperty('c.c.c', 1);
expect(test).toHaveProperty('d.d.d', 1);
expect(test).toHaveProperty('e.e.e', 1);
expect(test).toHaveProperty('f.f.f', 1);
expect(test).toHaveProperty('g.g.g', 1);
});

it('should keep the type of the referenced property', () => {
const referenceType = {
a: 1,
b: {
c: 2,
},
d: '{a}',
e: '{b}',
f: [1, 2, 3],
g: '{f}',
};
const test = resolveObject<typeof referenceType>(referenceType);
expect(test).toHaveProperty('d', 1);
expect(typeof test.d).toBe('number');
expect(typeof test.e).toBe('object');
expect(Array.isArray(test.f)).toBeTruthy();
expect(test).toHaveProperty('e.c', 2);
});

it('should handle and evaluate items in an array', () => {
const withArray = {
a: 1,
b: {
c: 2,
},
d: ['{b.c}', '{a}'],
e: [
{
a: '{a}',
},
{
a: '{b.c}',
},
],
};
const test = resolveObject<typeof withArray>(withArray);
expect(test.d[0]).toBe(2);
expect(test.d[1]).toBe(1);
expect(test.e[0].a).toBe(1);
expect(test.e[1].a).toBe(2);
});

it('should correctly replace multiple references without reference errors', function () {
const obj = resolveObject({
prop1: { value: 'test1 value' },
prop2: { value: 'test2 value' },
prop3: { value: '{prop1.value}' },
prop4: { value: '{prop3.value}' },
prop5: { value: 5 },
prop6: { value: 6 },
prop7: { value: '{prop5.value}' },
prop8: { value: '{prop7.value}' },
prop12: { value: '{prop1.value}, {prop2.value} and some extra stuff' },
prop124: { value: '{prop1.value}, {prop2.value} and {prop4.value}' },
prop15: { value: '{prop1.value}, {prop5.value} and some extra stuff' },
prop156: { value: '{prop1.value}, {prop5.value} and {prop6.value}' },
prop1568: {
value: '{prop1.value}, {prop5.value}, {prop6.value} and {prop8.value}',
},
});
expect(JSON.stringify(obj)).toBe(
JSON.stringify({
prop1: { value: 'test1 value' },
prop2: { value: 'test2 value' },
prop3: { value: 'test1 value' },
prop4: { value: 'test1 value' },
prop5: { value: 5 },
prop6: { value: 6 },
prop7: { value: 5 },
prop8: { value: 5 },
prop12: { value: 'test1 value, test2 value and some extra stuff' },
prop124: { value: 'test1 value, test2 value and test1 value' },
prop15: { value: 'test1 value, 5 and some extra stuff' },
prop156: { value: 'test1 value, 5 and 6' },
prop1568: { value: 'test1 value, 5, 6 and 5' },
})
);
});

it('should handle spaces', () => {
const withSpaces = {
foo: { value: 'bar' },
bar: { value: '{ foo.value }' },
};
const test = resolveObject<typeof withSpaces>(withSpaces);
expect(test).toHaveProperty('foo.value', test.bar.value);
});

it('should handle 0', () => {
const withZero = {
test: { value: '{zero.value}' },
zero: { value: 0 },
};
const test = resolveObject<typeof withZero>(withZero);
expect(test.test.value).toBe(0);
});
});
Loading

0 comments on commit 0d86485

Please sign in to comment.