@marigold/system 0.3.3 → 0.4.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.
package/src/Box.test.tsx DELETED
@@ -1,308 +0,0 @@
1
- import React from 'react';
2
- import { render, screen } from '@testing-library/react';
3
- import { ThemeProvider } from './useTheme';
4
- import { Box, StyleProps } from './Box';
5
- import { normalize } from './normalize';
6
-
7
- const theme = {
8
- colors: {
9
- primary: 'black',
10
- secondary: 'hotpink',
11
- black: '#000',
12
- white: '#fff',
13
- blue: 'cornflowerblue',
14
- },
15
- fontSizes: {
16
- body: 16,
17
- small: 12,
18
- large: 24,
19
- },
20
- space: {
21
- none: 0,
22
- xsmall: 2,
23
- small: 4,
24
- medium: 8,
25
- large: 16,
26
- },
27
- sizes: {
28
- none: 0,
29
- small: 8,
30
- medium: 16,
31
- large: 32,
32
- },
33
- borders: { none: 'none', regular: '1px solid black' },
34
- radii: { none: 0, small: 2, medium: 4 },
35
- opacities: {
36
- hidden: 0,
37
- faded: 0.5,
38
- visible: 1,
39
- },
40
- transitions: { none: 'none', regular: '1s opacity' },
41
- shadows: {
42
- none: 'none',
43
- regular: '3px 3px 5px 6px #ccc',
44
- inset: 'inset 0 0 10px #000000',
45
- },
46
- text: {
47
- body: {
48
- fontSize: 'body',
49
- color: 'primary',
50
- bg: 'white',
51
- },
52
- headline1: {
53
- fontSize: 'large',
54
- color: 'secondary',
55
- },
56
- whitespace: {
57
- p: 'medium',
58
- },
59
- },
60
- variant: {
61
- spacing: {
62
- m: 'large',
63
- p: 'large',
64
- },
65
- },
66
- };
67
-
68
- test('renders a <div> by default', () => {
69
- render(<Box>Test</Box>);
70
- const testelem = screen.getByText('Test');
71
-
72
- expect(testelem instanceof HTMLDivElement).toBeTruthy();
73
- });
74
-
75
- test('changes rendered element via "as" prop', () => {
76
- render(<Box as="p">Test</Box>);
77
- const testelem = screen.getByText('Test');
78
-
79
- expect(testelem instanceof HTMLParagraphElement).toBeTruthy();
80
- });
81
-
82
- test('supports custom className', () => {
83
- render(<Box className="my-custom-class">Test</Box>);
84
- const element = screen.getByText('Test');
85
-
86
- expect(element.getAttribute('class')).toMatch('my-custom-class');
87
- });
88
-
89
- test('passes down HTML attributes', () => {
90
- render(
91
- <Box className="my-custom-class" id="element-id" disabled>
92
- Test
93
- </Box>
94
- );
95
- const element = screen.getByText('Test');
96
-
97
- expect(element.getAttribute('id')).toEqual('element-id');
98
- expect(element.getAttribute('disabled')).toMatch('');
99
- });
100
-
101
- test('forwards ref', () => {
102
- const ref = React.createRef<HTMLButtonElement>();
103
- render(
104
- <Box as="button" ref={ref}>
105
- button
106
- </Box>
107
- );
108
-
109
- expect(ref.current instanceof HTMLButtonElement).toBeTruthy();
110
- });
111
-
112
- test('apply normalized styles', () => {
113
- render(<Box>Test</Box>);
114
- const element = screen.getByText('Test');
115
- const { base } = normalize;
116
-
117
- // Smoketest
118
- expect(element).toHaveStyle(`box-sizing: ${base.boxSizing}`);
119
- expect(element).toHaveStyle(`margin: ${base.margin}px`);
120
- expect(element).toHaveStyle(`min-width: ${base.minWidth}`);
121
- });
122
-
123
- test('base normalization is always applied', () => {
124
- render(<Box as="button">Test</Box>);
125
- const element = screen.getByText('Test');
126
- const { base } = normalize;
127
-
128
- expect(element).toHaveStyle(`box-sizing: ${base.boxSizing}`);
129
- expect(element).toHaveStyle(`margin: ${base.margin}px`);
130
- expect(element).toHaveStyle(`min-width: ${base.minWidth}`);
131
- });
132
-
133
- test('apply normalized styles based on element', () => {
134
- render(<Box as="h1">Test</Box>);
135
- const element = screen.getByText('Test');
136
- const { h1 } = normalize;
137
-
138
- expect(element).toHaveStyle(`overflow-wrap: ${h1.overflowWrap}`);
139
- });
140
-
141
- test('accepts default styling via "__baseCSS" prop', () => {
142
- render(<Box __baseCSS={{ color: 'hotpink' }}>Test</Box>);
143
- const element = screen.getByText('Test');
144
-
145
- expect(element).toHaveStyle('color: hotpink');
146
- });
147
-
148
- test('default styling overrides normalization', () => {
149
- render(
150
- <ThemeProvider theme={theme}>
151
- <Box __baseCSS={{ m: 'medium' }}>Test</Box>
152
- </ThemeProvider>
153
- );
154
- const element = screen.getByText('Test');
155
-
156
- expect(element).toHaveStyle(`margin: ${theme.space.medium}px`);
157
- });
158
-
159
- test('variants are applied correctly', () => {
160
- render(
161
- <ThemeProvider theme={theme}>
162
- <Box variant="text.body">Test</Box>
163
- </ThemeProvider>
164
- );
165
- const element = screen.getByText('Test');
166
-
167
- expect(element).toHaveStyle(`font-size: ${theme.fontSizes.body}px`);
168
- expect(element).toHaveStyle(`color: ${theme.colors.primary}`);
169
- });
170
-
171
- test('accept an array of variants', () => {
172
- render(
173
- <ThemeProvider theme={theme}>
174
- <Box as="p" variant={['text.headline1', 'text.whitespace']}>
175
- Test
176
- </Box>
177
- </ThemeProvider>
178
- );
179
- const element = screen.getByText('Test');
180
-
181
- expect(element).toHaveStyle(`font-size: ${theme.fontSizes.large}px`);
182
- expect(element).toHaveStyle(`color: ${theme.colors.secondary}`);
183
- expect(element).toHaveStyle(`padding: ${theme.space.medium}px`);
184
- });
185
-
186
- test('variants override normalization and default styles', () => {
187
- render(
188
- <ThemeProvider theme={theme}>
189
- <Box __baseCSS={{ p: 'small' }} variant="variant.spacing">
190
- Test
191
- </Box>
192
- </ThemeProvider>
193
- );
194
- const element = screen.getByText('Test');
195
-
196
- expect(element).toHaveStyle(`margin: ${theme.space.large}px`);
197
- expect(element).toHaveStyle(`padding: ${theme.space.large}px`);
198
- });
199
-
200
- test.each([
201
- [{ display: 'flex' }, 'display: flex'],
202
- [{ height: 'small' }, 'height: 8px'],
203
- [{ width: 'medium' }, 'width: 16px'],
204
- [{ minWidth: 'small' }, 'min-width: 8px'],
205
- [{ maxWidth: 'large' }, 'max-width: 32px'],
206
- [{ position: 'absolute' }, 'position: absolute'],
207
- [{ top: 'none' }, 'top: 0px'],
208
- [{ bottom: 'xsmall' }, 'bottom: 2px'],
209
- [{ right: 'medium' }, 'right: 8px'],
210
- [{ left: 'small' }, 'left: 4px'],
211
- [{ zIndex: 1000 }, 'z-index: 1000'],
212
- [{ p: 'xsmall' }, 'padding: 2px'],
213
- [{ px: 'xsmall' }, 'padding-left: 2px', 'padding-right: 2px'],
214
- [{ py: 'small' }, 'padding-top: 4px', 'padding-bottom: 4px'],
215
- [{ pt: 'xsmall' }, 'padding-top: 2px'],
216
- [{ pb: 'xsmall' }, 'padding-bottom: 2px'],
217
- [{ pl: 'xsmall' }, 'padding-left: 2px'],
218
- [{ pr: 'xsmall' }, 'padding-right: 2px'],
219
- [{ m: 'xsmall' }, 'margin: 2px'],
220
- [{ mx: 'xsmall' }, 'margin-left: 2px', 'margin-right: 2px'],
221
- [{ my: 'small' }, 'margin-top: 4px', 'margin-bottom: 4px'],
222
- [{ mt: 'xsmall' }, 'margin-top: 2px'],
223
- [{ mb: 'xsmall' }, 'margin-bottom: 2px'],
224
- [{ ml: 'xsmall' }, 'margin-left: 2px'],
225
- [{ mr: 'xsmall' }, 'margin-right: 2px'],
226
- [{ flexDirection: 'column' }, 'flex-direction: column'],
227
- [{ flexWrap: 'wrap' }, 'flex-wrap: wrap'],
228
- [{ flexShrink: 5 }, 'flex-shrink: 5'],
229
- [{ flexGrow: 1 }, 'flex-grow: 1'],
230
- [{ alignItems: 'baseline' }, 'align-items: baseline'],
231
- [{ justifyContent: 'space-between' }, 'justify-content: space-between'],
232
- [{ bg: 'secondary' }, 'background-color: hotpink'],
233
- [{ border: 'regular' }, 'border: 1px solid black'],
234
- [{ borderRadius: 'medium' }, 'border-radius: 4px'],
235
- [{ boxShadow: 'regular' }, 'box-shadow: 3px 3px 5px 6px #ccc'],
236
- [{ opacity: 'faded' }, 'opacity: 0.5'],
237
- [{ overflow: 'hidden' }, 'overflow: hidden'],
238
- [{ transition: 'regular' }, 'transition: 1s opacity'],
239
- ])('supports style prop (%o)', (...args) => {
240
- const props = args.shift() as StyleProps;
241
-
242
- render(
243
- <ThemeProvider theme={theme}>
244
- <Box {...props}>What's in the box!</Box>
245
- </ThemeProvider>
246
- );
247
-
248
- const box = screen.getByText(`What's in the box!`);
249
- args.forEach((style: any) => {
250
- expect(box).toHaveStyle(style);
251
- });
252
- });
253
-
254
- test('style props override normalization, defaults and variants', () => {
255
- render(
256
- <ThemeProvider theme={theme}>
257
- <Box
258
- __baseCSS={{ p: 'small' }}
259
- variant="text.body"
260
- bg="blue"
261
- m="medium"
262
- p="large"
263
- >
264
- Test
265
- </Box>
266
- </ThemeProvider>
267
- );
268
- const element = screen.getByText('Test');
269
-
270
- expect(element).toHaveStyle(`margin: ${theme.space.medium}px`); // overrides normalization
271
- expect(element).toHaveStyle(`padding: ${theme.space.large}px`); // overrides default
272
- expect(element).toHaveStyle(`background: ${theme.colors.blue}`); // overrides variant
273
- });
274
-
275
- test('apply custom styling via css prop', () => {
276
- render(
277
- <ThemeProvider theme={theme}>
278
- <Box css={{ color: 'secondary', padding: '1rem' }}>Test</Box>
279
- </ThemeProvider>
280
- );
281
- const element = screen.getByText('Test');
282
-
283
- expect(element).toHaveStyle(`padding: 1rem`);
284
- expect(element).toHaveStyle(`color: ${theme.colors.secondary}`);
285
- });
286
-
287
- test('custom styling overrides normalization, defaults, variants and style props', () => {
288
- render(
289
- <ThemeProvider theme={theme}>
290
- <Box
291
- __baseCSS={{ p: 'small' }}
292
- variant="text.body"
293
- bg="black"
294
- css={{ fontSize: 'large', m: 'small', p: 'large', bg: 'blue' }}
295
- >
296
- Test
297
- </Box>
298
- </ThemeProvider>
299
- );
300
- const element = screen.getByText('Test');
301
-
302
- expect(element).toHaveStyle(`margin: ${theme.space.small}px`); // overrides normalization
303
- expect(element).toHaveStyle(`padding: ${theme.space.large}px`); // overrides default
304
- expect(element).toHaveStyle(`font-size: ${theme.fontSizes.large}px`); // overrides variant
305
- expect(element).toHaveStyle(`background: ${theme.colors.blue}`); // overrides style prop
306
-
307
- expect(element).not.toHaveStyle(`color: ${theme.colors.primary}px`); // variant part that is not overriden
308
- });
package/src/Box.tsx DELETED
@@ -1,199 +0,0 @@
1
- import { jsx, Theme } from '@emotion/react';
2
- import { css as transformStyleObject } from '@theme-ui/css';
3
- import { forwardRef } from 'react';
4
- import {
5
- PolymorphicPropsWithRef,
6
- PolymorphicComponentWithRef,
7
- } from '@marigold/types';
8
-
9
- import { getNormalizedStyles } from './normalize';
10
- import { CSSObject } from './types';
11
- import { ensureArrayVariant } from './variant';
12
-
13
- export type StyleProps = Pick<
14
- CSSObject,
15
- | 'display'
16
- | 'height'
17
- | 'width'
18
- | 'minWidth'
19
- | 'maxWidth'
20
- | 'position'
21
- | 'top'
22
- | 'bottom'
23
- | 'right'
24
- | 'left'
25
- | 'zIndex'
26
- | 'p'
27
- | 'px'
28
- | 'py'
29
- | 'pt'
30
- | 'pb'
31
- | 'pl'
32
- | 'pr'
33
- | 'm'
34
- | 'mx'
35
- | 'my'
36
- | 'mt'
37
- | 'mb'
38
- | 'ml'
39
- | 'mr'
40
- | 'flexDirection'
41
- | 'flexWrap'
42
- | 'flexShrink'
43
- | 'flexGrow'
44
- | 'alignItems'
45
- | 'justifyContent'
46
- | 'bg'
47
- | 'border'
48
- | 'borderRadius'
49
- | 'boxShadow'
50
- | 'opacity'
51
- | 'overflow'
52
- | 'transition'
53
- >;
54
-
55
- export type BoxOwnProps = {
56
- css?: CSSObject;
57
- variant?: string | string[];
58
- /**
59
- * Use to set base styles for the component
60
- * @internal Used to set default styles for Marigold components
61
- */
62
- __baseCSS?: CSSObject;
63
- } & StyleProps;
64
-
65
- export type BoxProps = PolymorphicPropsWithRef<BoxOwnProps, 'div'>;
66
-
67
- /**
68
- * Check if there is any falsy value or empty object
69
- */
70
- const isNotEmpty = (val: any) =>
71
- !(val && Object.keys(val).length === 0 && val.constructor === Object);
72
-
73
- type CreateStyleProps = {
74
- as?: BoxProps['as'];
75
- __baseCSS?: BoxOwnProps['__baseCSS'];
76
- variant?: BoxOwnProps['variant'];
77
- css?: BoxOwnProps['css'];
78
- styles?: StyleProps;
79
- };
80
-
81
- const createThemedStyle =
82
- ({ as, __baseCSS, variant, styles, css }: CreateStyleProps) =>
83
- (theme: Theme) => {
84
- return [
85
- getNormalizedStyles(as),
86
- transformStyleObject(__baseCSS)(theme),
87
- ...ensureArrayVariant(variant).map(v =>
88
- transformStyleObject({ variant: v })(theme)
89
- ),
90
- transformStyleObject(styles)(theme),
91
- transformStyleObject(css)(theme),
92
- ].filter(isNotEmpty);
93
- };
94
-
95
- export const Box: PolymorphicComponentWithRef<BoxOwnProps, 'div'> = forwardRef(
96
- (
97
- {
98
- as = 'div',
99
- children,
100
- __baseCSS,
101
- variant,
102
- css = {},
103
- display,
104
- height,
105
- width,
106
- minWidth,
107
- maxWidth,
108
- position,
109
- top,
110
- bottom,
111
- right,
112
- left,
113
- zIndex,
114
- p,
115
- px,
116
- py,
117
- pt,
118
- pb,
119
- pl,
120
- pr,
121
- m,
122
- mx,
123
- my,
124
- mt,
125
- mb,
126
- ml,
127
- mr,
128
- flexDirection,
129
- flexWrap,
130
- flexShrink,
131
- flexGrow,
132
- alignItems,
133
- justifyContent,
134
- bg,
135
- border,
136
- borderRadius,
137
- boxShadow,
138
- opacity,
139
- overflow,
140
- transition,
141
- ...props
142
- },
143
- ref
144
- ) =>
145
- jsx(
146
- as,
147
- {
148
- ...props,
149
- css: createThemedStyle({
150
- as,
151
- __baseCSS,
152
- variant,
153
- css,
154
- styles: {
155
- display,
156
- height,
157
- width,
158
- minWidth,
159
- maxWidth,
160
- position,
161
- top,
162
- bottom,
163
- right,
164
- left,
165
- zIndex,
166
- p,
167
- px,
168
- py,
169
- pt,
170
- pb,
171
- pl,
172
- pr,
173
- m,
174
- mx,
175
- my,
176
- mt,
177
- mb,
178
- ml,
179
- mr,
180
- flexDirection,
181
- flexWrap,
182
- flexShrink,
183
- flexGrow,
184
- alignItems,
185
- justifyContent,
186
- bg,
187
- border,
188
- borderRadius,
189
- boxShadow,
190
- opacity,
191
- overflow,
192
- transition,
193
- },
194
- }),
195
- ref,
196
- },
197
- children
198
- )
199
- );
@@ -1,57 +0,0 @@
1
- import React from 'react';
2
- import { render } from '@testing-library/react';
3
- import { ThemeProvider } from './useTheme';
4
-
5
- import { Global } from './Global';
6
-
7
- test('applies normlaization to html and body', () => {
8
- const root = render(<Global />);
9
-
10
- const html = window.getComputedStyle(root.baseElement.parentElement!);
11
- expect(html.height).toBe('100%');
12
- const body = window.getComputedStyle(root.baseElement);
13
- expect(body.height).toBe('100%');
14
- expect(body.lineHeight).toBe('1.5');
15
- });
16
-
17
- test('applies global styles for body and html based on `theme.root`', () => {
18
- const theme = {
19
- colors: {
20
- background: '#fff',
21
- },
22
- fonts: {
23
- body: 'Inter',
24
- },
25
- lineHeights: {
26
- body: 2.5,
27
- },
28
- fontWeights: {
29
- body: 500,
30
- html: 700,
31
- },
32
- root: {
33
- body: {
34
- fontFamily: 'body',
35
- lineHeight: 'body',
36
- fontWeight: 'body',
37
- },
38
- html: {
39
- bg: 'background',
40
- },
41
- },
42
- };
43
-
44
- const root = render(
45
- <ThemeProvider theme={theme}>
46
- <Global />
47
- </ThemeProvider>
48
- );
49
-
50
- const html = root.baseElement.parentElement;
51
- expect(html).toHaveStyle(`background: ${theme.colors.background}`);
52
-
53
- const body = root.baseElement;
54
- expect(body).toHaveStyle(`font-family: ${theme.fonts.body}`);
55
- expect(body).toHaveStyle(`line-height: ${theme.lineHeights.body}`);
56
- expect(body).toHaveStyle(`font-weight: ${theme.fontWeights.body}`);
57
- });
package/src/Global.tsx DELETED
@@ -1,34 +0,0 @@
1
- import React from 'react';
2
- import { Global as EmotionGlobal } from '@emotion/react';
3
- import { useTheme } from './useTheme';
4
-
5
- /**
6
- * CSS snippet and idea from:
7
- * https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/
8
- */
9
- const reduceMotionStyles = {
10
- '@media screen and (prefers-reduced-motion: reduce), (update: slow)': {
11
- '*': {
12
- animationDuration: '0.001ms !important',
13
- animationIterationCount: '1 !important',
14
- transitionDuration: '0.001ms !important',
15
- },
16
- },
17
- };
18
-
19
- export const Global = () => {
20
- const { css } = useTheme();
21
- const styles = css({
22
- html: {
23
- height: '100%',
24
- variant: 'root.html',
25
- },
26
- body: {
27
- height: '100%',
28
- lineHeight: 1.5,
29
- WebkitFontSmoothing: 'antialiased',
30
- variant: 'root.body',
31
- },
32
- });
33
- return <EmotionGlobal styles={{ reduceMotionStyles, ...styles }} />;
34
- };
@@ -1,48 +0,0 @@
1
- import React from 'react';
2
- import type { Meta, ComponentStory } from '@storybook/react';
3
- import { SVG } from './SVG';
4
-
5
- export default {
6
- title: 'Components/SVG',
7
- argTypes: {
8
- variant: {
9
- control: {
10
- type: 'text',
11
- },
12
- table: {
13
- defaultValue: {
14
- summary: 'icon',
15
- },
16
- },
17
- },
18
- size: {
19
- control: {
20
- type: 'range',
21
- min: 0,
22
- max: 96,
23
- step: 2,
24
- },
25
- table: {
26
- defaultValue: {
27
- summary: 24,
28
- },
29
- },
30
- },
31
- fill: {
32
- control: {
33
- type: 'text',
34
- },
35
- table: {
36
- defaultValue: {
37
- summary: 'currentColor',
38
- },
39
- },
40
- },
41
- },
42
- } as Meta;
43
-
44
- export const Basic: ComponentStory<typeof SVG> = args => (
45
- <SVG {...args}>
46
- <path d="M9.9 20.113V13.8415H14.1V20.113H19.35V11.751H22.5L12 2.34375L1.5 11.751H4.65V20.113H9.9Z" />
47
- </SVG>
48
- );