@marigold/components 0.0.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/CHANGELOG.md +294 -0
  2. package/dist/ActionGroup/ActionGroup.d.ts +8 -0
  3. package/dist/ActionGroup/ActionGroup.stories.d.ts +5 -0
  4. package/dist/ActionGroup/index.d.ts +1 -0
  5. package/dist/Alert/Alert.d.ts +16 -3
  6. package/dist/Alert/Alert.stories.d.ts +5 -0
  7. package/dist/Badge/Badge.d.ts +11 -5
  8. package/dist/Badge/Badge.stories.d.ts +5 -0
  9. package/dist/Box.d.ts +2 -0
  10. package/dist/Button/Button.d.ts +9 -5
  11. package/dist/Button/Button.stories.d.ts +5 -0
  12. package/dist/Card/Card.d.ts +14 -0
  13. package/dist/Card/Card.stories.d.ts +5 -0
  14. package/dist/Card/index.d.ts +1 -0
  15. package/dist/Checkbox/Checkbox.d.ts +17 -5
  16. package/dist/Checkbox/Checkbox.stories.d.ts +5 -0
  17. package/dist/Checkbox/CheckboxIcons.d.ts +9 -0
  18. package/dist/Column/Column.d.ts +6 -4
  19. package/dist/Column/Column.stories.d.ts +5 -0
  20. package/dist/Columns/Columns.d.ts +10 -0
  21. package/dist/Columns/Columns.stories.d.ts +5 -0
  22. package/dist/Columns/index.d.ts +1 -0
  23. package/dist/Container/Container.d.ts +5 -4
  24. package/dist/Container/Container.stories.d.ts +5 -0
  25. package/dist/Dialog/Dialog.d.ts +17 -0
  26. package/dist/Dialog/Dialog.stories.d.ts +5 -0
  27. package/dist/Dialog/ModalDialog.d.ts +8 -0
  28. package/dist/Dialog/index.d.ts +1 -0
  29. package/dist/Divider/Divider.d.ts +10 -3
  30. package/dist/Divider/Divider.stories.d.ts +5 -0
  31. package/dist/Field/Field.d.ts +10 -5
  32. package/dist/Field/Field.stories.d.ts +5 -0
  33. package/dist/Image/Image.d.ts +11 -5
  34. package/dist/Image/Image.stories.d.ts +5 -0
  35. package/dist/Inline/Inline.d.ts +7 -0
  36. package/dist/Inline/Inline.stories.d.ts +5 -0
  37. package/dist/Inline/index.d.ts +1 -0
  38. package/dist/Input/Input.d.ts +10 -4
  39. package/dist/Input/Input.stories.d.ts +5 -0
  40. package/dist/Label/Label.d.ts +18 -5
  41. package/dist/Label/Label.stories.d.ts +5 -0
  42. package/dist/Link/Link.d.ts +10 -5
  43. package/dist/Link/Link.stories.d.ts +5 -0
  44. package/dist/Menu/Menu.d.ts +11 -4
  45. package/dist/Menu/Menu.stories.d.ts +5 -0
  46. package/dist/MenuItem/MenuItem.d.ts +11 -4
  47. package/dist/MenuItem/MenuItem.stories.d.ts +5 -0
  48. package/dist/Message/Message.d.ts +10 -4
  49. package/dist/Message/Message.stories.d.ts +5 -0
  50. package/dist/Provider/MarigoldProvider.d.ts +11 -0
  51. package/dist/Provider/index.d.ts +3 -0
  52. package/dist/Radio/Radio.d.ts +17 -4
  53. package/dist/Radio/RadioIcons.d.ts +10 -0
  54. package/dist/Select/ListBox.d.ts +9 -0
  55. package/dist/Select/ListBoxSection.d.ts +9 -0
  56. package/dist/Select/Option.d.ts +9 -0
  57. package/dist/Select/Popover.d.ts +9 -0
  58. package/dist/Select/Select.d.ts +27 -3
  59. package/dist/Select/Select.stories.d.ts +5 -0
  60. package/dist/Slider/Slider.d.ts +10 -4
  61. package/dist/Slider/Slider.stories.d.ts +5 -0
  62. package/dist/Stack/Stack.d.ts +7 -0
  63. package/dist/Stack/Stack.stories.d.ts +5 -0
  64. package/dist/Stack/index.d.ts +1 -0
  65. package/dist/Text/Text.d.ts +17 -7
  66. package/dist/Text/Text.stories.d.ts +5 -0
  67. package/dist/Textarea/Textarea.d.ts +15 -4
  68. package/dist/Textarea/Textarea.stories.d.ts +5 -0
  69. package/dist/ValidationMessage/ValidationMessage.d.ts +10 -4
  70. package/dist/ValidationMessage/ValidationMessage.stories.d.ts +5 -0
  71. package/dist/VisuallyHidden/VisuallyHidden.d.ts +1 -0
  72. package/dist/VisuallyHidden/VisuallyHidden.stories.d.ts +5 -0
  73. package/dist/VisuallyHidden/index.d.ts +1 -0
  74. package/dist/components.cjs.development.js +1276 -461
  75. package/dist/components.cjs.development.js.map +1 -1
  76. package/dist/components.cjs.production.min.js +1 -1
  77. package/dist/components.cjs.production.min.js.map +1 -1
  78. package/dist/components.esm.js +1229 -461
  79. package/dist/components.esm.js.map +1 -1
  80. package/dist/index.d.ts +10 -3
  81. package/dist/theme.d.ts +23 -28
  82. package/package.json +27 -4
  83. package/src/ActionGroup/ActionGroup.stories.tsx +47 -0
  84. package/src/ActionGroup/ActionGroup.test.tsx +83 -0
  85. package/src/ActionGroup/ActionGroup.tsx +32 -0
  86. package/src/ActionGroup/index.ts +1 -0
  87. package/src/Alert/Alert.stories.tsx +32 -0
  88. package/src/Alert/Alert.test.tsx +34 -23
  89. package/src/Alert/Alert.tsx +48 -24
  90. package/src/Badge/Badge.stories.tsx +38 -0
  91. package/src/Badge/Badge.test.tsx +14 -40
  92. package/src/Badge/Badge.tsx +31 -28
  93. package/src/Box.ts +2 -0
  94. package/src/Button/Button.stories.tsx +57 -0
  95. package/src/Button/Button.test.tsx +76 -13
  96. package/src/Button/Button.tsx +58 -23
  97. package/src/Card/Card.stories.tsx +41 -0
  98. package/src/Card/Card.test.tsx +71 -0
  99. package/src/Card/Card.tsx +48 -0
  100. package/src/Card/index.ts +1 -0
  101. package/src/Checkbox/Checkbox.stories.mdx +90 -112
  102. package/src/Checkbox/Checkbox.stories.tsx +78 -0
  103. package/src/Checkbox/Checkbox.test.tsx +139 -24
  104. package/src/Checkbox/Checkbox.tsx +95 -58
  105. package/src/Checkbox/CheckboxIcons.tsx +59 -0
  106. package/src/Column/Column.stories.tsx +33 -0
  107. package/src/Column/Column.test.tsx +15 -59
  108. package/src/Column/Column.tsx +21 -19
  109. package/src/Columns/Columns.stories.tsx +75 -0
  110. package/src/Columns/Columns.test.tsx +113 -0
  111. package/src/Columns/Columns.tsx +69 -0
  112. package/src/Columns/index.ts +1 -0
  113. package/src/Container/Container.stories.tsx +14 -0
  114. package/src/Container/Container.test.tsx +8 -49
  115. package/src/Container/Container.tsx +8 -19
  116. package/src/Dialog/Dialog.stories.tsx +88 -0
  117. package/src/Dialog/Dialog.test.tsx +158 -0
  118. package/src/Dialog/Dialog.tsx +130 -0
  119. package/src/Dialog/ModalDialog.tsx +76 -0
  120. package/src/Dialog/index.ts +1 -0
  121. package/src/Divider/Divider.stories.tsx +30 -0
  122. package/src/Divider/Divider.test.tsx +14 -6
  123. package/src/Divider/Divider.tsx +20 -13
  124. package/src/Field/Field.stories.tsx +110 -0
  125. package/src/Field/Field.test.tsx +75 -34
  126. package/src/Field/Field.tsx +50 -43
  127. package/src/Image/Image.stories.tsx +34 -0
  128. package/src/Image/Image.test.tsx +6 -3
  129. package/src/Image/Image.tsx +21 -15
  130. package/src/Inline/Inline.stories.tsx +39 -0
  131. package/src/Inline/Inline.test.tsx +99 -0
  132. package/src/Inline/Inline.tsx +38 -0
  133. package/src/Inline/index.ts +1 -0
  134. package/src/Input/Input.stories.tsx +54 -0
  135. package/src/Input/Input.test.tsx +9 -5
  136. package/src/Input/Input.tsx +21 -16
  137. package/src/Label/Label.stories.tsx +41 -0
  138. package/src/Label/Label.test.tsx +41 -6
  139. package/src/Label/Label.tsx +59 -18
  140. package/src/Link/Link.stories.tsx +35 -0
  141. package/src/Link/Link.test.tsx +52 -22
  142. package/src/Link/Link.tsx +40 -20
  143. package/src/Menu/Menu.stories.tsx +62 -0
  144. package/src/Menu/Menu.test.tsx +13 -7
  145. package/src/Menu/Menu.tsx +44 -38
  146. package/src/MenuItem/MenuItem.stories.tsx +30 -0
  147. package/src/MenuItem/MenuItem.test.tsx +23 -14
  148. package/src/MenuItem/MenuItem.tsx +29 -18
  149. package/src/Message/Message.stories.tsx +30 -0
  150. package/src/Message/Message.test.tsx +5 -2
  151. package/src/Message/Message.tsx +48 -40
  152. package/src/Provider/MarigoldProvider.test.tsx +136 -0
  153. package/src/Provider/MarigoldProvider.tsx +47 -0
  154. package/src/Provider/index.ts +4 -0
  155. package/src/Radio/Radio.stories.mdx +91 -94
  156. package/src/Radio/Radio.test.tsx +92 -16
  157. package/src/Radio/Radio.tsx +114 -50
  158. package/src/Radio/RadioIcons.tsx +39 -0
  159. package/src/Select/ListBox.tsx +40 -0
  160. package/src/Select/ListBoxSection.tsx +40 -0
  161. package/src/Select/Option.tsx +48 -0
  162. package/src/Select/Popover.tsx +50 -0
  163. package/src/Select/Select.stories.tsx +81 -0
  164. package/src/Select/Select.test.tsx +311 -43
  165. package/src/Select/Select.tsx +174 -28
  166. package/src/Slider/Slider.stories.tsx +24 -0
  167. package/src/Slider/Slider.test.tsx +11 -7
  168. package/src/Slider/Slider.tsx +30 -15
  169. package/src/Stack/Stack.stories.tsx +57 -0
  170. package/src/Stack/Stack.test.tsx +138 -0
  171. package/src/Stack/Stack.tsx +39 -0
  172. package/src/Stack/index.ts +1 -0
  173. package/src/Text/Text.stories.tsx +61 -0
  174. package/src/Text/Text.test.tsx +41 -36
  175. package/src/Text/Text.tsx +55 -29
  176. package/src/Textarea/Textarea.stories.tsx +64 -0
  177. package/src/Textarea/Textarea.test.tsx +41 -5
  178. package/src/Textarea/Textarea.tsx +57 -17
  179. package/src/ValidationMessage/ValidationMessage.stories.tsx +27 -0
  180. package/src/ValidationMessage/ValidationMessage.test.tsx +19 -14
  181. package/src/ValidationMessage/ValidationMessage.tsx +36 -21
  182. package/src/VisuallyHidden/VisuallyHidden.stories.tsx +19 -0
  183. package/src/VisuallyHidden/VisuallyHidden.test.tsx +10 -0
  184. package/src/VisuallyHidden/VisuallyHidden.tsx +1 -0
  185. package/src/VisuallyHidden/index.ts +1 -0
  186. package/src/index.ts +11 -3
  187. package/src/theme.ts +49 -28
  188. package/dist/Heading/Heading.d.ts +0 -5
  189. package/dist/Heading/index.d.ts +0 -1
  190. package/dist/Hidden/Hidden.d.ts +0 -6
  191. package/dist/Hidden/index.d.ts +0 -1
  192. package/dist/Svg/Svg.d.ts +0 -6
  193. package/dist/Svg/index.d.ts +0 -1
  194. package/src/Alert/Alert.stories.mdx +0 -49
  195. package/src/Badge/Badge.stories.mdx +0 -41
  196. package/src/Button/Button.stories.mdx +0 -155
  197. package/src/Column/Column.stories.mdx +0 -76
  198. package/src/Container/Container.stories.mdx +0 -42
  199. package/src/Divider/Divider.stories.mdx +0 -42
  200. package/src/Field/Field.stories.mdx +0 -57
  201. package/src/Heading/Heading.stories.mdx +0 -79
  202. package/src/Heading/Heading.test.tsx +0 -63
  203. package/src/Heading/Heading.tsx +0 -22
  204. package/src/Heading/index.ts +0 -1
  205. package/src/Hidden/Hidden.stories.mdx +0 -64
  206. package/src/Hidden/Hidden.test.tsx +0 -87
  207. package/src/Hidden/Hidden.tsx +0 -25
  208. package/src/Hidden/index.ts +0 -1
  209. package/src/Image/Image.stories.mdx +0 -40
  210. package/src/Input/Input.stories.mdx +0 -44
  211. package/src/Label/Label.stories.mdx +0 -34
  212. package/src/Link/Link.stories.mdx +0 -37
  213. package/src/Menu/Menu.stories.mdx +0 -47
  214. package/src/MenuItem/MenuItem.stories.mdx +0 -32
  215. package/src/Message/Message.stories.mdx +0 -43
  216. package/src/Select/Select.stories.mdx +0 -43
  217. package/src/Slider/Slider.stories.mdx +0 -57
  218. package/src/Svg/Svg.stories.mdx +0 -47
  219. package/src/Svg/Svg.test.tsx +0 -76
  220. package/src/Svg/Svg.tsx +0 -31
  221. package/src/Svg/index.ts +0 -1
  222. package/src/Text/Text.stories.mdx +0 -60
  223. package/src/Textarea/Textarea.stories.mdx +0 -34
  224. package/src/ValidationMessage/ValidationMessage.stories.mdx +0 -36
@@ -1,52 +1,13 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
- import { ThemeProvider } from '@marigold/system';
4
- import { Container, Text } from '@marigold/components';
5
-
6
- const theme = {
7
- layout: {
8
- container: {
9
- margin: 0,
10
- },
11
- notContainer: {
12
- margin: '2px',
13
- },
14
- },
15
- };
16
-
17
- test('supports default variant and themeSection', () => {
18
- render(
19
- <ThemeProvider theme={theme}>
20
- <Container title="container">
21
- <Text>sdf</Text>
22
- </Container>
23
- </ThemeProvider>
24
- );
25
- const container = screen.getByTitle(/container/);
26
-
27
- expect(container).toHaveStyle(`margin: 0`);
28
- });
29
-
30
- test('accepts other variant than default', () => {
31
- render(
32
- <ThemeProvider theme={theme}>
33
- <Container variant="notContainer" title="container">
34
- <Text>sdf</Text>
35
- </Container>
36
- </ThemeProvider>
37
- );
38
- const container = screen.getByTitle(/container/);
39
-
40
- expect(container).toHaveStyle(`margin: 2px`);
41
- });
3
+ import { Container } from './Container';
4
+ import { Text } from '../Text';
42
5
 
43
6
  test('renders correct HTML element', () => {
44
7
  render(
45
- <ThemeProvider theme={theme}>
46
- <Container title="container">
47
- <Text>sdf</Text>
48
- </Container>
49
- </ThemeProvider>
8
+ <Container title="container">
9
+ <Text>sdf</Text>
10
+ </Container>
50
11
  );
51
12
  const container = screen.getByTitle(/container/);
52
13
 
@@ -55,11 +16,9 @@ test('renders correct HTML element', () => {
55
16
 
56
17
  test('accepts custom styles prop className', () => {
57
18
  render(
58
- <ThemeProvider theme={theme}>
59
- <Container className="custom-class-name" title="container">
60
- <Text>text</Text>
61
- </Container>
62
- </ThemeProvider>
19
+ <Container className="custom-class-name" title="container">
20
+ <Text>text</Text>
21
+ </Container>
63
22
  );
64
23
  const container = screen.getByTitle(/container/);
65
24
 
@@ -1,24 +1,13 @@
1
1
  import React from 'react';
2
- import { useStyles, system } from '@marigold/system';
2
+ import { Box } from '../Box';
3
3
 
4
- type ContainerProps = {
5
- variant?: string;
4
+ export type ContainerProps = {
5
+ className?: string;
6
+ title?: string; // Used for testing.
6
7
  };
7
8
 
8
- export const Container = system<ContainerProps, 'div'>(
9
- ({ variant = 'container', className, children, ...props }) => {
10
- const classNames = useStyles(
11
- {
12
- variant: `layout.${variant}`,
13
- width: '100%',
14
- },
15
- className
16
- );
17
-
18
- return (
19
- <div className={classNames} {...props}>
20
- {children}
21
- </div>
22
- );
23
- }
9
+ export const Container: React.FC<ContainerProps> = ({ children, ...props }) => (
10
+ <Box {...props} width="100%">
11
+ {children}
12
+ </Box>
24
13
  );
@@ -0,0 +1,88 @@
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+ import { Dialog, useDialogButtonProps } from './Dialog';
4
+ import { Button } from '../Button';
5
+ import { Text } from '../Text';
6
+
7
+ export default {
8
+ title: 'Components/Dialog',
9
+ parameters: {
10
+ actions: {
11
+ handles: ['click'],
12
+ },
13
+ },
14
+ argTypes: {
15
+ isOpen: {
16
+ control: {
17
+ type: 'boolean',
18
+ },
19
+ description: 'handled by state from useDialogButtonProps',
20
+ options: [true, false],
21
+ table: {
22
+ defaultValue: {
23
+ summary: false,
24
+ },
25
+ },
26
+ },
27
+ title: {
28
+ control: {
29
+ type: 'text',
30
+ },
31
+ description: 'set dialog title',
32
+ },
33
+ close: {
34
+ control: {
35
+ type: 'text',
36
+ },
37
+ description: 'handled by state from useDialogButtonProps',
38
+ },
39
+ variant: {
40
+ control: {
41
+ type: 'text',
42
+ },
43
+ description: 'Dialog variant',
44
+ table: {
45
+ defaultValue: {
46
+ summary: '__default',
47
+ },
48
+ },
49
+ },
50
+ backdropVariant: {
51
+ control: {
52
+ type: 'text',
53
+ },
54
+ description: 'Dialog backdrop variant',
55
+ table: {
56
+ defaultValue: {
57
+ summary: 'backdrop',
58
+ },
59
+ },
60
+ },
61
+ },
62
+ } as Meta;
63
+
64
+ export const Basic: ComponentStory<typeof Dialog> = args => {
65
+ const { state, openButtonProps, openButtonRef } = useDialogButtonProps();
66
+ return (
67
+ <>
68
+ <Button
69
+ variant="secondary"
70
+ size="small"
71
+ {...openButtonProps}
72
+ ref={openButtonRef}
73
+ >
74
+ Open Dialog
75
+ </Button>
76
+ {state.isOpen && (
77
+ <Dialog
78
+ title="Dialog Title"
79
+ {...args}
80
+ isOpen={state.isOpen}
81
+ close={state.close}
82
+ >
83
+ <Text>Dialog content</Text>
84
+ </Dialog>
85
+ )}
86
+ </>
87
+ );
88
+ };
@@ -0,0 +1,158 @@
1
+ import React from 'react';
2
+ import { fireEvent, render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+
5
+ import { ThemeProvider } from '@marigold/system';
6
+
7
+ import { Dialog, useDialogButtonProps } from './Dialog';
8
+ import { Button } from '../Button';
9
+
10
+ const theme = {
11
+ space: {
12
+ none: 0,
13
+ xxsmall: 1,
14
+ xsmall: 2,
15
+ small: 4,
16
+ medium: 8,
17
+ large: 16,
18
+ },
19
+ dialog: {
20
+ __default: {
21
+ p: 'small',
22
+ },
23
+ default: {
24
+ p: 'medium',
25
+ },
26
+ backdrop: {
27
+ p: 'none',
28
+ },
29
+ },
30
+ };
31
+
32
+ type DialogComponentProps = {
33
+ title?: string;
34
+ variant?: string;
35
+ backdropVariant?: string;
36
+ };
37
+
38
+ const DialogComponent: React.FC<DialogComponentProps> = ({
39
+ variant,
40
+ backdropVariant,
41
+ }) => {
42
+ const { state, openButtonProps, openButtonRef } = useDialogButtonProps();
43
+ return (
44
+ <>
45
+ <Button {...openButtonProps} ref={openButtonRef}>
46
+ Open
47
+ </Button>
48
+ {state.isOpen && (
49
+ <Dialog
50
+ variant={variant}
51
+ backdropVariant={backdropVariant}
52
+ title="Title"
53
+ isOpen={state.isOpen}
54
+ close={state.close}
55
+ >
56
+ Content
57
+ </Dialog>
58
+ )}
59
+ </>
60
+ );
61
+ };
62
+
63
+ test('dialog can be opened by button', () => {
64
+ render(<DialogComponent />);
65
+ const button = screen.getByText(/Open/);
66
+ fireEvent.click(button);
67
+ const dialog = screen.getByText(/Content/);
68
+ expect(dialog).toBeDefined();
69
+ });
70
+
71
+ test('supports default variants', () => {
72
+ render(
73
+ <ThemeProvider theme={theme}>
74
+ <DialogComponent />
75
+ </ThemeProvider>
76
+ );
77
+ const button = screen.getByText(/Open/);
78
+ fireEvent.click(button);
79
+
80
+ const dialog = screen.getByRole(/dialog/);
81
+ expect(dialog).toHaveStyle(`padding: 4px`);
82
+ expect(dialog.parentElement).toHaveStyle(`padding: 0px`);
83
+ });
84
+
85
+ test('supports other variants than default', () => {
86
+ render(
87
+ <ThemeProvider theme={theme}>
88
+ <DialogComponent variant="default" backdropVariant="default" />
89
+ </ThemeProvider>
90
+ );
91
+ const button = screen.getByText(/Open/);
92
+ fireEvent.click(button);
93
+
94
+ const dialog = screen.getByRole(/dialog/);
95
+ expect(dialog).toHaveStyle(`padding: 8px`);
96
+ expect(dialog.parentElement).toHaveStyle(`padding: 8px`);
97
+ });
98
+
99
+ test('dialog has correct baseCSS styles', async () => {
100
+ render(
101
+ <ThemeProvider theme={theme}>
102
+ <DialogComponent variant="default" backdropVariant="default" />
103
+ </ThemeProvider>
104
+ );
105
+ const button = screen.getByText(/Open/);
106
+ fireEvent.click(button);
107
+
108
+ const dialog = screen.getByRole(/dialog/);
109
+ expect(dialog.firstChild).toHaveStyle(`display: flex`);
110
+ expect(dialog.firstChild?.lastChild).toHaveStyle(`alignItems: start`);
111
+
112
+ // ModalDialog baseCSS
113
+ expect(dialog.parentElement).toHaveStyle(`display: grid`);
114
+ });
115
+
116
+ test('dialog has correct baseCSS styles with theme index', async () => {
117
+ render(
118
+ <ThemeProvider theme={theme}>
119
+ <DialogComponent variant="default" backdropVariant="default" />
120
+ </ThemeProvider>
121
+ );
122
+ const button = screen.getByText(/Open/);
123
+ fireEvent.click(button);
124
+
125
+ const dialog = screen.getByRole(/dialog/);
126
+ expect(dialog.firstChild).toHaveStyle(`paddingLeft: 16`);
127
+ expect(dialog.firstChild?.lastChild).toHaveStyle(`paddingTop: 2`);
128
+
129
+ // find all buttons to get the close and not the open button
130
+ const onCloseButton = await screen.findAllByRole('button');
131
+ expect(onCloseButton[1]).toHaveStyle(`paddingLeft: 1`);
132
+ });
133
+
134
+ test('close Dialog by escape key', () => {
135
+ render(<DialogComponent />);
136
+ const button = screen.getByText(/Open/);
137
+ fireEvent.click(button);
138
+
139
+ const dialog = screen.getByText(/Content/);
140
+ userEvent.type(dialog, '{esc}');
141
+ expect(dialog).not.toBeVisible();
142
+ });
143
+
144
+ test('close Dialog by close button', async () => {
145
+ render(<DialogComponent />);
146
+ const button = screen.getByText(/Open/);
147
+ fireEvent.click(button);
148
+
149
+ const dialog = screen.getByRole(/dialog/);
150
+ expect(dialog).toBeVisible();
151
+
152
+ // find all buttons to get the close and not the open button
153
+ const onCloseButton = await screen.findAllByRole('button');
154
+ expect(onCloseButton[1]).toBeVisible();
155
+ fireEvent.click(onCloseButton[1]);
156
+
157
+ expect(dialog).not.toBeVisible();
158
+ });
@@ -0,0 +1,130 @@
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 { Text } from '../Text';
11
+
12
+ import { ModalDialog, ModalDialogProps } from './ModalDialog';
13
+
14
+ // Props
15
+ // ---------------
16
+ export type DialogProps = {
17
+ backdropVariant?: string;
18
+ close: ComponentProps<typeof Button>['onClick'];
19
+ isOpen: boolean;
20
+ title?: string;
21
+ variant?: string;
22
+ } & ModalDialogProps &
23
+ ComponentProps<'div'>;
24
+
25
+ // Component
26
+ // ---------------
27
+ export const Dialog: React.FC<DialogProps> = ({
28
+ backdropVariant,
29
+ children,
30
+ className,
31
+ close,
32
+ isOpen,
33
+ title,
34
+ variant,
35
+ ...props
36
+ }) => {
37
+ const closeButtonRef = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
38
+
39
+ // useButton ensures that focus management is handled correctly,
40
+ // across all browsers. Focus is restored to the button once the
41
+ // dialog closes.
42
+ const { buttonProps: closeButtonProps } = useButton(
43
+ {
44
+ onPress: () => close(),
45
+ },
46
+ closeButtonRef
47
+ );
48
+
49
+ return (
50
+ <OverlayContainer>
51
+ <ModalDialog
52
+ variant={variant}
53
+ backdropVariant={backdropVariant}
54
+ isOpen={isOpen}
55
+ onClose={close}
56
+ isDismissable
57
+ {...props}
58
+ >
59
+ <Box
60
+ __baseCSS={{
61
+ display: 'flex',
62
+ justifyContent: 'space-between',
63
+ borderRadius: 'small',
64
+ pl: 'large',
65
+ pb: 'large',
66
+ }}
67
+ className={className}
68
+ >
69
+ <Box pt="medium">
70
+ {title && (
71
+ <Text as="h4" variant="headline4">
72
+ {title}
73
+ </Text>
74
+ )}
75
+ {children}
76
+ </Box>
77
+ <Box
78
+ __baseCSS={{
79
+ display: 'flex',
80
+ justifyContent: 'flex-end',
81
+ alignItems: 'start',
82
+ paddingTop: 'xsmall',
83
+ paddingX: 'xsmall',
84
+ }}
85
+ >
86
+ <Box
87
+ as={Button}
88
+ __baseCSS={{
89
+ color: 'text',
90
+ bg: 'transparent',
91
+ lineHeight: 'xsmall',
92
+ px: 'xxsmall',
93
+ ':hover': {
94
+ color: 'text',
95
+ bg: 'transparent',
96
+ cursor: 'pointer',
97
+ },
98
+ ':focus': {
99
+ outline: 0,
100
+ },
101
+ }}
102
+ {...closeButtonProps}
103
+ ref={closeButtonRef}
104
+ >
105
+ <Close size={16} />
106
+ </Box>
107
+ </Box>
108
+ </Box>
109
+ </ModalDialog>
110
+ </OverlayContainer>
111
+ );
112
+ };
113
+
114
+ // get the overlayTriggerState and openButton props for using the dialog component
115
+ export const useDialogButtonProps = () => {
116
+ const state = useOverlayTriggerState({});
117
+ const openButtonRef = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
118
+ const { buttonProps: openButtonProps } = useButton(
119
+ {
120
+ onPress: () => state.open(),
121
+ },
122
+ openButtonRef
123
+ );
124
+
125
+ return {
126
+ state,
127
+ openButtonProps,
128
+ openButtonRef,
129
+ };
130
+ };
@@ -0,0 +1,76 @@
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
+ // Props
15
+ // ---------------
16
+ export type ModalDialogProps = {
17
+ variant?: string;
18
+ backdropVariant?: string;
19
+ } & OverlayProps &
20
+ AriaDialogProps;
21
+
22
+ // Component
23
+ // ---------------
24
+ export const ModalDialog: React.FC<ModalDialogProps> = ({
25
+ variant,
26
+ backdropVariant = 'backdrop',
27
+ children,
28
+ ...props
29
+ }) => {
30
+ const { isDismissable, isOpen, onClose, ...restProps } = props;
31
+
32
+ // Handle interacting outside the dialog and pressing
33
+ // the Escape key to close the modal.
34
+ const ref = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
35
+ const { overlayProps, underlayProps } = useOverlay(
36
+ { isDismissable, isOpen, onClose },
37
+ ref
38
+ );
39
+
40
+ // Prevent scrolling while the modal is open, and hide content
41
+ // outside the modal from screen readers.
42
+ usePreventScroll();
43
+
44
+ const { modalProps } = useModal();
45
+ const { dialogProps } = useDialog(props, ref);
46
+
47
+ return (
48
+ <Box
49
+ __baseCSS={{
50
+ display: 'grid',
51
+ placeItems: 'center',
52
+ position: 'fixed',
53
+ zIndex: 100,
54
+ top: 0,
55
+ left: 0,
56
+ bottom: 0,
57
+ right: 0,
58
+ }}
59
+ variant={`dialog.${backdropVariant}`}
60
+ {...underlayProps}
61
+ >
62
+ <FocusScope contain restoreFocus autoFocus>
63
+ <Box
64
+ {...overlayProps}
65
+ {...dialogProps}
66
+ {...modalProps}
67
+ ref={ref}
68
+ variant={variant ? `dialog.${variant}` : `dialog`}
69
+ {...restProps}
70
+ >
71
+ {children}
72
+ </Box>
73
+ </FocusScope>
74
+ </Box>
75
+ );
76
+ };
@@ -0,0 +1 @@
1
+ export * from './Dialog';
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+ import { Divider } from './Divider';
4
+ import { Text } from '../Text';
5
+
6
+ export default {
7
+ title: 'Components/Divider',
8
+ argTypes: {
9
+ variant: {
10
+ control: {
11
+ type: 'select',
12
+ },
13
+ options: ['regular', 'bold'],
14
+ description: 'Thick or thin line',
15
+ table: {
16
+ defaultValue: {
17
+ summary: 'regular',
18
+ },
19
+ },
20
+ },
21
+ },
22
+ } as Meta;
23
+
24
+ export const Basic: ComponentStory<typeof Divider> = args => (
25
+ <>
26
+ <Text>Above</Text>
27
+ <Divider {...args} />
28
+ <Text>Below</Text>
29
+ </>
30
+ );
@@ -1,19 +1,27 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
3
  import { ThemeProvider } from '@marigold/system';
4
- import { Divider } from '@marigold/components';
4
+ import { Divider } from './Divider';
5
5
 
6
6
  const theme = {
7
+ space: {
8
+ none: 0,
9
+ small: 2,
10
+ },
11
+ borders: {
12
+ none: 0,
13
+ regular: '1px solid',
14
+ },
7
15
  divider: {
8
16
  regular: {
9
- border: 0,
10
- borderBottom: '1px solid',
11
- margin: '2px',
17
+ border: 'none',
18
+ borderBottom: 'regular',
19
+ margin: 'small',
12
20
  },
13
21
  bold: {
14
- border: 0,
22
+ border: 'none',
15
23
  borderBottom: '2px solid',
16
- margin: '2px',
24
+ margin: 'small',
17
25
  },
18
26
  },
19
27
  };
@@ -1,18 +1,25 @@
1
1
  import React from 'react';
2
- import { useStyles, system } from '@marigold/system';
2
+ import { Box } from '../Box';
3
3
 
4
- type DividerProps = {
4
+ // Theme Extension
5
+ // ---------------
6
+ export interface DividerThemeExtension<Value> {
7
+ divider?: {
8
+ [key: string]: Value;
9
+ };
10
+ }
11
+
12
+ // Props
13
+ // ---------------
14
+ export type DividerProps = {
15
+ className?: string;
5
16
  variant?: string;
17
+ title?: string; // Should only be used for testing.
6
18
  };
7
19
 
8
- export const Divider = system<DividerProps, 'hr'>(
9
- ({ variant = 'regular', className, ...props }) => {
10
- const classNames = useStyles(
11
- {
12
- variant: `divider.${variant}`,
13
- },
14
- className
15
- );
16
- return <hr className={classNames} {...props} />;
17
- }
18
- );
20
+ // Component
21
+ // ---------------
22
+ export const Divider: React.FC<DividerProps> = ({
23
+ variant = 'regular',
24
+ ...props
25
+ }) => <Box {...props} as="hr" variant={`divider.${variant}`} />;