@marigold/system 0.0.2 → 0.3.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 (47) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/dist/Box.d.ts +14 -0
  3. package/dist/Global.d.ts +2 -0
  4. package/dist/SVG.d.ts +6 -0
  5. package/dist/index.d.ts +7 -4
  6. package/dist/normalize.d.ts +143 -5
  7. package/dist/system.cjs.development.js +334 -159
  8. package/dist/system.cjs.development.js.map +1 -1
  9. package/dist/system.cjs.production.min.js +1 -1
  10. package/dist/system.cjs.production.min.js.map +1 -1
  11. package/dist/system.esm.js +324 -156
  12. package/dist/system.esm.js.map +1 -1
  13. package/dist/theme.d.ts +136 -0
  14. package/dist/types.d.ts +8 -0
  15. package/dist/useTheme.d.ts +15 -5
  16. package/dist/variant.d.ts +29 -0
  17. package/package.json +6 -8
  18. package/src/Box.test.tsx +308 -0
  19. package/src/Box.tsx +199 -0
  20. package/src/Colors.stories.mdx +492 -448
  21. package/src/Global.test.tsx +57 -0
  22. package/src/Global.tsx +34 -0
  23. package/src/SVG.stories.mdx +55 -0
  24. package/src/SVG.test.tsx +82 -0
  25. package/src/SVG.tsx +24 -0
  26. package/src/concepts-principles.mdx +1 -1
  27. package/src/index.ts +7 -4
  28. package/src/normalize.test.tsx +15 -0
  29. package/src/normalize.ts +79 -93
  30. package/src/theme.ts +157 -0
  31. package/src/types.ts +14 -0
  32. package/src/useTheme.test.tsx +92 -17
  33. package/src/useTheme.tsx +45 -6
  34. package/src/variant.test.ts +93 -0
  35. package/src/variant.ts +54 -0
  36. package/dist/categories.d.ts +0 -169
  37. package/dist/system.d.ts +0 -37
  38. package/dist/useClassname.d.ts +0 -2
  39. package/dist/useStyles.d.ts +0 -10
  40. package/src/categories.ts +0 -203
  41. package/src/system.test.tsx +0 -84
  42. package/src/system.tsx +0 -55
  43. package/src/useClassname.test.tsx +0 -61
  44. package/src/useClassname.ts +0 -8
  45. package/src/useStyles.test.tsx +0 -313
  46. package/src/useStyles.ts +0 -56
  47. package/src/writeComponent.stories.mdx +0 -126
@@ -1,313 +0,0 @@
1
- import React from 'react';
2
- import { renderHook } from '@testing-library/react-hooks';
3
- import { useStyles } from './useStyles';
4
- import { ThemeProvider } from './useTheme';
5
- import { render } from '@testing-library/react';
6
-
7
- // Setup
8
- // ---------------
9
- const theme = {
10
- text: {
11
- body: {
12
- fontSize: 1,
13
- color: 'black',
14
- marginTop: '2px',
15
- },
16
- heading: {
17
- fontSize: 3,
18
- color: 'primary',
19
- },
20
- padding: {
21
- paddingTop: '2px',
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(
32
- () => useStyles({ element: ['a'], color: 'primary' }),
33
- {
34
- wrapper,
35
- }
36
- );
37
- expect(result.current).toEqual(expect.any(String));
38
- });
39
-
40
- // Tests
41
- // ---------------
42
-
43
- test('base styles first', () => {
44
- const TestComponent: React.FC<{}> = ({ children, ...props }) => {
45
- const classNames = useStyles({ element: ['p'] });
46
- return (
47
- <p className={classNames} {...props}>
48
- {children}
49
- </p>
50
- );
51
- };
52
-
53
- const { getByText } = render(
54
- <ThemeProvider theme={theme}>
55
- <TestComponent>Text</TestComponent>
56
- </ThemeProvider>
57
- );
58
- const testelem = getByText('Text');
59
- const style = getComputedStyle(testelem);
60
-
61
- expect(style.marginTop).toEqual('0px'); // 0px come from base
62
- });
63
-
64
- test('variant styles second', () => {
65
- const TestComponent: React.FC<{ variant?: 'body' }> = ({
66
- variant = 'body',
67
- children,
68
- ...props
69
- }) => {
70
- const classNames = useStyles({
71
- element: ['p'],
72
- variant: `text.${variant}`,
73
- });
74
- return (
75
- <p className={classNames} {...props}>
76
- {children}
77
- </p>
78
- );
79
- };
80
-
81
- const { getByText } = render(
82
- <ThemeProvider theme={theme}>
83
- <TestComponent>Text</TestComponent>
84
- </ThemeProvider>
85
- );
86
- const testelem = getByText('Text');
87
- const style = getComputedStyle(testelem);
88
-
89
- expect(style.marginTop).not.toEqual('0px'); // 0px come from base
90
- expect(style.marginBottom).toEqual('0px'); // 0px still come from base
91
- expect(style.marginTop).toEqual('2px'); // 2px come from variant
92
- });
93
-
94
- test('array of variant styles', () => {
95
- const TestComponent: React.FC<{ variant?: 'body' }> = ({
96
- variant = 'body',
97
- children,
98
- ...props
99
- }) => {
100
- const classNames = useStyles({
101
- element: ['p'],
102
- variant: [`text.${variant}`, `text.padding`],
103
- components: 'body',
104
- });
105
- return (
106
- <p className={classNames} {...props}>
107
- {children}
108
- </p>
109
- );
110
- };
111
-
112
- const { getByText } = render(
113
- <ThemeProvider theme={theme}>
114
- <TestComponent>Text</TestComponent>
115
- </ThemeProvider>
116
- );
117
- const testelem = getByText('Text');
118
- const style = getComputedStyle(testelem);
119
-
120
- expect(style.marginTop).not.toEqual('0px'); // 0px come from base
121
- expect(style.marginBottom).toEqual('0px'); // 0px still come from base
122
- expect(style.marginTop).toEqual('2px'); // 2px marginTop come from variant
123
- expect(style.paddingTop).toEqual('2px'); // 2px paddingTop come from variant
124
- });
125
-
126
- test('custom styles third', () => {
127
- const TestComponent: React.FC<{ variant?: 'body' }> = ({
128
- variant = 'body',
129
- children,
130
- ...props
131
- }) => {
132
- const classNames = useStyles({
133
- element: ['p'],
134
- variant: `text.${variant}`,
135
- marginTop: '4px',
136
- });
137
- return (
138
- <p className={classNames} {...props}>
139
- {children}
140
- </p>
141
- );
142
- };
143
-
144
- const { getByText } = render(
145
- <ThemeProvider theme={theme}>
146
- <TestComponent>Text</TestComponent>
147
- </ThemeProvider>
148
- );
149
- const testelem = getByText('Text');
150
- const style = getComputedStyle(testelem);
151
-
152
- expect(style.marginTop).not.toEqual('0px'); // do not apply 0px from base
153
- expect(style.marginTop).not.toEqual('2px'); // do not apply 2px from variant
154
- expect(style.marginTop).toEqual('4px'); // apply 4px from custom styles
155
- });
156
-
157
- test('customClassName styles fourth', () => {
158
- const TestComponent: React.FC<{ variant?: 'body' }> = ({
159
- variant = 'body',
160
- children,
161
- ...props
162
- }) => {
163
- const classNames = useStyles(
164
- {
165
- element: ['p'],
166
- variant: `text.${variant}`,
167
- marginTop: '4px',
168
- },
169
- useStyles({ element: ['p'], marginTop: '8px' })
170
- );
171
- return (
172
- <p className={classNames} {...props}>
173
- {children}
174
- </p>
175
- );
176
- };
177
-
178
- const { getByText } = render(
179
- <ThemeProvider theme={theme}>
180
- <TestComponent>Text</TestComponent>
181
- </ThemeProvider>
182
- );
183
- const testelem = getByText('Text');
184
- const style = getComputedStyle(testelem);
185
-
186
- expect(style.marginTop).not.toEqual('0px'); // do not apply 0px from base
187
- expect(style.marginTop).not.toEqual('2px'); // do not apply 2px from variant
188
- expect(style.marginTop).not.toEqual('4px'); // do not apply 4px from custom styles
189
- expect(style.marginTop).toEqual('8px'); // apply 8px from customClassNames styles
190
- });
191
-
192
- test('normalize base without element prop', () => {
193
- const TestComponent: React.FC<{ variant?: 'body' }> = ({
194
- variant = 'normal',
195
- children,
196
- ...props
197
- }) => {
198
- const classNames = useStyles({
199
- // element: [],
200
- variant: `text.${variant}`,
201
- });
202
- return (
203
- <a className={classNames} {...props}>
204
- {children}
205
- </a>
206
- );
207
- };
208
-
209
- const { getByText } = render(
210
- <ThemeProvider theme={theme}>
211
- <TestComponent>Link</TestComponent>
212
- </ThemeProvider>
213
- );
214
- const testelem = getByText('Link');
215
- const style = getComputedStyle(testelem);
216
-
217
- expect(style.boxSizing).toEqual('border-box');
218
- expect(style.margin).toEqual('0px');
219
- expect(style.padding).toEqual('0px');
220
- expect(style.minWidth).toEqual('0');
221
- });
222
-
223
- test('normalize base with empty element prop', () => {
224
- const TestComponent: React.FC<{ variant?: 'body' }> = ({
225
- variant = 'body',
226
- children,
227
- ...props
228
- }) => {
229
- const classNames = useStyles({
230
- element: [],
231
- variant: `text.${variant}`,
232
- });
233
- return (
234
- <a className={classNames} {...props}>
235
- {children}
236
- </a>
237
- );
238
- };
239
-
240
- const { getByText } = render(
241
- <ThemeProvider theme={theme}>
242
- <TestComponent>Link</TestComponent>
243
- </ThemeProvider>
244
- );
245
- const testelem = getByText('Link');
246
- const style = getComputedStyle(testelem);
247
-
248
- expect(style.boxSizing).toEqual('border-box');
249
- expect(style.margin).toEqual('0px');
250
- expect(style.padding).toEqual('0px');
251
- expect(style.minWidth).toEqual('0');
252
- });
253
-
254
- test('normalize tag name <a>', () => {
255
- const TestComponent: React.FC<{ variant?: 'body' }> = ({
256
- variant = 'body',
257
- children,
258
- ...props
259
- }) => {
260
- const classNames = useStyles({
261
- element: ['a'],
262
- variant: `text.${variant}`,
263
- });
264
- return (
265
- <a className={classNames} {...props}>
266
- {children}
267
- </a>
268
- );
269
- };
270
-
271
- const { getByText } = render(
272
- <ThemeProvider theme={theme}>
273
- <TestComponent>Link</TestComponent>
274
- </ThemeProvider>
275
- );
276
- const testelem = getByText('Link');
277
- const style = getComputedStyle(testelem);
278
-
279
- expect(style.boxSizing).toEqual('border-box'); // from base
280
- expect(style.textDecoration).toEqual('none'); // from a
281
- });
282
-
283
- test('normalize tag names <a> and <p>', () => {
284
- const TestComponent: React.FC<{ variant?: 'body' }> = ({
285
- variant = 'body',
286
- children,
287
- ...props
288
- }) => {
289
- const classNames = useStyles({
290
- element: ['a', 'p'],
291
- variant: `text.${variant}`,
292
- });
293
- return (
294
- <p>
295
- <a className={classNames} {...props}>
296
- {children}
297
- </a>
298
- </p>
299
- );
300
- };
301
-
302
- const { getByText } = render(
303
- <ThemeProvider theme={theme}>
304
- <TestComponent>Link</TestComponent>
305
- </ThemeProvider>
306
- );
307
- const testelem = getByText('Link');
308
- const style = getComputedStyle(testelem);
309
-
310
- expect(style.boxSizing).toEqual('border-box'); // from base
311
- expect(style.textDecoration).toEqual('none'); // from a
312
- expect(style.listStyle).toEqual('none'); // from p
313
- });
package/src/useStyles.ts DELETED
@@ -1,56 +0,0 @@
1
- import { useClassname } from './useClassname';
2
-
3
- import * as resetStyleRefs from './normalize';
4
- import { ElementType } from 'react';
5
-
6
- export type StylesProps = {
7
- element?: ElementType[];
8
- variant?: string | string[];
9
- [key: string]: any;
10
- };
11
-
12
- /**
13
- * Hook function that can add base styles, normalization, variant and custom styles
14
- */
15
- export const useStyles = (
16
- { element, variant, ...styles }: StylesProps,
17
- classNames?: string
18
- ) => {
19
- /**
20
- * Normalization styles looked up by html tag name(s). Base normalization
21
- * is always applied.
22
- */
23
- var elementArray: ElementType[] = [];
24
- if (element) {
25
- element.push('base'); // always apply base styles
26
- elementArray = element;
27
- } else {
28
- elementArray = ['base'];
29
- }
30
- const resetStyles = resetStyleRefs.el;
31
- const elements: { [key: string]: any }[] = elementArray.map(
32
- styleObject => resetStyles[styleObject as keyof typeof resetStyleRefs.el]
33
- );
34
-
35
- const elementObject = Object.assign({}, ...elements);
36
-
37
- const basedOnNormalize = useClassname(elementObject);
38
-
39
- /**
40
- * Variants are retrieved from the theme.
41
- */
42
- const variants = Array.isArray(variant)
43
- ? variant.map(v => ({ variant: v }))
44
- : [{ variant }];
45
-
46
- const basedOnVariants = useClassname(...variants);
47
-
48
- /**
49
- * Custom styles are applied "on runtime". They are usually controlled via component
50
- * props and can change between component instances. They are more or less the `css`
51
- * prop of `emotion`.
52
- */
53
- const custom = useClassname(styles);
54
-
55
- return [basedOnNormalize, basedOnVariants, custom, classNames].join(' ');
56
- };
@@ -1,126 +0,0 @@
1
- import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
2
-
3
- <Meta title="Guides/How to Write and Use Components" />
4
-
5
- # How to Write and Use Components
6
-
7
- Small guidance for creating components in Marigold.
8
-
9
- ## API
10
-
11
- ### Use the base HTML element
12
-
13
- Create your basic component by using the HTML tagname with its own props. Specify the HTML element you want to render.
14
- The `system` helper infers a forwardRef (and will soon be abolished).
15
-
16
- ```tsx
17
- export const Button = system<ButtonProps, 'button'>(({ ...props }) => {
18
- return <button {...props}>{children}</button>;
19
- });
20
- ```
21
-
22
- ### Add Styling via Classnames
23
-
24
- In order to add styles to your component, you can work with classNames. ClassNames are automatically generated via the `useStyles` hook.
25
- There are three levels of styles to be applied: `useStyles` takes the HTML element type(s) used in the component to normalize the styles according to those HTML elements.
26
- A base normalization is automatically added to this list and always applies in order to have the same defaults cross-browser.
27
- Next, `useStyles` takes a `variant` which is retrieved from the theme (which is given in the `<ThemeProvider>`). Additionally, you can insert custom styles
28
- which are applied on runtime and override normalization and theme styles. Lastly, you can use custom classnames and pass them to your component in the `useStyles` hook.
29
-
30
- ```tsx
31
- const classNames = useStyles(
32
- {
33
- element: ['button'],
34
- variant: `button.${variant}`,
35
- },
36
- className
37
- );
38
- ```
39
-
40
- ### Put it together
41
-
42
- Don't forget imports, defaults and (optional) logic needed for your component as seen in the following example.
43
-
44
- ```tsx
45
- import React from 'react';
46
- import { ThemeProvider, system } from '@marigold/system';
47
- import { render } from '@testing-library/react';
48
-
49
- const theme = {
50
- ...anyTheme,
51
- button: {
52
- outlined: { // variant
53
- border: '1px solid orange',
54
- mx: 2,
55
- },
56
- },
57
- };
58
- // Define custom properties for your component
59
- type ButtonProps = {
60
- kind?: 'basic' | 'other';
61
- size?: 'small' | 'medium' | 'large';
62
- };
63
-
64
- // Specify the HTML element you want to render and merge its properties with the custom component props
65
- const Button = system<ButtonProps, 'button'>(
66
- // Set default values for extra props
67
- ({
68
- kind = 'basic',
69
- size = 'medium',
70
- className
71
- children,
72
- ...props
73
- }) => {
74
- const classNames = useStyles(
75
- // add normalization and variant
76
- {
77
- element: ['button', 'span'],
78
- variant: `button.${variant}`,
79
- },
80
- className
81
- )
82
- // Place logic here like toggle states, calculations, mappings etc.
83
- return (
84
- <button
85
- className={classNames}
86
- {...props}
87
- >
88
- <span
89
- className={useStyles({ // use custom styles only
90
- display: 'inline-flex',
91
- alignItems: 'center',
92
- })}
93
- >
94
- {children}
95
- </span>
96
- </button>
97
- );
98
- }
99
- );
100
- // Use the component; don't forget the imports
101
- render(
102
- <ThemeProvider theme={theme}>
103
- <Button /> // Default Button component instance
104
- </ThemeProvider>
105
- );
106
- ```
107
-
108
- ### Folder Structure
109
-
110
- As we want to keep an organized file structure, we use a script to create new component templates. Navigate to the root folder and use it with `yarn create:component COMPONENTNAME`. The new component
111
- is generated with all files needed and already added to the component exports.
112
-
113
- ```
114
- packages
115
- └─── system
116
- |
117
- └─── components
118
- | index.ts
119
- | theme.ts
120
- └─── src
121
- └─── Button
122
- | index.ts
123
- | Button.tsx
124
- | Button.test.tsx
125
- | Button.stories.mdx
126
- ```