@marigold/components 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 (194) hide show
  1. package/dist/ActionGroup/ActionGroup.d.ts +9 -0
  2. package/dist/ActionGroup/index.d.ts +1 -0
  3. package/dist/Alert/Alert.d.ts +20 -2
  4. package/dist/Badge/Badge.d.ts +8 -0
  5. package/dist/Badge/index.d.ts +1 -0
  6. package/dist/Box/Box.d.ts +47 -0
  7. package/dist/Box/index.d.ts +1 -0
  8. package/dist/Button/Button.d.ts +4 -3
  9. package/dist/Card/Card.d.ts +9 -0
  10. package/dist/Card/index.d.ts +1 -0
  11. package/dist/Checkbox/Checkbox.d.ts +14 -2
  12. package/dist/Checkbox/CheckboxIcons.d.ts +9 -0
  13. package/dist/Column/Column.d.ts +8 -0
  14. package/dist/Column/index.d.ts +1 -0
  15. package/dist/Columns/Columns.d.ts +10 -0
  16. package/dist/Columns/index.d.ts +1 -0
  17. package/dist/Container/Container.d.ts +6 -0
  18. package/dist/Container/index.d.ts +1 -0
  19. package/dist/Dialog/Dialog.d.ts +14 -0
  20. package/dist/Dialog/ModalDialog.d.ts +5 -0
  21. package/dist/Dialog/index.d.ts +1 -0
  22. package/dist/Divider/Divider.d.ts +7 -0
  23. package/dist/Divider/index.d.ts +1 -0
  24. package/dist/Field/Field.d.ts +11 -0
  25. package/dist/Field/index.d.ts +1 -0
  26. package/dist/Heading/Heading.d.ts +7 -5
  27. package/dist/Hidden/Hidden.d.ts +5 -0
  28. package/dist/Hidden/index.d.ts +1 -0
  29. package/dist/Image/Image.d.ts +7 -0
  30. package/dist/Image/index.d.ts +1 -0
  31. package/dist/Input/Input.d.ts +6 -0
  32. package/dist/Input/index.d.ts +1 -0
  33. package/dist/Label/Label.d.ts +8 -5
  34. package/dist/Link/Link.d.ts +7 -3
  35. package/dist/Menu/Menu.d.ts +12 -0
  36. package/dist/Menu/index.d.ts +1 -0
  37. package/dist/MenuItem/MenuItem.d.ts +7 -0
  38. package/dist/MenuItem/index.d.ts +1 -0
  39. package/dist/Message/Message.d.ts +7 -0
  40. package/dist/Message/index.d.ts +1 -0
  41. package/dist/Provider/MarigoldProvider.d.ts +3 -0
  42. package/dist/Provider/index.d.ts +3 -0
  43. package/dist/Radio/Radio.d.ts +14 -2
  44. package/dist/Radio/RadioIcons.d.ts +9 -0
  45. package/dist/Select/ListBox.d.ts +8 -0
  46. package/dist/Select/ListBoxSection.d.ts +8 -0
  47. package/dist/Select/Option.d.ts +8 -0
  48. package/dist/Select/Popover.d.ts +9 -0
  49. package/dist/Select/Select.d.ts +13 -3
  50. package/dist/Slider/Slider.d.ts +6 -3
  51. package/dist/Stack/Stack.d.ts +7 -0
  52. package/dist/Stack/index.d.ts +1 -0
  53. package/dist/Text/Text.d.ts +12 -3
  54. package/dist/Textarea/Textarea.d.ts +11 -3
  55. package/dist/ValidationMessage/ValidationMessage.d.ts +6 -0
  56. package/dist/ValidationMessage/index.d.ts +1 -0
  57. package/dist/components.cjs.development.js +1308 -195
  58. package/dist/components.cjs.development.js.map +1 -1
  59. package/dist/components.cjs.production.min.js +1 -1
  60. package/dist/components.cjs.production.min.js.map +1 -1
  61. package/dist/components.esm.js +1267 -185
  62. package/dist/components.esm.js.map +1 -1
  63. package/dist/index.d.ts +21 -4
  64. package/dist/theme.d.ts +24 -4
  65. package/package.json +24 -4
  66. package/src/ActionGroup/ActionGroup.stories.mdx +62 -0
  67. package/src/ActionGroup/ActionGroup.test.tsx +83 -0
  68. package/src/ActionGroup/ActionGroup.tsx +43 -0
  69. package/src/ActionGroup/index.ts +1 -0
  70. package/src/Alert/Alert.stories.mdx +30 -42
  71. package/src/Alert/Alert.test.tsx +37 -22
  72. package/src/Alert/Alert.tsx +31 -21
  73. package/src/Badge/Badge.stories.mdx +57 -0
  74. package/src/Badge/Badge.test.tsx +61 -0
  75. package/src/Badge/Badge.tsx +25 -0
  76. package/src/Badge/index.ts +1 -0
  77. package/src/Box/Box.stories.mdx +334 -0
  78. package/src/Box/Box.test.tsx +133 -0
  79. package/src/Box/Box.tsx +165 -0
  80. package/src/Box/index.ts +1 -0
  81. package/src/Button/Button.stories.mdx +58 -134
  82. package/src/Button/Button.test.tsx +65 -23
  83. package/src/Button/Button.tsx +48 -14
  84. package/src/Card/Card.stories.mdx +49 -0
  85. package/src/Card/Card.test.tsx +66 -0
  86. package/src/Card/Card.tsx +36 -0
  87. package/src/Card/index.ts +1 -0
  88. package/src/Checkbox/Checkbox.stories.mdx +79 -101
  89. package/src/Checkbox/Checkbox.test.tsx +73 -32
  90. package/src/Checkbox/Checkbox.tsx +114 -35
  91. package/src/Checkbox/CheckboxIcons.tsx +49 -0
  92. package/src/Column/Column.stories.mdx +49 -0
  93. package/src/Column/Column.test.tsx +32 -0
  94. package/src/Column/Column.tsx +27 -0
  95. package/src/Column/index.ts +1 -0
  96. package/src/Columns/Columns.stories.mdx +65 -0
  97. package/src/Columns/Columns.test.tsx +102 -0
  98. package/src/Columns/Columns.tsx +69 -0
  99. package/src/Columns/index.ts +1 -0
  100. package/src/Container/Container.stories.mdx +19 -0
  101. package/src/Container/Container.test.tsx +26 -0
  102. package/src/Container/Container.tsx +13 -0
  103. package/src/Container/index.ts +1 -0
  104. package/src/Dialog/Dialog.stories.mdx +73 -0
  105. package/src/Dialog/Dialog.test.tsx +87 -0
  106. package/src/Dialog/Dialog.tsx +84 -0
  107. package/src/Dialog/ModalDialog.tsx +47 -0
  108. package/src/Dialog/index.ts +1 -0
  109. package/src/Divider/Divider.stories.mdx +37 -0
  110. package/src/Divider/Divider.test.tsx +63 -0
  111. package/src/Divider/Divider.tsx +13 -0
  112. package/src/Divider/index.ts +1 -0
  113. package/src/Field/Field.stories.mdx +97 -0
  114. package/src/Field/Field.test.tsx +80 -0
  115. package/src/Field/Field.tsx +54 -0
  116. package/src/Field/index.ts +1 -0
  117. package/src/Heading/Heading.stories.mdx +36 -76
  118. package/src/Heading/Heading.test.tsx +31 -17
  119. package/src/Heading/Heading.tsx +15 -12
  120. package/src/Hidden/Hidden.stories.mdx +39 -0
  121. package/src/Hidden/Hidden.test.tsx +24 -0
  122. package/src/Hidden/Hidden.tsx +16 -0
  123. package/src/Hidden/index.ts +1 -0
  124. package/src/Image/Image.stories.mdx +36 -0
  125. package/src/Image/Image.test.tsx +70 -0
  126. package/src/Image/Image.tsx +13 -0
  127. package/src/Image/index.ts +1 -0
  128. package/src/Input/Input.stories.mdx +61 -0
  129. package/src/Input/Input.test.tsx +70 -0
  130. package/src/Input/Input.tsx +13 -0
  131. package/src/Input/index.ts +1 -0
  132. package/src/Label/Label.stories.mdx +50 -34
  133. package/src/Label/Label.test.tsx +45 -16
  134. package/src/Label/Label.tsx +26 -17
  135. package/src/Link/Link.stories.mdx +40 -31
  136. package/src/Link/Link.test.tsx +53 -28
  137. package/src/Link/Link.tsx +32 -14
  138. package/src/Menu/Menu.stories.mdx +81 -0
  139. package/src/Menu/Menu.test.tsx +79 -0
  140. package/src/Menu/Menu.tsx +41 -0
  141. package/src/Menu/index.ts +1 -0
  142. package/src/MenuItem/MenuItem.stories.mdx +37 -0
  143. package/src/MenuItem/MenuItem.test.tsx +63 -0
  144. package/src/MenuItem/MenuItem.tsx +23 -0
  145. package/src/MenuItem/index.ts +1 -0
  146. package/src/Message/Message.stories.mdx +44 -0
  147. package/src/Message/Message.test.tsx +87 -0
  148. package/src/Message/Message.tsx +43 -0
  149. package/src/Message/index.ts +1 -0
  150. package/src/Provider/MarigoldProvider.test.tsx +126 -0
  151. package/src/Provider/MarigoldProvider.tsx +29 -0
  152. package/src/Provider/index.ts +3 -0
  153. package/src/Radio/Radio.stories.mdx +80 -83
  154. package/src/Radio/Radio.test.tsx +63 -22
  155. package/src/Radio/Radio.tsx +110 -35
  156. package/src/Radio/RadioIcons.tsx +39 -0
  157. package/src/Select/ListBox.tsx +39 -0
  158. package/src/Select/ListBoxSection.tsx +40 -0
  159. package/src/Select/Option.tsx +48 -0
  160. package/src/Select/Popover.tsx +50 -0
  161. package/src/Select/Select.stories.mdx +72 -37
  162. package/src/Select/Select.test.tsx +271 -28
  163. package/src/Select/Select.tsx +158 -23
  164. package/src/Slider/Slider.stories.mdx +26 -54
  165. package/src/Slider/Slider.test.tsx +13 -13
  166. package/src/Slider/Slider.tsx +20 -18
  167. package/src/Stack/Stack.stories.mdx +51 -0
  168. package/src/Stack/Stack.test.tsx +129 -0
  169. package/src/Stack/Stack.tsx +39 -0
  170. package/src/Stack/index.ts +1 -0
  171. package/src/Text/Text.stories.mdx +53 -47
  172. package/src/Text/Text.test.tsx +55 -15
  173. package/src/Text/Text.tsx +44 -10
  174. package/src/Textarea/Textarea.stories.mdx +68 -21
  175. package/src/Textarea/Textarea.test.tsx +47 -16
  176. package/src/Textarea/Textarea.tsx +46 -14
  177. package/src/ValidationMessage/ValidationMessage.stories.mdx +36 -0
  178. package/src/ValidationMessage/ValidationMessage.test.tsx +63 -0
  179. package/src/ValidationMessage/ValidationMessage.tsx +28 -0
  180. package/src/ValidationMessage/index.ts +1 -0
  181. package/src/index.ts +22 -4
  182. package/src/theme.ts +24 -4
  183. package/dist/Svg/Svg.d.ts +0 -5
  184. package/dist/Svg/index.d.ts +0 -1
  185. package/dist/TextInput/TextInput.d.ts +0 -3
  186. package/dist/TextInput/index.d.ts +0 -1
  187. package/src/Svg/Svg.stories.mdx +0 -47
  188. package/src/Svg/Svg.test.tsx +0 -58
  189. package/src/Svg/Svg.tsx +0 -25
  190. package/src/Svg/index.ts +0 -1
  191. package/src/TextInput/TextInput.stories.mdx +0 -37
  192. package/src/TextInput/TextInput.test.tsx +0 -71
  193. package/src/TextInput/TextInput.tsx +0 -21
  194. package/src/TextInput/index.ts +0 -1
@@ -0,0 +1,84 @@
1
+ import React, { RefObject } from 'react';
2
+ import { ComponentProps } from '@marigold/types';
3
+ import { useOverlayTriggerState } from '@react-stately/overlays';
4
+ import { OverlayContainer } from '@react-aria/overlays';
5
+ import { useButton } from '@react-aria/button';
6
+ import { Close } from '@marigold/icons';
7
+
8
+ import { Box } from '../Box';
9
+ import { Button } from '../Button';
10
+ import { Heading } from '../Heading';
11
+
12
+ import { ModalDialog } from './ModalDialog';
13
+
14
+ export type DialogProps = {
15
+ isOpen: boolean;
16
+ close: ComponentProps<typeof Button>['onClick'];
17
+ title?: string;
18
+ } & ComponentProps<'div'>;
19
+
20
+ export const Dialog: React.FC<DialogProps> = ({
21
+ children,
22
+ title,
23
+ className,
24
+ isOpen,
25
+ close,
26
+ ...props
27
+ }) => {
28
+ const closeButtonRef = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
29
+
30
+ // useButton ensures that focus management is handled correctly,
31
+ // across all browsers. Focus is restored to the button once the
32
+ // dialog closes.
33
+ const { buttonProps: closeButtonProps } = useButton(
34
+ {
35
+ onPress: () => close(),
36
+ },
37
+ closeButtonRef
38
+ );
39
+
40
+ return (
41
+ <OverlayContainer>
42
+ <ModalDialog isOpen={isOpen} onClose={close} isDismissable>
43
+ <Box variant="dialog.wrapper" className={className} {...props}>
44
+ <Box variant="dialog.body">
45
+ {title && (
46
+ <Heading as="h4" variant="h4">
47
+ {title}
48
+ </Heading>
49
+ )}
50
+ {children}
51
+ </Box>
52
+ <Box variant="dialog.onClose">
53
+ <Button
54
+ variant="close"
55
+ size="xsmall"
56
+ {...closeButtonProps}
57
+ ref={closeButtonRef}
58
+ >
59
+ <Close size={16} />
60
+ </Button>
61
+ </Box>
62
+ </Box>
63
+ </ModalDialog>
64
+ </OverlayContainer>
65
+ );
66
+ };
67
+
68
+ // use this hook to get the overlayTriggerState and openButton props for using the dialog component
69
+ export const useDialogButtonProps = () => {
70
+ const state = useOverlayTriggerState({});
71
+ const openButtonRef = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
72
+ const { buttonProps: openButtonProps } = useButton(
73
+ {
74
+ onPress: () => state.open(),
75
+ },
76
+ openButtonRef
77
+ );
78
+
79
+ return {
80
+ state,
81
+ openButtonProps,
82
+ openButtonRef,
83
+ };
84
+ };
@@ -0,0 +1,47 @@
1
+ import React, { RefObject } from 'react';
2
+ import {
3
+ useOverlay,
4
+ usePreventScroll,
5
+ useModal,
6
+ OverlayProps,
7
+ } from '@react-aria/overlays';
8
+ import { useDialog } from '@react-aria/dialog';
9
+ import { FocusScope } from '@react-aria/focus';
10
+ import { AriaDialogProps } from '@react-types/dialog';
11
+
12
+ import { Box } from '../Box';
13
+
14
+ export type ModalDialogProps = OverlayProps & AriaDialogProps;
15
+
16
+ export const ModalDialog: React.FC<ModalDialogProps> = ({
17
+ children,
18
+ ...props
19
+ }) => {
20
+ // Handle interacting outside the dialog and pressing
21
+ // the Escape key to close the modal.
22
+ const ref = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
23
+ const { overlayProps, underlayProps } = useOverlay(props, ref);
24
+
25
+ // Prevent scrolling while the modal is open, and hide content
26
+ // outside the modal from screen readers.
27
+ usePreventScroll();
28
+
29
+ const { modalProps } = useModal();
30
+ const { dialogProps } = useDialog(props, ref);
31
+
32
+ return (
33
+ <Box variant="dialog.modalWrapper" {...underlayProps}>
34
+ <FocusScope contain restoreFocus autoFocus>
35
+ <Box
36
+ {...overlayProps}
37
+ {...dialogProps}
38
+ {...modalProps}
39
+ ref={ref}
40
+ variant="dialog.modalBody"
41
+ >
42
+ {children}
43
+ </Box>
44
+ </FocusScope>
45
+ </Box>
46
+ );
47
+ };
@@ -0,0 +1 @@
1
+ export * from './Dialog';
@@ -0,0 +1,37 @@
1
+ import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
2
+ import { Divider } from './Divider';
3
+ import { Text } from '../Text';
4
+
5
+ <Meta
6
+ title="Components/Divider"
7
+ argTypes={{
8
+ variant: {
9
+ control: {
10
+ type: 'select',
11
+ },
12
+ options: ['regular', 'bold'],
13
+ description: 'Thick or thin line',
14
+ table: {
15
+ defaultValue: {
16
+ summary: 'regular',
17
+ },
18
+ },
19
+ },
20
+ }}
21
+ />
22
+
23
+ # Divider
24
+
25
+ export const Template = args => (
26
+ <div>
27
+ <Text>Above</Text>
28
+ <Divider {...args} />
29
+ <Text>Below</Text>
30
+ </div>
31
+ );
32
+
33
+ <Canvas>
34
+ <Story name="Default">{Template.bind({})}</Story>
35
+ </Canvas>
36
+
37
+ <ArgsTable story="Default" />
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { ThemeProvider } from '@marigold/system';
4
+ import { Divider } from './Divider';
5
+
6
+ const theme = {
7
+ divider: {
8
+ regular: {
9
+ border: 0,
10
+ borderBottom: '1px solid',
11
+ margin: '2px',
12
+ },
13
+ bold: {
14
+ border: 0,
15
+ borderBottom: '2px solid',
16
+ margin: '2px',
17
+ },
18
+ },
19
+ };
20
+
21
+ test('supports default variant and themeSection', () => {
22
+ render(
23
+ <ThemeProvider theme={theme}>
24
+ <Divider title="divider" />
25
+ </ThemeProvider>
26
+ );
27
+ const divider = screen.getByTitle(/divider/);
28
+
29
+ expect(divider).toHaveStyle(`borderBottom: 1px solid`);
30
+ });
31
+
32
+ test('accepts other variant than default', () => {
33
+ render(
34
+ <ThemeProvider theme={theme}>
35
+ <Divider variant="bold" title="divider" />
36
+ </ThemeProvider>
37
+ );
38
+ const divider = screen.getByTitle(/divider/);
39
+
40
+ expect(divider).toHaveStyle(`borderBottom: 2px solid`);
41
+ });
42
+
43
+ test('renders correct HTML element', () => {
44
+ render(
45
+ <ThemeProvider theme={theme}>
46
+ <Divider title="divider" />
47
+ </ThemeProvider>
48
+ );
49
+ const divider = screen.getByTitle(/divider/);
50
+
51
+ expect(divider instanceof HTMLHRElement).toBeTruthy();
52
+ });
53
+
54
+ test('accepts custom styles prop className', () => {
55
+ render(
56
+ <ThemeProvider theme={theme}>
57
+ <Divider className="custom-class-name" title="divider" />
58
+ </ThemeProvider>
59
+ );
60
+ const divider = screen.getByTitle(/divider/);
61
+
62
+ expect(divider.className).toMatch('custom-class-name');
63
+ });
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { Box } from '../Box';
3
+
4
+ export type DividerProps = {
5
+ className?: string;
6
+ variant?: string;
7
+ title?: string; // Should only be used for testing.
8
+ };
9
+
10
+ export const Divider: React.FC<DividerProps> = ({
11
+ variant = 'regular',
12
+ ...props
13
+ }) => <Box {...props} as="hr" variant={`divider.${variant}`} />;
@@ -0,0 +1 @@
1
+ export * from './Divider';
@@ -0,0 +1,97 @@
1
+ import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
2
+ import { Field } from './Field';
3
+
4
+ <Meta
5
+ title="Components/Field"
6
+ argTypes={{
7
+ htmlFor: {
8
+ control: {
9
+ type: 'text',
10
+ },
11
+ type: { required: true },
12
+ },
13
+ label: {
14
+ control: {
15
+ type: 'text',
16
+ },
17
+ type: { required: true },
18
+ },
19
+ error: {
20
+ control: {
21
+ type: 'boolean',
22
+ },
23
+ description: 'Error',
24
+ table: {
25
+ defaultValue: {
26
+ summary: false,
27
+ },
28
+ },
29
+ },
30
+ errorMessage: {
31
+ control: {
32
+ type: 'text',
33
+ },
34
+ description: 'Error Message',
35
+ },
36
+ required: {
37
+ control: {
38
+ type: 'boolean',
39
+ },
40
+ options: [true, false],
41
+ table: {
42
+ defaultValue: {
43
+ summary: false,
44
+ },
45
+ },
46
+ },
47
+ disabled: {
48
+ control: {
49
+ type: 'boolean',
50
+ },
51
+ options: [true, false],
52
+ table: {
53
+ defaultValue: {
54
+ summary: false,
55
+ },
56
+ },
57
+ },
58
+ type: {
59
+ control: {
60
+ type: 'select',
61
+ },
62
+ options: [
63
+ 'date',
64
+ 'datetime-local',
65
+ 'email',
66
+ 'month',
67
+ 'number',
68
+ 'password',
69
+ 'search',
70
+ 'tel',
71
+ 'text',
72
+ 'time',
73
+ 'time',
74
+ 'url',
75
+ 'week',
76
+ ],
77
+ type: { required: true },
78
+ table: {
79
+ defaultValue: {
80
+ summary: 'text',
81
+ },
82
+ },
83
+ },
84
+ }}
85
+ />
86
+
87
+ # Field
88
+
89
+ export const Template = args => (
90
+ <Field htmlFor="id" label="A label" type="text" {...args} />
91
+ );
92
+
93
+ <Canvas>
94
+ <Story name="Default">{Template.bind({})}</Story>
95
+ </Canvas>
96
+
97
+ <ArgsTable story="Default" />
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { ThemeProvider } from '@marigold/system';
4
+ import { Field } from './Field';
5
+
6
+ const theme = {
7
+ field: {
8
+ default: {
9
+ padding: '4px',
10
+ },
11
+ inputField: {
12
+ padding: '8px',
13
+ },
14
+ },
15
+ };
16
+
17
+ test('renders correct HTML element', () => {
18
+ render(
19
+ <ThemeProvider theme={theme}>
20
+ <Field htmlFor="myId" label="label" />
21
+ </ThemeProvider>
22
+ );
23
+ const field = screen.getByText(/label/);
24
+
25
+ expect(field instanceof HTMLLabelElement).toBeTruthy();
26
+ });
27
+
28
+ test('supports label prop', () => {
29
+ render(<Field htmlFor="myId" label="Name" />);
30
+ const field = screen.getByText(/Name/);
31
+
32
+ expect(field).toBeDefined();
33
+ });
34
+
35
+ test('supports htmlFor prop', () => {
36
+ render(<Field htmlFor="myId" label="Name" />);
37
+ const field = screen.getByText(/Name/);
38
+
39
+ expect(field).toHaveAttribute('for');
40
+ });
41
+
42
+ test('supports required prop', () => {
43
+ render(<Field htmlFor="myId" label="label" required />);
44
+ const fieldLabel = screen.getByText(/label/);
45
+
46
+ expect(fieldLabel.nextSibling).toBeDefined();
47
+ expect(fieldLabel.nextSibling instanceof SVGElement).toBeTruthy();
48
+ });
49
+
50
+ test('supports error and errorMessage prop', () => {
51
+ render(
52
+ <Field htmlFor="myId" label="label" error errorMessage="Validation error" />
53
+ );
54
+
55
+ const errorMessage = screen.getByText(/Validation/);
56
+ expect(errorMessage).toBeDefined();
57
+ });
58
+
59
+ test('supports disabled prop', () => {
60
+ render(<Field htmlFor="myId" label="label" disabled />);
61
+ const fieldLabel = screen.getByText(/label/);
62
+ expect(fieldLabel.nextSibling).toHaveAttribute('disabled');
63
+ });
64
+
65
+ test('accepts custom styles prop className', () => {
66
+ render(
67
+ <ThemeProvider theme={theme}>
68
+ <Field
69
+ htmlFor="myId"
70
+ label="label"
71
+ className="custom-class-name"
72
+ title="field"
73
+ data-testid="field"
74
+ />
75
+ </ThemeProvider>
76
+ );
77
+ const field = screen.getByTestId(/field/);
78
+
79
+ expect(field.className).toMatch('custom-class-name');
80
+ });
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import { Exclamation } from '@marigold/icons';
3
+ import { ComponentProps } from '@marigold/types';
4
+
5
+ import { Input } from '../Input';
6
+ import { Label } from '../Label';
7
+ import { ValidationMessage } from '../ValidationMessage';
8
+
9
+ export type FieldProps = {
10
+ htmlFor: string;
11
+ label: string;
12
+ required?: boolean;
13
+ error?: boolean;
14
+ errorMessage?: string;
15
+ disabled?: boolean;
16
+ } & ComponentProps<'input'>;
17
+
18
+ export const Field: React.FC<FieldProps> = ({
19
+ type = 'text',
20
+ className,
21
+ htmlFor,
22
+ label,
23
+ required,
24
+ error,
25
+ errorMessage,
26
+ disabled,
27
+ ...props
28
+ }) => {
29
+ return (
30
+ <>
31
+ <Label
32
+ variant={disabled ? 'disabled' : 'above'}
33
+ htmlFor={htmlFor}
34
+ required={required}
35
+ >
36
+ {label}
37
+ </Label>
38
+ <Input
39
+ {...props}
40
+ type={type}
41
+ id={htmlFor}
42
+ disabled={disabled}
43
+ variant={error ? 'error' : 'default'}
44
+ className={className}
45
+ />
46
+ {error && errorMessage && (
47
+ <ValidationMessage>
48
+ <Exclamation size={16} />
49
+ {errorMessage}
50
+ </ValidationMessage>
51
+ )}
52
+ </>
53
+ );
54
+ };
@@ -0,0 +1 @@
1
+ export * from './Field';
@@ -1,79 +1,39 @@
1
- import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
2
- import { Heading, Text } from '@marigold/components';
3
-
4
- <Meta title="Components/Typography/Heading" />
1
+ import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
2
+ import { Heading } from './Heading';
3
+ import { Text } from '../Text';
4
+
5
+ <Meta
6
+ title="Components/Heading"
7
+ argTypes={{
8
+ variant: {
9
+ control: {
10
+ type: 'select',
11
+ },
12
+ options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
13
+ description: 'HTML element style',
14
+ table: {
15
+ defaultValue: {
16
+ summary: 'h2',
17
+ },
18
+ },
19
+ },
20
+ }}
21
+ />
5
22
 
6
23
  # Heading
7
24
 
8
- ## Description
9
-
10
- Use the Heading component for headings of texts.
11
-
12
- ## Properties
13
-
14
- | Property | Type | Default |
15
- | :------------- | :--------------------------------- | :------ |
16
- | `headingStyle` | `h1`, `h2`, `h3`, `h4`, `h5`, `h6` | `h2` |
17
-
18
- ## Import
19
-
20
- ```tsx
21
- import { Heading } from '@marigold/components';
22
- ```
23
-
24
- ## Usage
25
-
26
- <Preview>
27
- <Story name="Headings">
28
- <div>
29
- <Heading headingStyle="h1">H1 amazing heading</Heading>
30
- <Text as="p" variant="heading">
31
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
32
- eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
33
- voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
34
- clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
35
- amet.
36
- </Text>
37
- <Heading>H2 amazing heading</Heading>
38
- <Text as="p" variant="heading">
39
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
40
- eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
41
- voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
42
- clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
43
- amet.
44
- </Text>
45
- <Heading headingStyle="h3">H3 amazing heading</Heading>
46
- <Text as="p" variant="heading">
47
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
48
- eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
49
- voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
50
- clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
51
- amet.
52
- </Text>
53
- <Heading headingStyle="h4">H4 amazing heading</Heading>
54
- <Text as="p" variant="heading">
55
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
56
- eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
57
- voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
58
- clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
59
- amet.
60
- </Text>
61
- <Heading headingStyle="h5">H5 amazing heading</Heading>
62
- <Text as="p" variant="heading">
63
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
64
- eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
65
- voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
66
- clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
67
- amet.
68
- </Text>
69
- <Heading headingStyle="h6">H6 amazing heading</Heading>
70
- <Text as="p" variant="heading">
71
- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
72
- eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
73
- voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
74
- clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
75
- amet.
76
- </Text>
77
- </div>
78
- </Story>
79
- </Preview>
25
+ export const Template = args => (
26
+ <div>
27
+ <Heading {...args}>Heading</Heading>
28
+ <Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
29
+ dignissim dapibus elit, vel egestas felis pharetra non. Cras
30
+ malesuada, massa nec ultricies efficitur, lectus ante consequat magna,
31
+ a porttitor massa ex ut quam.</Text>
32
+ </div>
33
+ );
34
+
35
+ <Canvas>
36
+ <Story name="Default">{Template.bind({})}</Story>
37
+ </Canvas>
38
+
39
+ <ArgsTable story="Default" />
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
- import { MarigoldProvider } from '@marigold/system';
4
- import { Heading } from '@marigold/components';
3
+ import { ThemeProvider } from '@marigold/system';
4
+ import { Heading } from './Heading';
5
5
 
6
6
  const theme = {
7
7
  text: {
@@ -16,9 +16,9 @@ const theme = {
16
16
 
17
17
  test('supports default variant and themeSection', () => {
18
18
  render(
19
- <MarigoldProvider theme={theme}>
19
+ <ThemeProvider theme={theme}>
20
20
  <Heading title="default">Default</Heading>
21
- </MarigoldProvider>
21
+ </ThemeProvider>
22
22
  );
23
23
  const heading = screen.getByTitle(/default/);
24
24
 
@@ -27,37 +27,51 @@ test('supports default variant and themeSection', () => {
27
27
 
28
28
  test('accepts other variant than default', () => {
29
29
  render(
30
- <MarigoldProvider theme={theme}>
31
- <Heading title="default" headingStyle="h3">
30
+ <ThemeProvider theme={theme}>
31
+ <Heading title="default" variant="h3">
32
32
  Default
33
33
  </Heading>
34
- </MarigoldProvider>
34
+ </ThemeProvider>
35
35
  );
36
36
  const heading = screen.getByTitle(/default/);
37
37
 
38
38
  expect(heading).toHaveStyle(`font-family: Roboto`);
39
39
  });
40
40
 
41
- test('renders correct HTML element', () => {
41
+ test('supports default as prop', () => {
42
+ render(<Heading title="default">Default</Heading>);
43
+ const heading = screen.getByTitle(/default/);
44
+
45
+ expect(heading.tagName).toEqual('H2');
46
+ });
47
+
48
+ test('accepts other as prop than default', () => {
42
49
  render(
43
- <MarigoldProvider theme={theme}>
44
- <Heading title="default">Default</Heading>
45
- </MarigoldProvider>
50
+ <Heading as="h3" title="default" variant="h3">
51
+ Default
52
+ </Heading>
46
53
  );
47
54
  const heading = screen.getByTitle(/default/);
48
55
 
56
+ expect(heading.tagName).toEqual('H3');
57
+ });
58
+
59
+ test('renders correct HTML element', () => {
60
+ render(<Heading title="default">Default</Heading>);
61
+ const heading = screen.getByTitle(/default/);
62
+
49
63
  expect(heading instanceof HTMLHeadingElement).toBeTruthy();
50
64
  });
51
65
 
52
- test('variant styles cannot be overridden with CSS prop', () => {
66
+ test('accepts custom styles prop className', () => {
53
67
  render(
54
- <MarigoldProvider theme={theme}>
55
- <Heading css={{ fontFamily: 'Arial' }} title="default">
68
+ <ThemeProvider theme={theme}>
69
+ <Heading className="custom-class-name" title="heading">
56
70
  Default
57
71
  </Heading>
58
- </MarigoldProvider>
72
+ </ThemeProvider>
59
73
  );
60
- const heading = screen.getByTitle(/default/);
74
+ const heading = screen.getByTitle(/heading/);
61
75
 
62
- expect(heading).not.toHaveStyle(`font-family: Arial`);
76
+ expect(heading.className).toMatch('custom-class-name');
63
77
  });