Skip to content

Commit 5e21a2d

Browse files
author
Hector Arce De Las Heras
committed
Introduce useStylesV2 hook and update components
This commit introduces a new hook, `useStylesV2`, which provides more flexibility and control over style application by allowing optional styles and custom tokens. Tests have been added to ensure the functionality of the new hook. The existing components, `CardSelectorControlled` and `NavigationRow`, have been updated to use the new `useStylesV2` hook. The `lineSeparatorLineStyles` property in the `INavigationRowStandAlone` interface has been made optional to accommodate the optional styles feature of `useStylesV2`. These changes enhance the flexibility and control developers have over style application in components, improving the customizability and adaptability of the application.
1 parent 9bfb502 commit 5e21a2d

File tree

5 files changed

+188
-1
lines changed

5 files changed

+188
-1
lines changed

src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export { useStyles } from './useStyles/useStyles';
2+
export { useStylesV2 } from './useStyles/useStylesV2';
23
export * from './useMediaDevice/useMediaDevice';
34
export * from './useMediaDevice/useActiveBreakpoints';
45
export * from './useId/useId';
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// mock hooks
2+
import * as styledComponents from 'styled-components';
3+
4+
import { useStylesV2 } from '../useStylesV2';
5+
6+
describe('useStylesV2', () => {
7+
it('When no styleName in theme, we expect an exception', () => {
8+
const useThemeHock = () => ({
9+
MEDIA_QUERIES: {
10+
onlyDesktop: 'onlyDesktop',
11+
tabletAndDesktop: 'tabletAndDesktop',
12+
onlyTablet: 'onlyTablet',
13+
mobileAndTablet: 'mobileAndTablet',
14+
onlyMobile: 'onlyMobile',
15+
matchMedia: {
16+
onlyDesktop: 'onlyDesktop',
17+
onlyMobile: 'onlyMobile',
18+
onlyTablet: 'onlyTablet',
19+
},
20+
},
21+
SPACINGS: {},
22+
});
23+
jest.spyOn(styledComponents, 'useTheme').mockImplementation(useThemeHock);
24+
expect(() => {
25+
useStylesV2({ styleName: 'styleName' });
26+
}).toThrow('styles styleName does not exist');
27+
});
28+
29+
it('When no typeName in styles, we expect an exception', () => {
30+
const useThemeHock = () => ({
31+
MEDIA_QUERIES: {
32+
onlyDesktop: 'onlyDesktop',
33+
tabletAndDesktop: 'tabletAndDesktop',
34+
onlyTablet: 'onlyTablet',
35+
mobileAndTablet: 'mobileAndTablet',
36+
onlyMobile: 'onlyMobile',
37+
matchMedia: {
38+
onlyDesktop: 'onlyDesktop',
39+
onlyMobile: 'onlyMobile',
40+
onlyTablet: 'onlyTablet',
41+
},
42+
},
43+
SPACINGS: {},
44+
styleName: {},
45+
});
46+
jest.spyOn(styledComponents, 'useTheme').mockImplementation(useThemeHock);
47+
expect(() => {
48+
useStylesV2({ styleName: 'styleName', variantName: 'typeName' });
49+
}).toThrow('type typeName does not exist');
50+
});
51+
52+
it('When styleName in theme and no typeName, should return styles', () => {
53+
const useThemeHock = () => ({
54+
MEDIA_QUERIES: {
55+
onlyDesktop: 'onlyDesktop',
56+
tabletAndDesktop: 'tabletAndDesktop',
57+
onlyTablet: 'onlyTablet',
58+
mobileAndTablet: 'mobileAndTablet',
59+
onlyMobile: 'onlyMobile',
60+
matchMedia: {
61+
onlyDesktop: 'onlyDesktop',
62+
onlyMobile: 'onlyMobile',
63+
onlyTablet: 'onlyTablet',
64+
},
65+
},
66+
SPACINGS: {},
67+
styleName: 'styleName',
68+
});
69+
jest.spyOn(styledComponents, 'useTheme').mockImplementation(useThemeHock);
70+
const styles = useStylesV2({ styleName: 'styleName' });
71+
expect(styles).toBe('styleName');
72+
});
73+
it('When styleName in theme and typeName, should return typeName styles', () => {
74+
const useThemeHock = () => ({
75+
MEDIA_QUERIES: {
76+
onlyDesktop: 'onlyDesktop',
77+
tabletAndDesktop: 'tabletAndDesktop',
78+
onlyTablet: 'onlyTablet',
79+
mobileAndTablet: 'mobileAndTablet',
80+
onlyMobile: 'onlyMobile',
81+
matchMedia: {
82+
onlyDesktop: 'onlyDesktop',
83+
onlyMobile: 'onlyMobile',
84+
onlyTablet: 'onlyTablet',
85+
},
86+
},
87+
SPACINGS: {},
88+
styleName: {
89+
typeName: 'typeName',
90+
},
91+
});
92+
jest.spyOn(styledComponents, 'useTheme').mockImplementation(useThemeHock);
93+
const styles = useStylesV2({ styleName: 'styleName', variantName: 'typeName' });
94+
expect(styles).toBe('typeName');
95+
});
96+
it('return undefined when isOptional is true and variantName does not exist', () => {
97+
const useThemeHock = () => ({
98+
MEDIA_QUERIES: {
99+
onlyDesktop: 'onlyDesktop',
100+
tabletAndDesktop: 'tabletAndDesktop',
101+
onlyTablet: 'onlyTablet',
102+
mobileAndTablet: 'mobileAndTablet',
103+
onlyMobile: 'onlyMobile',
104+
matchMedia: {
105+
onlyDesktop: 'onlyDesktop',
106+
onlyMobile: 'onlyMobile',
107+
onlyTablet: 'onlyTablet',
108+
},
109+
},
110+
SPACINGS: {},
111+
styleName: {},
112+
});
113+
jest.spyOn(styledComponents, 'useTheme').mockImplementation(useThemeHock);
114+
const styles = useStylesV2({
115+
styleName: 'styleName',
116+
variantName: 'fakeTypeName',
117+
isOptional: true,
118+
});
119+
expect(styles).toBe(undefined);
120+
});
121+
it('return undefined when isOptional is true and styleName does not exist', () => {
122+
const useThemeHock = () => ({
123+
MEDIA_QUERIES: {
124+
onlyDesktop: 'onlyDesktop',
125+
tabletAndDesktop: 'tabletAndDesktop',
126+
onlyTablet: 'onlyTablet',
127+
mobileAndTablet: 'mobileAndTablet',
128+
onlyMobile: 'onlyMobile',
129+
matchMedia: {
130+
onlyDesktop: 'onlyDesktop',
131+
onlyMobile: 'onlyMobile',
132+
onlyTablet: 'onlyTablet',
133+
},
134+
},
135+
SPACINGS: {},
136+
});
137+
jest.spyOn(styledComponents, 'useTheme').mockImplementation(useThemeHock);
138+
const styles = useStylesV2({
139+
styleName: 'fakeStyleName',
140+
isOptional: true,
141+
});
142+
expect(styles).toBe(undefined);
143+
});
144+
});

src/hooks/useStyles/useStyles.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { useTheme } from 'styled-components';
22

33
import { mergeObjects } from '@/utils/mergeObjects/mergeObjects';
44

5+
/**
6+
* @version This hook has a upper version, please use useStylesV2
7+
*/
58
export const useStyles = <T, V = undefined | string>(
69
styleName: string,
710
typeName?: V,

src/hooks/useStyles/useStylesV2.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { useTheme } from 'styled-components';
2+
3+
import { mergeObjects } from '@/utils';
4+
5+
interface IUseStyles<V> {
6+
styleName: string;
7+
variantName?: V;
8+
customTokens?: object;
9+
isOptional?: boolean;
10+
}
11+
12+
export const useStylesV2 = <T, V = undefined | string>({
13+
styleName,
14+
variantName,
15+
customTokens,
16+
isOptional,
17+
}: IUseStyles<V>): T | undefined => {
18+
const theme = useTheme();
19+
if (styleName in theme) {
20+
const style = theme[styleName];
21+
22+
if (!variantName) {
23+
return style as T;
24+
} else if ((variantName as string) in style) {
25+
if (customTokens) {
26+
return mergeObjects(structuredClone(style[variantName]), customTokens) as T;
27+
}
28+
return style[variantName];
29+
}
30+
if (isOptional) {
31+
return undefined;
32+
}
33+
throw Error(`type ${variantName} does not exist`);
34+
}
35+
if (isOptional) {
36+
return undefined;
37+
}
38+
throw Error(`styles ${styleName} does not exist`);
39+
};

src/tests/__mocks__/assetMock.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = {};
1+
module.exports = 'ASSET_MOCK';

0 commit comments

Comments
 (0)