@marigold/system 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/Element.d.ts +8 -0
  2. package/dist/cache.d.ts +4 -0
  3. package/dist/index.d.ts +6 -4
  4. package/dist/normalize.d.ts +110 -0
  5. package/dist/reset.d.ts +24 -0
  6. package/dist/system.cjs.development.js +332 -95
  7. package/dist/system.cjs.development.js.map +1 -1
  8. package/dist/system.cjs.production.min.js +1 -1
  9. package/dist/system.cjs.production.min.js.map +1 -1
  10. package/dist/system.esm.js +323 -92
  11. package/dist/system.esm.js.map +1 -1
  12. package/dist/types.d.ts +9 -0
  13. package/dist/useClassname.d.ts +2 -0
  14. package/dist/useStyles.d.ts +15 -0
  15. package/dist/useTheme.d.ts +10 -0
  16. package/package.json +7 -10
  17. package/src/Colors.stories.mdx +616 -448
  18. package/src/Element.test.tsx +203 -0
  19. package/src/Element.tsx +59 -0
  20. package/src/cache.ts +4 -0
  21. package/src/concepts-principles.mdx +1 -1
  22. package/src/index.ts +6 -4
  23. package/src/normalize.test.tsx +42 -0
  24. package/src/normalize.ts +131 -0
  25. package/src/reset.ts +108 -0
  26. package/src/types.ts +16 -0
  27. package/src/useClassname.test.tsx +70 -0
  28. package/src/useClassname.ts +23 -0
  29. package/src/useStyles.stories.mdx +24 -0
  30. package/src/useStyles.test.tsx +286 -0
  31. package/src/useStyles.ts +63 -0
  32. package/src/useTheme.test.tsx +115 -0
  33. package/src/useTheme.tsx +22 -0
  34. package/dist/Box/Box.d.ts +0 -6
  35. package/dist/Box/index.d.ts +0 -1
  36. package/dist/MarigoldProvider.d.ts +0 -7
  37. package/dist/categories.d.ts +0 -169
  38. package/dist/emotion.d.ts +0 -7
  39. package/dist/system.d.ts +0 -37
  40. package/src/Box/Box.stories.mdx +0 -148
  41. package/src/Box/Box.test.tsx +0 -215
  42. package/src/Box/Box.tsx +0 -58
  43. package/src/Box/index.ts +0 -1
  44. package/src/MarigoldProvider.test.tsx +0 -80
  45. package/src/MarigoldProvider.tsx +0 -37
  46. package/src/categories.ts +0 -203
  47. package/src/emotion.ts +0 -39
  48. package/src/system.test.tsx +0 -84
  49. package/src/system.tsx +0 -55
  50. package/src/writeComponent.stories.mdx +0 -114
@@ -0,0 +1,203 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { useStyles } from './useStyles';
4
+ import { ThemeProvider } from './useTheme';
5
+ import { Element } from './Element';
6
+
7
+ const theme = {
8
+ text: {
9
+ body: {
10
+ fontSize: 1,
11
+ color: 'black',
12
+ marginTop: '2px',
13
+ },
14
+ heading: {
15
+ fontSize: 3,
16
+ color: 'primary',
17
+ },
18
+ padding: {
19
+ paddingTop: '2px',
20
+ },
21
+ },
22
+ };
23
+
24
+ test('renders a <div> by default', () => {
25
+ render(<Element>Text</Element>);
26
+ const testelem = screen.getByText('Text');
27
+
28
+ expect(testelem instanceof HTMLDivElement).toBeTruthy();
29
+ });
30
+
31
+ test('supports as prop', () => {
32
+ render(<Element as="p">Text</Element>);
33
+ const testelem = screen.getByText('Text');
34
+
35
+ expect(testelem instanceof HTMLParagraphElement).toBeTruthy();
36
+ });
37
+
38
+ test('supports HTML className attribute', () => {
39
+ render(<Element className="my-custom-class">Text</Element>);
40
+ const element = screen.getByText('Text');
41
+
42
+ expect(element.getAttribute('class')).toMatch('my-custom-class');
43
+ });
44
+
45
+ test('passes down HTML attributes', () => {
46
+ render(
47
+ <Element className="my-custom-class" id="element-id" disabled>
48
+ Text
49
+ </Element>
50
+ );
51
+ const element = screen.getByText('Text');
52
+
53
+ expect(element.getAttribute('id')).toEqual('element-id');
54
+ expect(element.getAttribute('disabled')).toMatch('');
55
+ expect(element.getAttribute('class')).toMatch('my-custom-class');
56
+ });
57
+
58
+ test('forwards ref', () => {
59
+ const ref = React.createRef<HTMLButtonElement>();
60
+ render(
61
+ <Element as="button" ref={ref}>
62
+ button
63
+ </Element>
64
+ );
65
+
66
+ expect(ref.current instanceof HTMLButtonElement).toBeTruthy();
67
+ });
68
+
69
+ test('base styles first', () => {
70
+ const { getByText } = render(<Element as="p">Text</Element>);
71
+ const testelem = getByText('Text');
72
+ const style = getComputedStyle(testelem);
73
+
74
+ expect(style.marginTop).toEqual('0px'); // 0px come from base
75
+ });
76
+
77
+ test('variant styles second', () => {
78
+ const TestComponent: React.FC<{ variant?: 'body' }> = ({
79
+ variant = 'body',
80
+ children,
81
+ ...props
82
+ }) => {
83
+ return (
84
+ <Element as="p" variant={`text.${variant}`} {...props}>
85
+ {children}
86
+ </Element>
87
+ );
88
+ };
89
+
90
+ const { getByText } = render(
91
+ <ThemeProvider theme={theme}>
92
+ <TestComponent>Text</TestComponent>
93
+ </ThemeProvider>
94
+ );
95
+ const testelem = getByText('Text');
96
+ const style = getComputedStyle(testelem);
97
+
98
+ expect(style.marginTop).not.toEqual('0px'); // 0px come from base
99
+ expect(style.marginBottom).toEqual('0px'); // 0px still come from base
100
+ expect(style.marginTop).toEqual('2px'); // 2px come from variant
101
+ });
102
+
103
+ test('array of variant styles', () => {
104
+ const TestComponent: React.FC<{ variant?: 'body' }> = ({
105
+ variant = 'body',
106
+ children,
107
+ ...props
108
+ }) => {
109
+ return (
110
+ <Element as="p" variant={[`text.${variant}`, `text.padding`]} {...props}>
111
+ {children}
112
+ </Element>
113
+ );
114
+ };
115
+
116
+ const { getByText } = render(
117
+ <ThemeProvider theme={theme}>
118
+ <TestComponent>Text</TestComponent>
119
+ </ThemeProvider>
120
+ );
121
+ const testelem = getByText('Text');
122
+ const style = getComputedStyle(testelem);
123
+
124
+ expect(style.marginTop).not.toEqual('0px'); // 0px come from base
125
+ expect(style.marginBottom).toEqual('0px'); // 0px still come from base
126
+ expect(style.marginTop).toEqual('2px'); // 2px marginTop come from variant
127
+ expect(style.paddingTop).toEqual('2px'); // 2px paddingTop come from variant
128
+ });
129
+
130
+ test('custom styles with css prop third', () => {
131
+ const TestComponent: React.FC<{ variant?: 'body' }> = ({
132
+ variant = 'body',
133
+ children,
134
+ ...props
135
+ }) => {
136
+ return (
137
+ <Element
138
+ as="p"
139
+ variant={`text.${variant}`}
140
+ css={{ marginTop: '4px' }}
141
+ {...props}
142
+ >
143
+ {children}
144
+ </Element>
145
+ );
146
+ };
147
+
148
+ const { getByText } = render(
149
+ <ThemeProvider theme={theme}>
150
+ <TestComponent>Text</TestComponent>
151
+ </ThemeProvider>
152
+ );
153
+ const testelem = getByText('Text');
154
+ const style = getComputedStyle(testelem);
155
+
156
+ expect(style.marginTop).not.toEqual('0px'); // do not apply 0px from base
157
+ expect(style.marginTop).not.toEqual('2px'); // do not apply 2px from variant
158
+ expect(style.marginTop).toEqual('4px'); // apply 4px from custom styles
159
+ });
160
+
161
+ test("don't apply the same reset multiple times", () => {
162
+ const Button = ({ className }: { className?: string }) => {
163
+ const classNames = useStyles({ element: 'button', className });
164
+ return (
165
+ <Element as="button" title="button" className={classNames}>
166
+ Click me!
167
+ </Element>
168
+ );
169
+ };
170
+ const Wrapper = () => <Button />;
171
+
172
+ render(<Wrapper />);
173
+ const button = screen.getByTitle('button');
174
+ const classNames = button.className.split(' ').filter(i => i.length);
175
+
176
+ // Test if applied classnames are unique
177
+ expect(classNames.length).toEqual([...new Set(classNames)].length);
178
+ });
179
+
180
+ test('normalize tag name <a>', () => {
181
+ const TestComponent: React.FC<{ variant?: 'body' }> = ({
182
+ variant = 'body',
183
+ children,
184
+ ...props
185
+ }) => {
186
+ return (
187
+ <Element as="a" variant={`text.${variant}`} {...props}>
188
+ {children}
189
+ </Element>
190
+ );
191
+ };
192
+
193
+ const { getByText } = render(
194
+ <ThemeProvider theme={theme}>
195
+ <TestComponent>Link</TestComponent>
196
+ </ThemeProvider>
197
+ );
198
+ const testelem = getByText('Link');
199
+ const style = getComputedStyle(testelem);
200
+
201
+ expect(style.boxSizing).toEqual('border-box'); // from base
202
+ expect(style.textDecoration).toEqual('none'); // from a
203
+ });
@@ -0,0 +1,59 @@
1
+ import { jsx } from '@emotion/react';
2
+ import { forwardRef } from 'react';
3
+ import {
4
+ PolymorphicPropsWithRef,
5
+ PolymorphicComponentWithRef,
6
+ } from '@marigold/types';
7
+
8
+ import { getNormalizedStyles } from './normalize';
9
+ import { CSSObject } from './types';
10
+ import { useTheme } from './useTheme';
11
+
12
+ export type ElementOwnProps = {
13
+ css?: CSSObject;
14
+ variant?: string | string[];
15
+ };
16
+
17
+ export type ElementProps = PolymorphicPropsWithRef<ElementOwnProps, 'div'>;
18
+
19
+ /**
20
+ * Function expression to check if there is any falsy value or empty object
21
+ */
22
+ const isNotEmpty = (val: any) =>
23
+ !(val && Object.keys(val).length === 0 && val.constructor === Object);
24
+
25
+ /**
26
+ * Get the normalized base styles
27
+ */
28
+ const baseStyles = getNormalizedStyles('base');
29
+
30
+ export const Element: PolymorphicComponentWithRef<ElementOwnProps, 'div'> =
31
+ forwardRef(
32
+ ({ as = 'div', css: styles = {}, variant, children, ...props }, ref) => {
33
+ const { css } = useTheme();
34
+
35
+ /**
36
+ * Transform variant input for `@theme-ui/css`
37
+ */
38
+ const variants = Array.isArray(variant)
39
+ ? variant.map(v => ({ variant: v }))
40
+ : [{ variant }];
41
+
42
+ return jsx(
43
+ as,
44
+ {
45
+ ...props,
46
+ ...{
47
+ css: [
48
+ baseStyles,
49
+ getNormalizedStyles(as),
50
+ ...variants.map(v => css(v)),
51
+ css(styles),
52
+ ].filter(isNotEmpty),
53
+ },
54
+ ref,
55
+ },
56
+ children
57
+ );
58
+ }
59
+ );
package/src/cache.ts ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Expose cache from emotion so we can use the same cache when doing SSR.
3
+ */
4
+ export { cache } from '@emotion/css';
@@ -1,4 +1,4 @@
1
- import { Meta } from '@storybook/addon-docs/blocks';
1
+ import { Meta } from '@storybook/addon-docs';
2
2
 
3
3
  <Meta title="Guides/Concepts & Principles" />
4
4
 
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
- export * from './Box';
2
- export * from './categories';
3
- export * from './MarigoldProvider';
4
- export * from './system';
1
+ export * from './Element';
2
+ export * from './cache';
3
+ export * from './types';
4
+ export * from './useClassname';
5
+ export * from './useStyles';
6
+ export * from './useTheme';
@@ -0,0 +1,42 @@
1
+ import { getNormalizedStyles } from './normalize';
2
+
3
+ test('get base styles', () => {
4
+ const baseStyles = getNormalizedStyles('base');
5
+ expect(baseStyles).toEqual({
6
+ boxSizing: 'border-box',
7
+ margin: 0,
8
+ padding: 0,
9
+ minWidth: 0,
10
+ fontSize: '100%',
11
+ fontFamily: 'inherit',
12
+ verticalAlign: 'baseline',
13
+ WebkitTapHighlightColor: 'transparent',
14
+ });
15
+ });
16
+
17
+ test('get reset style by element', () => {
18
+ const baseStyles = getNormalizedStyles('a');
19
+ expect(baseStyles).toEqual({
20
+ textDecoration: 'none',
21
+ touchAction: 'manipulation',
22
+ });
23
+ });
24
+
25
+ test('getNormalizedStyles returns base if input is not a string', () => {
26
+ const baseStyles = getNormalizedStyles(undefined);
27
+ expect(baseStyles).toEqual({
28
+ boxSizing: 'border-box',
29
+ margin: 0,
30
+ padding: 0,
31
+ minWidth: 0,
32
+ fontSize: '100%',
33
+ fontFamily: 'inherit',
34
+ verticalAlign: 'baseline',
35
+ WebkitTapHighlightColor: 'transparent',
36
+ });
37
+ });
38
+
39
+ test('getNormalizedStyles returns empty object if input is unknown', () => {
40
+ const baseStyles = getNormalizedStyles('p');
41
+ expect(baseStyles).toEqual({});
42
+ });
@@ -0,0 +1,131 @@
1
+ import { ElementType } from 'react';
2
+
3
+ const base = {
4
+ boxSizing: 'border-box',
5
+ margin: 0,
6
+ padding: 0,
7
+ minWidth: 0,
8
+ fontSize: '100%',
9
+ fontFamily: 'inherit',
10
+ verticalAlign: 'baseline',
11
+ WebkitTapHighlightColor: 'transparent',
12
+ } as const;
13
+
14
+ // Content
15
+ // ---------------
16
+ const block = {
17
+ display: 'block',
18
+ } as const;
19
+
20
+ const list = {
21
+ // empty
22
+ } as const;
23
+
24
+ const table = {
25
+ borderCollapse: 'collapse',
26
+ borderSpacing: 0,
27
+ } as const;
28
+
29
+ // Typography
30
+ // ---------------
31
+ const a = {
32
+ textDecoration: 'none',
33
+ touchAction: 'manipulation',
34
+ } as const;
35
+
36
+ const quote = {
37
+ quotes: 'none',
38
+ selectors: {
39
+ '&:before, &:after': {
40
+ content: "''",
41
+ },
42
+ },
43
+ } as const;
44
+
45
+ // Form Elements
46
+ // ---------------
47
+ const button = {
48
+ display: 'block',
49
+ appearance: 'none',
50
+ background: 'transparent',
51
+ textAlign: 'center',
52
+ touchAction: 'manipulation',
53
+ } as const;
54
+
55
+ const input = {
56
+ display: 'block',
57
+ appearance: 'none',
58
+ selectors: {
59
+ '&::-ms-clear': {
60
+ display: 'none',
61
+ },
62
+ '&::-webkit-search-cancel-button': {
63
+ WebkitAppearance: 'none',
64
+ },
65
+ },
66
+ } as const;
67
+
68
+ const select = {
69
+ display: 'block',
70
+ appearance: 'none',
71
+ selectors: {
72
+ '&::-ms-expand': {
73
+ display: 'none',
74
+ },
75
+ },
76
+ } as const;
77
+
78
+ const textarea = {
79
+ display: 'block',
80
+ appearance: 'none',
81
+ } as const;
82
+
83
+ // Reset
84
+ // ---------------
85
+ const reset = {
86
+ article: block,
87
+ aside: block,
88
+ details: block,
89
+ figcaption: block,
90
+ figure: block,
91
+ footer: block,
92
+ header: block,
93
+ hgroup: block,
94
+ menu: block,
95
+ nav: block,
96
+ section: block,
97
+ ul: list,
98
+ ol: list,
99
+ blockquote: quote,
100
+ q: quote,
101
+ a,
102
+ base,
103
+ table,
104
+ select,
105
+ button,
106
+ textarea,
107
+ input,
108
+ } as const;
109
+
110
+ export type NormalizedElement = keyof typeof reset;
111
+ const isKnownElement = (input: string): input is NormalizedElement =>
112
+ input in reset;
113
+
114
+ /**
115
+ * Helper to conveniently get reset styles.
116
+ */
117
+ export const getNormalizedStyles = (input?: ElementType): object => {
118
+ /**
119
+ * If a React component is given, we don't apply any reset styles
120
+ * and return the base reset.
121
+ */
122
+ if (typeof input !== 'string') {
123
+ return reset.base;
124
+ }
125
+
126
+ /**
127
+ * Try to find the reset style for a HTML element. If the element
128
+ * is not included return empty styles.
129
+ */
130
+ return isKnownElement(input) ? reset[input] : {};
131
+ };
package/src/reset.ts ADDED
@@ -0,0 +1,108 @@
1
+ import { css } from '@emotion/css';
2
+
3
+ const base = css({
4
+ boxSizing: 'border-box',
5
+ margin: 0,
6
+ padding: 0,
7
+ minWidth: 0,
8
+ fontSize: '100%',
9
+ font: 'inherit',
10
+ verticalAlign: 'baseline',
11
+ WebkitTapHighlightColor: 'transparent',
12
+ });
13
+
14
+ // Content
15
+ // ---------------
16
+ const block = css({
17
+ display: 'block',
18
+ });
19
+
20
+ const list = css({
21
+ // empty
22
+ });
23
+
24
+ const table = css({
25
+ borderCollapse: 'collapse',
26
+ borderSpacing: 0,
27
+ });
28
+
29
+ // Typography
30
+ // ---------------
31
+ const a = css({
32
+ textDecoration: 'none',
33
+ touchAction: 'manipulation',
34
+ });
35
+
36
+ const quote = css({
37
+ quotes: 'none',
38
+ selectors: {
39
+ '&:before, &:after': {
40
+ content: "''",
41
+ },
42
+ },
43
+ });
44
+
45
+ // Form Elements
46
+ // ---------------
47
+ const button = css({
48
+ display: 'block',
49
+ appearance: 'none',
50
+ background: 'transparent',
51
+ textAlign: 'center',
52
+ touchAction: 'manipulation',
53
+ });
54
+
55
+ const input = css({
56
+ display: 'block',
57
+ appearance: 'none',
58
+ selectors: {
59
+ '&::-ms-clear': {
60
+ display: 'none',
61
+ },
62
+ '&::-webkit-search-cancel-button': {
63
+ WebkitAppearance: 'none',
64
+ },
65
+ },
66
+ });
67
+
68
+ const select = css({
69
+ display: 'block',
70
+ appearance: 'none',
71
+ selectors: {
72
+ '&::-ms-expand': {
73
+ display: 'none',
74
+ },
75
+ },
76
+ });
77
+
78
+ const textarea = css({
79
+ display: 'block',
80
+ appearance: 'none',
81
+ });
82
+
83
+ // Reset
84
+ // ---------------
85
+ export const reset = {
86
+ article: block,
87
+ aside: block,
88
+ details: block,
89
+ figcaption: block,
90
+ figure: block,
91
+ footer: block,
92
+ header: block,
93
+ hgroup: block,
94
+ menu: block,
95
+ nav: block,
96
+ section: block,
97
+ ul: list,
98
+ ol: list,
99
+ blockquote: quote,
100
+ q: quote,
101
+ a,
102
+ base,
103
+ table,
104
+ select,
105
+ button,
106
+ textarea,
107
+ input,
108
+ } as const;
package/src/types.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Create type aliases for `theme-ui` so that it doesn't leak too much into our code.
3
+ */
4
+ import {
5
+ Theme as ThemeUITheme,
6
+ ThemeUIStyleObject,
7
+ ThemeUICSSObject,
8
+ ThemeUICSSProperties,
9
+ ResponsiveStyleValue as RSV,
10
+ } from '@theme-ui/css';
11
+
12
+ export type ResponsiveStyleValue<T> = RSV<T>;
13
+ export type StyleObject = ThemeUIStyleObject;
14
+ export type CSSObject = ThemeUICSSObject;
15
+ export type CSSProperties = ThemeUICSSProperties;
16
+ export type Theme = ThemeUITheme;
@@ -0,0 +1,70 @@
1
+ import React from 'react';
2
+ import { renderHook } from '@testing-library/react-hooks';
3
+ import { useClassname } from './useClassname';
4
+ import { ThemeProvider } from './useTheme';
5
+
6
+ // Setup
7
+ // ---------------
8
+ const theme = {
9
+ colors: {
10
+ primary: 'hotpink',
11
+ black: '#000',
12
+ },
13
+ sizes: [0, 1, 2],
14
+ text: {
15
+ body: {
16
+ fontSize: 1,
17
+ color: 'black',
18
+ },
19
+ heading: {
20
+ fontSize: 3,
21
+ color: 'primary',
22
+ },
23
+ },
24
+ };
25
+
26
+ const wrapper: React.FC = ({ children }) => (
27
+ <ThemeProvider theme={theme}>{children}</ThemeProvider>
28
+ );
29
+
30
+ test('create a string classname', () => {
31
+ const { result } = renderHook(() => useClassname({ color: 'primary' }), {
32
+ wrapper,
33
+ });
34
+ expect(result.current).toEqual(expect.any(String));
35
+ });
36
+
37
+ test('create classnames from multiple intpus', () => {
38
+ const { result } = renderHook(
39
+ () => useClassname({ color: 'primary' }, { p: 2 }),
40
+ {
41
+ wrapper,
42
+ }
43
+ );
44
+ expect(result.current).toEqual(expect.any(String));
45
+ });
46
+
47
+ test('create a unique classnames', () => {
48
+ const { result: first } = renderHook(
49
+ () => useClassname({ color: 'primary' }),
50
+ {
51
+ wrapper,
52
+ }
53
+ );
54
+ const { result: second } = renderHook(
55
+ () => useClassname({ color: 'black' }),
56
+ {
57
+ wrapper,
58
+ }
59
+ );
60
+ expect(first.current).not.toEqual(second.current);
61
+ });
62
+
63
+ test('handle empty styles', () => {
64
+ /**
65
+ * emotion will add a lot of `css-0` classes especially
66
+ * when a "variant" is not present in the theme.
67
+ */
68
+ const { result } = renderHook(() => useClassname({}));
69
+ expect(result.current).toMatchInlineSnapshot(`""`);
70
+ });
@@ -0,0 +1,23 @@
1
+ import { css as emotion } from '@emotion/css';
2
+ import { StyleObject } from './types';
3
+ import { useTheme } from './useTheme';
4
+
5
+ // 🤫 https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object
6
+ // lodash.isEmpty is tooo much KBs!
7
+ const isEmpty = (val: any) =>
8
+ val && Object.keys(val).length === 0 && val.constructor === Object;
9
+
10
+ export const useClassname = (...styles: StyleObject[]) => {
11
+ const { css } = useTheme();
12
+ return styles
13
+ .map(style => {
14
+ /**
15
+ * emotion will create a `css-0` class whenever an empty object is
16
+ * passed. Since this makes debugging harder we'll do not pass empty
17
+ * objects to emotion.
18
+ */
19
+ const themedStyle = css(style);
20
+ return isEmpty(themedStyle) ? '' : emotion(themedStyle);
21
+ })
22
+ .join(' ');
23
+ };
@@ -0,0 +1,24 @@
1
+ import { Meta, Story, Canvas } from '@storybook/addon-docs';
2
+ import { useStyles } from './useStyles';
3
+ import { Text } from '@marigold/components';
4
+
5
+ <Meta title="Hooks/useStyles" />
6
+
7
+ # useStyles
8
+
9
+ <Canvas>
10
+ <Story name="usestyles">
11
+ <Text>
12
+ The useStyles hook generates classnames that style your component:
13
+ </Text>
14
+ </Story>
15
+ </Canvas>
16
+
17
+ ```tsx
18
+ useStyles({
19
+ element: ElementType; // reset styles for the given HTML element
20
+ css: CSSObject; // custom styles
21
+ variant: string|string[]; // theme variant(s)
22
+ className: string; // additional classnames
23
+ })
24
+ ```