@marigold/system 0.2.0 → 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.
- package/CHANGELOG.md +95 -0
- package/dist/Box.d.ts +14 -0
- package/dist/Global.d.ts +2 -0
- package/dist/SVG.d.ts +6 -0
- package/dist/index.d.ts +6 -4
- package/dist/normalize.d.ts +101 -67
- package/dist/system.cjs.development.js +299 -294
- package/dist/system.cjs.development.js.map +1 -1
- package/dist/system.cjs.production.min.js +1 -1
- package/dist/system.cjs.production.min.js.map +1 -1
- package/dist/system.esm.js +291 -289
- package/dist/system.esm.js.map +1 -1
- package/dist/theme.d.ts +136 -0
- package/dist/types.d.ts +1 -2
- package/dist/useTheme.d.ts +11 -5
- package/dist/variant.d.ts +29 -0
- package/package.json +4 -5
- package/src/Box.test.tsx +308 -0
- package/src/Box.tsx +199 -0
- package/src/Colors.stories.mdx +332 -456
- package/src/Global.test.tsx +57 -0
- package/src/Global.tsx +34 -0
- package/src/SVG.stories.mdx +55 -0
- package/src/SVG.test.tsx +82 -0
- package/src/SVG.tsx +24 -0
- package/src/index.ts +6 -4
- package/src/normalize.test.tsx +9 -36
- package/src/normalize.ts +51 -82
- package/src/theme.ts +157 -0
- package/src/types.ts +0 -2
- package/src/useTheme.test.tsx +22 -14
- package/src/useTheme.tsx +37 -9
- package/src/variant.test.ts +93 -0
- package/src/variant.ts +54 -0
- package/dist/Element.d.ts +0 -8
- package/dist/cache.d.ts +0 -4
- package/dist/reset.d.ts +0 -24
- package/dist/useClassname.d.ts +0 -2
- package/dist/useStyles.d.ts +0 -15
- package/src/Element.test.tsx +0 -203
- package/src/Element.tsx +0 -59
- package/src/cache.ts +0 -4
- package/src/reset.ts +0 -108
- package/src/useClassname.test.tsx +0 -70
- package/src/useClassname.ts +0 -23
- package/src/useStyles.stories.mdx +0 -24
- package/src/useStyles.test.tsx +0 -286
- package/src/useStyles.ts +0 -63
package/src/useTheme.test.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { jsx } from '@emotion/react';
|
|
2
3
|
import { render, screen } from '@testing-library/react';
|
|
3
4
|
import { renderHook } from '@testing-library/react-hooks';
|
|
4
5
|
|
|
@@ -48,22 +49,22 @@ test('transpile style object to css object', () => {
|
|
|
48
49
|
const css = result.current.css;
|
|
49
50
|
|
|
50
51
|
expect(css({ p: 'small' })).toMatchInlineSnapshot(`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
`);
|
|
52
|
+
{
|
|
53
|
+
"padding": 16,
|
|
54
|
+
}
|
|
55
|
+
`);
|
|
55
56
|
expect(css({ color: 'primary', p: 'large' })).toMatchInlineSnapshot(`
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
`);
|
|
57
|
+
{
|
|
58
|
+
"color": "hotpink",
|
|
59
|
+
"padding": 32,
|
|
60
|
+
}
|
|
61
|
+
`);
|
|
61
62
|
expect(css({ variant: 'text.body' })).toMatchInlineSnapshot(`
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
`);
|
|
63
|
+
{
|
|
64
|
+
"color": "#000",
|
|
65
|
+
"fontSize": 14,
|
|
66
|
+
}
|
|
67
|
+
`);
|
|
67
68
|
});
|
|
68
69
|
|
|
69
70
|
test('themes can be cascaded', () => {
|
|
@@ -113,3 +114,10 @@ test('themes can be cascaded', () => {
|
|
|
113
114
|
}"
|
|
114
115
|
`);
|
|
115
116
|
});
|
|
117
|
+
|
|
118
|
+
test('theme is passed down to emotion', () => {
|
|
119
|
+
const css = jest.fn().mockReturnValue({});
|
|
120
|
+
render(<ThemeProvider theme={theme}>{jsx('div', { css })}</ThemeProvider>);
|
|
121
|
+
|
|
122
|
+
expect(css).toHaveBeenCalledWith(theme);
|
|
123
|
+
});
|
package/src/useTheme.tsx
CHANGED
|
@@ -1,22 +1,50 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
ReactNode,
|
|
4
|
+
useCallback,
|
|
5
|
+
useContext,
|
|
6
|
+
} from 'react';
|
|
7
|
+
import { css as transformStyleObject } from '@theme-ui/css';
|
|
8
|
+
import { ThemeProvider as EmotionProvider } from '@emotion/react';
|
|
4
9
|
|
|
10
|
+
import { Theme } from './theme';
|
|
5
11
|
import { StyleObject } from './types';
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
/**
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export const __defaultTheme: Theme = {};
|
|
17
|
+
|
|
18
|
+
const InternalContext = createContext<Theme>(__defaultTheme);
|
|
8
19
|
|
|
9
20
|
export const useTheme = () => {
|
|
10
|
-
const theme = useContext(
|
|
21
|
+
const theme = useContext(InternalContext);
|
|
22
|
+
/**
|
|
23
|
+
* We cast the theme here to `any` since our subset is not
|
|
24
|
+
* compatible with the typings of `theme-ui`, since they
|
|
25
|
+
* also support arrays as scale values, while we don't.
|
|
26
|
+
*/
|
|
11
27
|
const css = useCallback(
|
|
12
|
-
(style: StyleObject) =>
|
|
28
|
+
(style: StyleObject) => transformStyleObject(style)(theme as any),
|
|
13
29
|
[theme]
|
|
14
30
|
);
|
|
15
31
|
return { theme, css };
|
|
16
32
|
};
|
|
17
33
|
|
|
18
|
-
export type ThemeProviderProps = {
|
|
19
|
-
|
|
34
|
+
export type ThemeProviderProps<T extends Theme> = {
|
|
35
|
+
theme: T;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export function ThemeProvider<T extends Theme>({
|
|
20
40
|
theme,
|
|
21
41
|
children,
|
|
22
|
-
}
|
|
42
|
+
}: ThemeProviderProps<T>) {
|
|
43
|
+
return (
|
|
44
|
+
<EmotionProvider theme={theme}>
|
|
45
|
+
<InternalContext.Provider value={theme}>
|
|
46
|
+
{children}
|
|
47
|
+
</InternalContext.Provider>
|
|
48
|
+
</EmotionProvider>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendVariantState,
|
|
3
|
+
conditional,
|
|
4
|
+
ensureArray,
|
|
5
|
+
ensureArrayVariant,
|
|
6
|
+
ensureVariantDefault,
|
|
7
|
+
} from './variant';
|
|
8
|
+
|
|
9
|
+
test('ensure array', () => {
|
|
10
|
+
expect(ensureArray('foo')).toEqual(['foo']);
|
|
11
|
+
expect(ensureArray(['foo'])).toEqual(['foo']);
|
|
12
|
+
expect(ensureArray(['foo', 'bar'])).toEqual(['foo', 'bar']);
|
|
13
|
+
expect(ensureArray(null)).toEqual([]);
|
|
14
|
+
expect(ensureArray(undefined)).toEqual([]);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('ensure variant default', () => {
|
|
18
|
+
expect(ensureVariantDefault('foo.')).toEqual('foo');
|
|
19
|
+
expect(ensureVariantDefault('foo')).toEqual('foo');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('ensure array of variants', () => {
|
|
23
|
+
expect(ensureArrayVariant('foo')).toEqual(['foo']);
|
|
24
|
+
expect(ensureArrayVariant(['foo'])).toEqual(['foo']);
|
|
25
|
+
expect(ensureArrayVariant(['foo', 'bar'])).toEqual(['foo', 'bar']);
|
|
26
|
+
expect(ensureArrayVariant(undefined)).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('append variant state', () => {
|
|
30
|
+
expect(appendVariantState('foo', 'checked')).toEqual('foo.:checked');
|
|
31
|
+
expect(appendVariantState('foo', 'focus')).toEqual('foo.:focus');
|
|
32
|
+
expect(appendVariantState('foo', 'disabled')).toEqual('foo.:disabled');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('conditional variants', () => {
|
|
36
|
+
expect(
|
|
37
|
+
conditional('foo', {
|
|
38
|
+
checked: true,
|
|
39
|
+
})
|
|
40
|
+
).toMatchInlineSnapshot(`
|
|
41
|
+
[
|
|
42
|
+
"foo",
|
|
43
|
+
"foo.:checked",
|
|
44
|
+
]
|
|
45
|
+
`);
|
|
46
|
+
|
|
47
|
+
expect(
|
|
48
|
+
conditional('foo', {
|
|
49
|
+
checked: true,
|
|
50
|
+
focus: true,
|
|
51
|
+
disabled: true,
|
|
52
|
+
})
|
|
53
|
+
).toMatchInlineSnapshot(`
|
|
54
|
+
[
|
|
55
|
+
"foo",
|
|
56
|
+
"foo.:checked",
|
|
57
|
+
"foo.:focus",
|
|
58
|
+
"foo.:disabled",
|
|
59
|
+
]
|
|
60
|
+
`);
|
|
61
|
+
|
|
62
|
+
expect(
|
|
63
|
+
conditional('foo', {
|
|
64
|
+
checked: true,
|
|
65
|
+
focus: false,
|
|
66
|
+
disabled: true,
|
|
67
|
+
})
|
|
68
|
+
).toMatchInlineSnapshot(`
|
|
69
|
+
[
|
|
70
|
+
"foo",
|
|
71
|
+
"foo.:checked",
|
|
72
|
+
"foo.:disabled",
|
|
73
|
+
]
|
|
74
|
+
`);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('disabled is always last state variant', () => {
|
|
78
|
+
const one = conditional('foo', {
|
|
79
|
+
disabled: true,
|
|
80
|
+
checked: true,
|
|
81
|
+
focus: true,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
expect(one[one.length - 1]).toMatchInlineSnapshot(`"foo.:disabled"`);
|
|
85
|
+
|
|
86
|
+
const two = conditional('foo', {
|
|
87
|
+
checked: true,
|
|
88
|
+
disabled: true,
|
|
89
|
+
focus: true,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(two[two.length - 1]).toMatchInlineSnapshot(`"foo.:disabled"`);
|
|
93
|
+
});
|
package/src/variant.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const isNil = (value: any): value is null | undefined =>
|
|
2
|
+
value === null || value === undefined;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Ensures that the `val` is an array. Will return an empty array if `val` is falsy.
|
|
6
|
+
*/
|
|
7
|
+
export const ensureArray = <T>(val?: T | T[]) =>
|
|
8
|
+
isNil(val) ? [] : Array.isArray(val) ? val : [val];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Removes trailing dot from variant, if necessary. This is necessary to support
|
|
12
|
+
* `__default` styles. See https://github.com/system-ui/theme-ui/pull/951
|
|
13
|
+
*/
|
|
14
|
+
export const ensureVariantDefault = (val: string) => val.replace(/\.$/, '');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Ensures that the `variant` is an array and supports the `__default` key.
|
|
18
|
+
*/
|
|
19
|
+
export const ensureArrayVariant = <T extends string>(variant?: T | T[]) =>
|
|
20
|
+
ensureArray(variant).map(ensureVariantDefault);
|
|
21
|
+
|
|
22
|
+
export type State = {
|
|
23
|
+
checked?: boolean;
|
|
24
|
+
focus?: boolean;
|
|
25
|
+
hover?: boolean;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
error?: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Appends given `state` to a `variant`.
|
|
32
|
+
*/
|
|
33
|
+
export const appendVariantState = (variant: string, state: keyof State) => {
|
|
34
|
+
return `${ensureVariantDefault(variant)}.:${state}`;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create a variant array from a `variant` and `state` containing
|
|
39
|
+
* passed states, if they are truthy.
|
|
40
|
+
*/
|
|
41
|
+
export const conditional = (
|
|
42
|
+
variant: string,
|
|
43
|
+
{ disabled = false, ...states }: State
|
|
44
|
+
) => {
|
|
45
|
+
const entries = [...Object.entries(states), ['disabled', disabled]] as [
|
|
46
|
+
keyof State,
|
|
47
|
+
boolean
|
|
48
|
+
][];
|
|
49
|
+
const stateVariants = entries
|
|
50
|
+
.filter(([, val]) => Boolean(val))
|
|
51
|
+
.map(([key]) => appendVariantState(variant, key));
|
|
52
|
+
|
|
53
|
+
return [variant, ...stateVariants];
|
|
54
|
+
};
|
package/dist/Element.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { PolymorphicPropsWithRef, PolymorphicComponentWithRef } from '@marigold/types';
|
|
2
|
-
import { CSSObject } from './types';
|
|
3
|
-
export declare type ElementOwnProps = {
|
|
4
|
-
css?: CSSObject;
|
|
5
|
-
variant?: string | string[];
|
|
6
|
-
};
|
|
7
|
-
export declare type ElementProps = PolymorphicPropsWithRef<ElementOwnProps, 'div'>;
|
|
8
|
-
export declare const Element: PolymorphicComponentWithRef<ElementOwnProps, 'div'>;
|
package/dist/cache.d.ts
DELETED
package/dist/reset.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export declare const reset: {
|
|
2
|
-
readonly article: string;
|
|
3
|
-
readonly aside: string;
|
|
4
|
-
readonly details: string;
|
|
5
|
-
readonly figcaption: string;
|
|
6
|
-
readonly figure: string;
|
|
7
|
-
readonly footer: string;
|
|
8
|
-
readonly header: string;
|
|
9
|
-
readonly hgroup: string;
|
|
10
|
-
readonly menu: string;
|
|
11
|
-
readonly nav: string;
|
|
12
|
-
readonly section: string;
|
|
13
|
-
readonly ul: string;
|
|
14
|
-
readonly ol: string;
|
|
15
|
-
readonly blockquote: string;
|
|
16
|
-
readonly q: string;
|
|
17
|
-
readonly a: string;
|
|
18
|
-
readonly base: string;
|
|
19
|
-
readonly table: string;
|
|
20
|
-
readonly select: string;
|
|
21
|
-
readonly button: string;
|
|
22
|
-
readonly textarea: string;
|
|
23
|
-
readonly input: string;
|
|
24
|
-
};
|
package/dist/useClassname.d.ts
DELETED
package/dist/useStyles.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ElementType } from 'react';
|
|
2
|
-
import { CSSObject } from './types';
|
|
3
|
-
export declare type UseStyleInput = {
|
|
4
|
-
element?: ElementType;
|
|
5
|
-
css?: Omit<CSSObject, 'variant' | 'element'> & {
|
|
6
|
-
variant?: never;
|
|
7
|
-
element?: never;
|
|
8
|
-
};
|
|
9
|
-
variant?: string | string[];
|
|
10
|
-
className?: string;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Hook that can adds base styles, reset for certain elements, variants and custom styles
|
|
14
|
-
*/
|
|
15
|
-
export declare const useStyles: ({ element, css: styles, variant, className, }: UseStyleInput) => string;
|
package/src/Element.test.tsx
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
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
|
-
});
|
package/src/Element.tsx
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
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
DELETED
package/src/reset.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
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;
|