@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.
Files changed (48) 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 +6 -4
  6. package/dist/normalize.d.ts +101 -67
  7. package/dist/system.cjs.development.js +299 -294
  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 +291 -289
  12. package/dist/system.esm.js.map +1 -1
  13. package/dist/theme.d.ts +136 -0
  14. package/dist/types.d.ts +1 -2
  15. package/dist/useTheme.d.ts +11 -5
  16. package/dist/variant.d.ts +29 -0
  17. package/package.json +4 -5
  18. package/src/Box.test.tsx +308 -0
  19. package/src/Box.tsx +199 -0
  20. package/src/Colors.stories.mdx +332 -456
  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/index.ts +6 -4
  27. package/src/normalize.test.tsx +9 -36
  28. package/src/normalize.ts +51 -82
  29. package/src/theme.ts +157 -0
  30. package/src/types.ts +0 -2
  31. package/src/useTheme.test.tsx +22 -14
  32. package/src/useTheme.tsx +37 -9
  33. package/src/variant.test.ts +93 -0
  34. package/src/variant.ts +54 -0
  35. package/dist/Element.d.ts +0 -8
  36. package/dist/cache.d.ts +0 -4
  37. package/dist/reset.d.ts +0 -24
  38. package/dist/useClassname.d.ts +0 -2
  39. package/dist/useStyles.d.ts +0 -15
  40. package/src/Element.test.tsx +0 -203
  41. package/src/Element.tsx +0 -59
  42. package/src/cache.ts +0 -4
  43. package/src/reset.ts +0 -108
  44. package/src/useClassname.test.tsx +0 -70
  45. package/src/useClassname.ts +0 -23
  46. package/src/useStyles.stories.mdx +0 -24
  47. package/src/useStyles.test.tsx +0 -286
  48. package/src/useStyles.ts +0 -63
@@ -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
- Object {
52
- "padding": 16,
53
- }
54
- `);
52
+ {
53
+ "padding": 16,
54
+ }
55
+ `);
55
56
  expect(css({ color: 'primary', p: 'large' })).toMatchInlineSnapshot(`
56
- Object {
57
- "color": "hotpink",
58
- "padding": 32,
59
- }
60
- `);
57
+ {
58
+ "color": "hotpink",
59
+ "padding": 32,
60
+ }
61
+ `);
61
62
  expect(css({ variant: 'text.body' })).toMatchInlineSnapshot(`
62
- Object {
63
- "color": "#000",
64
- "fontSize": 14,
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, { createContext, useCallback, useContext } from 'react';
2
- import { css as themeUi } from '@theme-ui/css';
3
- import { Theme } from '@marigold/system';
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
- const Context = createContext<Theme>({});
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(Context);
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) => themeUi(style)(theme),
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 = { theme: any };
19
- export const ThemeProvider: React.FC<ThemeProviderProps> = ({
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
- }) => <Context.Provider value={theme}>{children}</Context.Provider>;
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
@@ -1,4 +0,0 @@
1
- /**
2
- * Expose cache from emotion so we can use the same cache when doing SSR.
3
- */
4
- export { cache } from '@emotion/css';
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
- };
@@ -1,2 +0,0 @@
1
- import { StyleObject } from './types';
2
- export declare const useClassname: (...styles: StyleObject[]) => string;
@@ -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;
@@ -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
@@ -1,4 +0,0 @@
1
- /**
2
- * Expose cache from emotion so we can use the same cache when doing SSR.
3
- */
4
- export { cache } from '@emotion/css';
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;