@marigold/components 0.2.0 → 0.3.3

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 (201) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/dist/ActionGroup/ActionGroup.d.ts +1 -2
  3. package/dist/ActionGroup/ActionGroup.stories.d.ts +5 -0
  4. package/dist/Alert/Alert.d.ts +7 -1
  5. package/dist/Alert/Alert.stories.d.ts +5 -0
  6. package/dist/Badge/Badge.d.ts +5 -0
  7. package/dist/Badge/Badge.stories.d.ts +5 -0
  8. package/dist/Box.d.ts +2 -0
  9. package/dist/Button/Button.d.ts +5 -0
  10. package/dist/Button/Button.stories.d.ts +5 -0
  11. package/dist/Card/Card.d.ts +5 -0
  12. package/dist/Card/Card.stories.d.ts +5 -0
  13. package/dist/Checkbox/Checkbox.d.ts +10 -5
  14. package/dist/Checkbox/Checkbox.stories.d.ts +5 -0
  15. package/dist/Checkbox/CheckboxIcons.d.ts +9 -9
  16. package/dist/Column/Column.stories.d.ts +5 -0
  17. package/dist/Columns/Columns.d.ts +2 -2
  18. package/dist/Columns/Columns.stories.d.ts +5 -0
  19. package/dist/Container/Container.stories.d.ts +5 -0
  20. package/dist/Dialog/Dialog.d.ts +5 -2
  21. package/dist/Dialog/Dialog.stories.d.ts +5 -0
  22. package/dist/Dialog/ModalDialog.d.ts +4 -1
  23. package/dist/Divider/Divider.d.ts +7 -3
  24. package/dist/Divider/Divider.stories.d.ts +5 -0
  25. package/dist/Field/Field.d.ts +2 -0
  26. package/dist/Field/Field.stories.d.ts +5 -0
  27. package/dist/Image/Image.d.ts +5 -0
  28. package/dist/Image/Image.stories.d.ts +5 -0
  29. package/dist/Inline/Inline.d.ts +7 -0
  30. package/dist/Inline/Inline.stories.d.ts +5 -0
  31. package/dist/Inline/index.d.ts +1 -0
  32. package/dist/Input/Input.d.ts +5 -0
  33. package/dist/Input/Input.stories.d.ts +5 -0
  34. package/dist/Label/Label.d.ts +12 -1
  35. package/dist/Label/Label.stories.d.ts +5 -0
  36. package/dist/Link/Link.d.ts +3 -0
  37. package/dist/Link/Link.stories.d.ts +5 -0
  38. package/dist/Menu/Menu.d.ts +3 -0
  39. package/dist/Menu/Menu.stories.d.ts +5 -0
  40. package/dist/MenuItem/MenuItem.d.ts +5 -0
  41. package/dist/MenuItem/MenuItem.stories.d.ts +5 -0
  42. package/dist/Message/Message.d.ts +5 -0
  43. package/dist/Message/Message.stories.d.ts +5 -0
  44. package/dist/Provider/MarigoldProvider.d.ts +11 -3
  45. package/dist/Provider/index.d.ts +1 -1
  46. package/dist/Radio/Radio.d.ts +9 -5
  47. package/dist/Radio/Radio.stories.d.ts +5 -0
  48. package/dist/Radio/RadioIcon.d.ts +9 -0
  49. package/dist/Select/ListBox.d.ts +1 -0
  50. package/dist/Select/ListBoxSection.d.ts +1 -0
  51. package/dist/Select/Option.d.ts +1 -0
  52. package/dist/Select/Select.d.ts +15 -1
  53. package/dist/Select/Select.stories.d.ts +5 -0
  54. package/dist/Slider/Slider.d.ts +5 -0
  55. package/dist/Slider/Slider.stories.d.ts +5 -0
  56. package/dist/Stack/Stack.stories.d.ts +5 -0
  57. package/dist/Text/Text.d.ts +5 -0
  58. package/dist/Text/Text.stories.d.ts +5 -0
  59. package/dist/Textarea/Textarea.d.ts +5 -0
  60. package/dist/Textarea/Textarea.stories.d.ts +5 -0
  61. package/dist/ValidationMessage/ValidationMessage.d.ts +5 -0
  62. package/dist/ValidationMessage/ValidationMessage.stories.d.ts +5 -0
  63. package/dist/VisuallyHidden/VisuallyHidden.d.ts +1 -0
  64. package/dist/VisuallyHidden/VisuallyHidden.stories.d.ts +5 -0
  65. package/dist/VisuallyHidden/index.d.ts +1 -0
  66. package/dist/components.cjs.development.js +536 -580
  67. package/dist/components.cjs.development.js.map +1 -1
  68. package/dist/components.cjs.production.min.js +1 -1
  69. package/dist/components.cjs.production.min.js.map +1 -1
  70. package/dist/components.esm.js +481 -535
  71. package/dist/components.esm.js.map +1 -1
  72. package/dist/index.d.ts +2 -2
  73. package/dist/theme.d.ts +23 -48
  74. package/package.json +8 -4
  75. package/src/ActionGroup/ActionGroup.stories.tsx +47 -0
  76. package/src/ActionGroup/ActionGroup.test.tsx +36 -36
  77. package/src/ActionGroup/ActionGroup.tsx +17 -28
  78. package/src/Alert/Alert.stories.tsx +32 -0
  79. package/src/Alert/Alert.test.tsx +4 -1
  80. package/src/Alert/Alert.tsx +18 -3
  81. package/src/Badge/Badge.stories.tsx +38 -0
  82. package/src/Badge/Badge.test.tsx +5 -1
  83. package/src/Badge/Badge.tsx +13 -1
  84. package/src/Box.ts +2 -0
  85. package/src/Button/{Button.stories.mdx → Button.stories.tsx} +10 -17
  86. package/src/Button/Button.test.tsx +34 -11
  87. package/src/Button/Button.tsx +17 -3
  88. package/src/Card/{Card.stories.mdx → Card.stories.tsx} +9 -17
  89. package/src/Card/Card.test.tsx +8 -3
  90. package/src/Card/Card.tsx +13 -1
  91. package/src/Checkbox/{Checkbox.stories.mdx → Checkbox.stories.tsx} +31 -39
  92. package/src/Checkbox/Checkbox.test.tsx +77 -8
  93. package/src/Checkbox/Checkbox.tsx +70 -90
  94. package/src/Checkbox/CheckboxIcons.tsx +51 -41
  95. package/src/Column/Column.stories.tsx +33 -0
  96. package/src/Column/Column.tsx +0 -0
  97. package/src/Columns/Columns.stories.tsx +75 -0
  98. package/src/Columns/Columns.test.tsx +34 -23
  99. package/src/Columns/Columns.tsx +30 -30
  100. package/src/Container/Container.stories.tsx +14 -0
  101. package/src/Container/Container.tsx +0 -0
  102. package/src/Dialog/{Dialog.stories.mdx → Dialog.stories.tsx} +33 -18
  103. package/src/Dialog/Dialog.test.tsx +91 -20
  104. package/src/Dialog/Dialog.tsx +63 -17
  105. package/src/Dialog/ModalDialog.tsx +33 -4
  106. package/src/Divider/Divider.stories.tsx +30 -0
  107. package/src/Divider/Divider.test.tsx +32 -23
  108. package/src/Divider/Divider.tsx +27 -7
  109. package/src/Field/{Field.stories.mdx → Field.stories.tsx} +33 -20
  110. package/src/Field/Field.test.tsx +55 -5
  111. package/src/Field/Field.tsx +10 -8
  112. package/src/Image/Image.stories.tsx +34 -0
  113. package/src/Image/Image.test.tsx +4 -1
  114. package/src/Image/Image.tsx +13 -1
  115. package/src/Inline/Inline.stories.tsx +39 -0
  116. package/src/Inline/Inline.test.tsx +99 -0
  117. package/src/Inline/Inline.tsx +38 -0
  118. package/src/Inline/index.ts +1 -0
  119. package/src/Input/{Input.stories.mdx → Input.stories.tsx} +10 -17
  120. package/src/Input/Input.test.tsx +7 -3
  121. package/src/Input/Input.tsx +13 -1
  122. package/src/Label/{Label.stories.mdx → Label.stories.tsx} +10 -21
  123. package/src/Label/Label.test.tsx +25 -4
  124. package/src/Label/Label.tsx +42 -9
  125. package/src/Link/Link.stories.tsx +35 -0
  126. package/src/Link/Link.test.tsx +6 -2
  127. package/src/Link/Link.tsx +12 -1
  128. package/src/Menu/{Menu.stories.mdx → Menu.stories.tsx} +13 -32
  129. package/src/Menu/Menu.test.tsx +7 -2
  130. package/src/Menu/Menu.tsx +10 -0
  131. package/src/MenuItem/MenuItem.stories.tsx +30 -0
  132. package/src/MenuItem/MenuItem.test.tsx +7 -2
  133. package/src/MenuItem/MenuItem.tsx +12 -0
  134. package/src/Message/Message.stories.tsx +30 -0
  135. package/src/Message/Message.test.tsx +4 -1
  136. package/src/Message/Message.tsx +17 -5
  137. package/src/Provider/MarigoldProvider.test.tsx +65 -55
  138. package/src/Provider/MarigoldProvider.tsx +37 -19
  139. package/src/Provider/index.ts +2 -1
  140. package/src/Radio/{Radio.stories.mdx → Radio.stories.tsx} +31 -39
  141. package/src/Radio/Radio.test.tsx +78 -9
  142. package/src/Radio/Radio.tsx +58 -87
  143. package/src/Radio/RadioIcon.tsx +49 -0
  144. package/src/Select/ListBox.tsx +1 -0
  145. package/src/Select/{Select.stories.mdx → Select.stories.tsx} +23 -20
  146. package/src/Select/Select.test.tsx +39 -1
  147. package/src/Select/Select.tsx +24 -13
  148. package/src/Slider/Slider.stories.tsx +24 -0
  149. package/src/Slider/Slider.test.tsx +10 -6
  150. package/src/Slider/Slider.tsx +25 -13
  151. package/src/Stack/Stack.stories.tsx +57 -0
  152. package/src/Stack/Stack.test.tsx +16 -7
  153. package/src/Stack/Stack.tsx +0 -0
  154. package/src/Text/{Text.stories.mdx → Text.stories.tsx} +20 -19
  155. package/src/Text/Text.test.tsx +2 -2
  156. package/src/Text/Text.tsx +12 -0
  157. package/src/Textarea/{Textarea.stories.mdx → Textarea.stories.tsx} +14 -24
  158. package/src/Textarea/Textarea.test.tsx +7 -3
  159. package/src/Textarea/Textarea.tsx +13 -1
  160. package/src/ValidationMessage/{ValidationMessage.stories.mdx → ValidationMessage.stories.tsx} +8 -17
  161. package/src/ValidationMessage/ValidationMessage.test.tsx +7 -2
  162. package/src/ValidationMessage/ValidationMessage.tsx +12 -0
  163. package/src/VisuallyHidden/VisuallyHidden.stories.tsx +19 -0
  164. package/src/VisuallyHidden/VisuallyHidden.test.tsx +10 -0
  165. package/src/VisuallyHidden/VisuallyHidden.tsx +1 -0
  166. package/src/VisuallyHidden/index.ts +1 -0
  167. package/src/index.ts +2 -2
  168. package/src/theme.ts +49 -48
  169. package/dist/Box/Box.d.ts +0 -47
  170. package/dist/Box/index.d.ts +0 -1
  171. package/dist/Heading/Heading.d.ts +0 -7
  172. package/dist/Heading/index.d.ts +0 -1
  173. package/dist/Hidden/Hidden.d.ts +0 -5
  174. package/dist/Hidden/index.d.ts +0 -1
  175. package/dist/Radio/RadioIcons.d.ts +0 -9
  176. package/src/ActionGroup/ActionGroup.stories.mdx +0 -62
  177. package/src/Alert/Alert.stories.mdx +0 -35
  178. package/src/Badge/Badge.stories.mdx +0 -57
  179. package/src/Box/Box.stories.mdx +0 -334
  180. package/src/Box/Box.test.tsx +0 -133
  181. package/src/Box/Box.tsx +0 -165
  182. package/src/Box/index.ts +0 -1
  183. package/src/Column/Column.stories.mdx +0 -49
  184. package/src/Columns/Columns.stories.mdx +0 -65
  185. package/src/Container/Container.stories.mdx +0 -19
  186. package/src/Divider/Divider.stories.mdx +0 -37
  187. package/src/Heading/Heading.stories.mdx +0 -39
  188. package/src/Heading/Heading.test.tsx +0 -77
  189. package/src/Heading/Heading.tsx +0 -19
  190. package/src/Heading/index.ts +0 -1
  191. package/src/Hidden/Hidden.stories.mdx +0 -39
  192. package/src/Hidden/Hidden.test.tsx +0 -24
  193. package/src/Hidden/Hidden.tsx +0 -16
  194. package/src/Hidden/index.ts +0 -1
  195. package/src/Image/Image.stories.mdx +0 -36
  196. package/src/Link/Link.stories.mdx +0 -45
  197. package/src/MenuItem/MenuItem.stories.mdx +0 -37
  198. package/src/Message/Message.stories.mdx +0 -44
  199. package/src/Radio/RadioIcons.tsx +0 -39
  200. package/src/Slider/Slider.stories.mdx +0 -31
  201. package/src/Stack/Stack.stories.mdx +0 -51
@@ -1,102 +1,113 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
- import { Column, Columns } from '@marigold/components';
3
+ import { Column, Columns, MarigoldProvider } from '@marigold/components';
4
+
5
+ const theme = {
6
+ space: {
7
+ none: 0,
8
+ large: 24,
9
+ },
10
+ };
4
11
 
5
12
  test('supports default space prop', () => {
6
13
  render(
7
- <Columns title="column">
8
- <Column>column</Column>
9
- </Columns>
14
+ <MarigoldProvider theme={theme}>
15
+ <Columns data-testid="column">
16
+ <Column>column</Column>
17
+ </Columns>
18
+ </MarigoldProvider>
10
19
  );
11
- const column = screen.getByTitle(/column/);
20
+ const column = screen.getByTestId(/column/);
12
21
 
13
22
  expect(column).toHaveStyle(`margin: 0px`);
14
23
  });
15
24
 
16
25
  test('supports custom space prop', () => {
17
26
  render(
18
- <Columns space={24} title="column">
19
- <Column>column</Column>
20
- </Columns>
27
+ <MarigoldProvider theme={theme}>
28
+ <Columns space="large" data-testid="column">
29
+ <Column>column</Column>
30
+ </Columns>
31
+ </MarigoldProvider>
21
32
  );
22
- const column = screen.getByTitle(/column/);
33
+ const column = screen.getByTestId(/column/);
23
34
 
24
35
  expect(column).toHaveStyle(`margin: -12px`);
25
36
  });
26
37
 
27
38
  test('supports default horizontalAlign prop: left', () => {
28
39
  render(
29
- <Columns title="column">
40
+ <Columns data-testid="column">
30
41
  <Column>column</Column>
31
42
  </Columns>
32
43
  );
33
- const column = screen.getByTitle(/column/);
44
+ const column = screen.getByTestId(/column/);
34
45
 
35
46
  expect(column).toHaveStyle(`justify-content: flex-start`);
36
47
  });
37
48
 
38
49
  test('supports custom horizontalAlign prop: center', () => {
39
50
  render(
40
- <Columns horizontalAlign="center" title="column">
51
+ <Columns horizontalAlign="center" data-testid="column">
41
52
  <Column>column</Column>
42
53
  </Columns>
43
54
  );
44
- const column = screen.getByTitle(/column/);
55
+ const column = screen.getByTestId(/column/);
45
56
 
46
57
  expect(column).toHaveStyle(`justify-content: center`);
47
58
  });
48
59
 
49
60
  test('supports custom horizontalAlign prop: right', () => {
50
61
  render(
51
- <Columns horizontalAlign="right" title="column">
62
+ <Columns horizontalAlign="right" data-testid="column">
52
63
  <Column>column</Column>
53
64
  </Columns>
54
65
  );
55
- const column = screen.getByTitle(/column/);
66
+ const column = screen.getByTestId(/column/);
56
67
 
57
68
  expect(column).toHaveStyle(`justify-content: flex-end`);
58
69
  });
59
70
 
60
71
  test('supports default verticalAlign prop: top', () => {
61
72
  render(
62
- <Columns title="column">
73
+ <Columns data-testid="column">
63
74
  <Column>column</Column>
64
75
  </Columns>
65
76
  );
66
- const column = screen.getByTitle(/column/);
77
+ const column = screen.getByTestId(/column/);
67
78
 
68
79
  expect(column).toHaveStyle(`align-items: flex-start`);
69
80
  });
70
81
 
71
82
  test('supports custom verticalAlign prop: center', () => {
72
83
  render(
73
- <Columns verticalAlign="center" title="column">
84
+ <Columns verticalAlign="center" data-testid="column">
74
85
  <Column>column</Column>
75
86
  </Columns>
76
87
  );
77
- const column = screen.getByTitle(/column/);
88
+ const column = screen.getByTestId(/column/);
78
89
 
79
90
  expect(column).toHaveStyle(`align-items: center`);
80
91
  });
81
92
 
82
93
  test('supports custom verticalAlign prop: bottom', () => {
83
94
  render(
84
- <Columns verticalAlign="bottom" title="column">
95
+ <Columns verticalAlign="bottom" data-testid="column">
85
96
  <Column>column</Column>
86
97
  </Columns>
87
98
  );
88
- const column = screen.getByTitle(/column/);
99
+ const column = screen.getByTestId(/column/);
89
100
 
90
101
  expect(column).toHaveStyle(`align-items: flex-end`);
91
102
  });
92
103
 
93
104
  test('renders correct HTML element', () => {
94
105
  render(
95
- <Columns title="column">
106
+ <Columns data-testid="column">
96
107
  <Column>column</Column>
97
108
  </Columns>
98
109
  );
99
- const column = screen.getByTitle(/column/);
110
+ const column = screen.getByTestId(/column/);
100
111
 
101
112
  expect(column instanceof HTMLDivElement).toBeTruthy();
102
113
  });
@@ -1,63 +1,63 @@
1
1
  import React, { Children } from 'react';
2
- import { useStyles } from '@marigold/system';
3
2
  import { Box } from '../Box';
4
3
  import flattenChildren from 'react-keyed-flatten-children';
4
+ import { ResponsiveStyleValue, useTheme } from '@marigold/system';
5
5
 
6
6
  type ColumnsProps = {
7
7
  className?: string;
8
- space?: number;
8
+ space?: ResponsiveStyleValue<string>;
9
9
  horizontalAlign?: 'left' | 'right' | 'center';
10
10
  verticalAlign?: 'top' | 'bottom' | 'center';
11
- title?: string; // Should only be used for testing.
11
+ };
12
+
13
+ const useAlignment = (direction: string) => {
14
+ switch (direction) {
15
+ case 'right':
16
+ return 'flex-end';
17
+ case 'bottom':
18
+ return 'flex-end';
19
+ case 'center':
20
+ return 'center';
21
+ }
22
+ return 'flex-start';
12
23
  };
13
24
 
14
25
  export const Columns: React.FC<ColumnsProps> = ({
15
- space = 0,
26
+ space = 'none',
16
27
  horizontalAlign = 'left',
17
28
  verticalAlign = 'top',
18
29
  className,
19
30
  children,
20
31
  ...props
21
32
  }) => {
22
- let columnItems = flattenChildren(children);
23
- let childClassNames = useStyles({ css: { p: `${space / 2}px` } });
33
+ const justifyContent = useAlignment(horizontalAlign);
34
+ const alignItems = useAlignment(verticalAlign);
24
35
 
25
- // horizontal Alignment
26
- let justify = 'flex-start';
27
- if (horizontalAlign === 'right') {
28
- justify = 'flex-end';
29
- } else if (horizontalAlign === 'center') {
30
- justify = 'center';
31
- }
32
-
33
- // vertical Alignment
34
- let alignItems = 'flex-start';
35
- if (verticalAlign === 'bottom') {
36
- alignItems = 'flex-end';
37
- } else if (verticalAlign === 'center') {
38
- alignItems = 'center';
39
- }
36
+ /**
37
+ * transform space string to space value from theme
38
+ */
39
+ const { css } = useTheme();
40
+ const spaceObject = css({ space }) as Object;
41
+ const spaceValue = Object.values(spaceObject)[0];
40
42
 
41
43
  return (
42
- <Box p={`${space}px`} display="flex" className={className}>
44
+ <Box p={space} display="flex" className={className}>
43
45
  <Box
44
- width={`calc(100% + ${space}px)`}
45
- m={`${-space / 2}px`}
46
+ width={`calc(100% + ${spaceValue}px)`}
47
+ m={`${-spaceValue / 2}px`}
46
48
  display="flex"
47
49
  flexWrap="wrap"
48
50
  alignItems={alignItems}
49
- justifyContent={justify}
51
+ justifyContent={justifyContent}
50
52
  {...props}
51
53
  >
52
54
  {Children.map(
53
- columnItems as unknown as React.ReactElement,
55
+ flattenChildren(children) as unknown as React.ReactElement,
54
56
  (child: React.ReactElement) => {
55
57
  return React.cloneElement(
56
58
  child,
57
- {
58
- className: childClassNames,
59
- },
60
- <Box className={child && child.props.className}>
59
+ {},
60
+ <Box css={{ p: `${spaceValue / 2}px` }}>
61
61
  {child.props.children}
62
62
  </Box>
63
63
  );
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+ import { Container } from './Container';
4
+ import { Text } from '../Text';
5
+
6
+ export default {
7
+ title: 'Components/Container',
8
+ } as Meta;
9
+
10
+ export const Basic: ComponentStory<typeof Container> = args => (
11
+ <Container {...args}>
12
+ <Text>Container with width=100%</Text>
13
+ </Container>
14
+ );
File without changes
@@ -1,16 +1,17 @@
1
- import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
2
3
  import { Dialog, useDialogButtonProps } from './Dialog';
3
4
  import { Button } from '../Button';
4
5
  import { Text } from '../Text';
5
6
 
6
- <Meta
7
- title="Components/Dialog"
8
- parameters={{
7
+ export default {
8
+ title: 'Components/Dialog',
9
+ parameters: {
9
10
  actions: {
10
11
  handles: ['click'],
11
12
  },
12
- }}
13
- argTypes={{
13
+ },
14
+ argTypes: {
14
15
  isOpen: {
15
16
  control: {
16
17
  type: 'boolean',
@@ -35,12 +36,32 @@ import { Text } from '../Text';
35
36
  },
36
37
  description: 'handled by state from useDialogButtonProps',
37
38
  },
38
- }}
39
- />
40
-
41
- # Dialog
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;
42
63
 
43
- export const Template = ({ ...args }) => {
64
+ export const Basic: ComponentStory<typeof Dialog> = args => {
44
65
  const { state, openButtonProps, openButtonRef } = useDialogButtonProps();
45
66
  return (
46
67
  <>
@@ -55,9 +76,9 @@ export const Template = ({ ...args }) => {
55
76
  {state.isOpen && (
56
77
  <Dialog
57
78
  title="Dialog Title"
79
+ {...args}
58
80
  isOpen={state.isOpen}
59
81
  close={state.close}
60
- {...args}
61
82
  >
62
83
  <Text>Dialog content</Text>
63
84
  </Dialog>
@@ -65,9 +86,3 @@ export const Template = ({ ...args }) => {
65
86
  </>
66
87
  );
67
88
  };
68
-
69
- <Canvas>
70
- <Story name="Default">{Template.bind({})}</Story>
71
- </Canvas>
72
-
73
- <ArgsTable story="Default" />
@@ -1,25 +1,44 @@
1
1
  import React from 'react';
2
2
  import { fireEvent, render, screen } from '@testing-library/react';
3
3
  import userEvent from '@testing-library/user-event';
4
+
4
5
  import { ThemeProvider } from '@marigold/system';
6
+
5
7
  import { Dialog, useDialogButtonProps } from './Dialog';
6
8
  import { Button } from '../Button';
7
9
 
8
10
  const theme = {
11
+ space: {
12
+ none: 0,
13
+ xxsmall: 1,
14
+ xsmall: 2,
15
+ small: 4,
16
+ medium: 8,
17
+ large: 16,
18
+ },
9
19
  dialog: {
10
- wrapper: {
11
- p: '8px',
20
+ __default: {
21
+ p: 'small',
12
22
  },
13
- body: {
14
- p: '4px',
23
+ default: {
24
+ p: 'medium',
15
25
  },
16
- onClose: {
17
- p: '0px',
26
+ backdrop: {
27
+ p: 'none',
18
28
  },
19
29
  },
20
30
  };
21
31
 
22
- const DialogComponent: React.FC = props => {
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
+ }) => {
23
42
  const { state, openButtonProps, openButtonRef } = useDialogButtonProps();
24
43
  return (
25
44
  <>
@@ -28,10 +47,11 @@ const DialogComponent: React.FC = props => {
28
47
  </Button>
29
48
  {state.isOpen && (
30
49
  <Dialog
50
+ variant={variant}
51
+ backdropVariant={backdropVariant}
31
52
  title="Title"
32
53
  isOpen={state.isOpen}
33
54
  close={state.close}
34
- {...props}
35
55
  >
36
56
  Content
37
57
  </Dialog>
@@ -48,19 +68,67 @@ test('dialog can be opened by button', () => {
48
68
  expect(dialog).toBeDefined();
49
69
  });
50
70
 
51
- test('supports theme variants', () => {
71
+ test('supports default variants', () => {
52
72
  render(
53
73
  <ThemeProvider theme={theme}>
54
- <DialogComponent data-testid="Dialog" />
74
+ <DialogComponent />
55
75
  </ThemeProvider>
56
76
  );
57
77
  const button = screen.getByText(/Open/);
58
78
  fireEvent.click(button);
59
79
 
60
- const dialogBody = screen.getByTestId(/Dialog/);
61
- expect(dialogBody).toHaveStyle(`padding: 8px`);
62
- const dialogTitle = screen.getByText(/Title/);
63
- expect(dialogTitle.parentElement).toHaveStyle(`padding: 4px`);
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`);
64
132
  });
65
133
 
66
134
  test('close Dialog by escape key', () => {
@@ -73,15 +141,18 @@ test('close Dialog by escape key', () => {
73
141
  expect(dialog).not.toBeVisible();
74
142
  });
75
143
 
76
- test('close Dialog by close button', () => {
77
- render(<DialogComponent data-testid="Dialog" />);
144
+ test('close Dialog by close button', async () => {
145
+ render(<DialogComponent />);
78
146
  const button = screen.getByText(/Open/);
79
147
  fireEvent.click(button);
80
148
 
81
- const dialog = screen.getByTestId(/Dialog/);
149
+ const dialog = screen.getByRole(/dialog/);
82
150
  expect(dialog).toBeVisible();
83
- const buttonDiv = dialog.lastChild;
84
- const onClose = buttonDiv && buttonDiv.firstChild;
85
- onClose && fireEvent.click(onClose);
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
+
86
157
  expect(dialog).not.toBeVisible();
87
158
  });
@@ -7,22 +7,31 @@ import { Close } from '@marigold/icons';
7
7
 
8
8
  import { Box } from '../Box';
9
9
  import { Button } from '../Button';
10
- import { Heading } from '../Heading';
10
+ import { Text } from '../Text';
11
11
 
12
- import { ModalDialog } from './ModalDialog';
12
+ import { ModalDialog, ModalDialogProps } from './ModalDialog';
13
13
 
14
+ // Props
15
+ // ---------------
14
16
  export type DialogProps = {
15
- isOpen: boolean;
17
+ backdropVariant?: string;
16
18
  close: ComponentProps<typeof Button>['onClick'];
19
+ isOpen: boolean;
17
20
  title?: string;
18
- } & ComponentProps<'div'>;
21
+ variant?: string;
22
+ } & ModalDialogProps &
23
+ ComponentProps<'div'>;
19
24
 
25
+ // Component
26
+ // ---------------
20
27
  export const Dialog: React.FC<DialogProps> = ({
28
+ backdropVariant,
21
29
  children,
22
- title,
23
30
  className,
24
- isOpen,
25
31
  close,
32
+ isOpen,
33
+ title,
34
+ variant,
26
35
  ...props
27
36
  }) => {
28
37
  const closeButtonRef = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
@@ -39,25 +48,62 @@ export const Dialog: React.FC<DialogProps> = ({
39
48
 
40
49
  return (
41
50
  <OverlayContainer>
42
- <ModalDialog isOpen={isOpen} onClose={close} isDismissable>
43
- <Box variant="dialog.wrapper" className={className} {...props}>
44
- <Box variant="dialog.body">
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">
45
70
  {title && (
46
- <Heading as="h4" variant="h4">
71
+ <Text as="h4" variant="headline4">
47
72
  {title}
48
- </Heading>
73
+ </Text>
49
74
  )}
50
75
  {children}
51
76
  </Box>
52
- <Box variant="dialog.onClose">
53
- <Button
54
- variant="close"
55
- size="xsmall"
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
+ }}
56
102
  {...closeButtonProps}
57
103
  ref={closeButtonRef}
58
104
  >
59
105
  <Close size={16} />
60
- </Button>
106
+ </Box>
61
107
  </Box>
62
108
  </Box>
63
109
  </ModalDialog>
@@ -65,7 +111,7 @@ export const Dialog: React.FC<DialogProps> = ({
65
111
  );
66
112
  };
67
113
 
68
- // use this hook to get the overlayTriggerState and openButton props for using the dialog component
114
+ // get the overlayTriggerState and openButton props for using the dialog component
69
115
  export const useDialogButtonProps = () => {
70
116
  const state = useOverlayTriggerState({});
71
117
  const openButtonRef = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
@@ -11,16 +11,31 @@ import { AriaDialogProps } from '@react-types/dialog';
11
11
 
12
12
  import { Box } from '../Box';
13
13
 
14
- export type ModalDialogProps = OverlayProps & AriaDialogProps;
14
+ // Props
15
+ // ---------------
16
+ export type ModalDialogProps = {
17
+ variant?: string;
18
+ backdropVariant?: string;
19
+ } & OverlayProps &
20
+ AriaDialogProps;
15
21
 
22
+ // Component
23
+ // ---------------
16
24
  export const ModalDialog: React.FC<ModalDialogProps> = ({
25
+ variant,
26
+ backdropVariant = 'backdrop',
17
27
  children,
18
28
  ...props
19
29
  }) => {
30
+ const { isDismissable, isOpen, onClose, ...restProps } = props;
31
+
20
32
  // Handle interacting outside the dialog and pressing
21
33
  // the Escape key to close the modal.
22
34
  const ref = React.useRef<HTMLElement>() as RefObject<HTMLElement>;
23
- const { overlayProps, underlayProps } = useOverlay(props, ref);
35
+ const { overlayProps, underlayProps } = useOverlay(
36
+ { isDismissable, isOpen, onClose },
37
+ ref
38
+ );
24
39
 
25
40
  // Prevent scrolling while the modal is open, and hide content
26
41
  // outside the modal from screen readers.
@@ -30,14 +45,28 @@ export const ModalDialog: React.FC<ModalDialogProps> = ({
30
45
  const { dialogProps } = useDialog(props, ref);
31
46
 
32
47
  return (
33
- <Box variant="dialog.modalWrapper" {...underlayProps}>
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
+ >
34
62
  <FocusScope contain restoreFocus autoFocus>
35
63
  <Box
36
64
  {...overlayProps}
37
65
  {...dialogProps}
38
66
  {...modalProps}
39
67
  ref={ref}
40
- variant="dialog.modalBody"
68
+ variant={variant ? `dialog.${variant}` : `dialog`}
69
+ {...restProps}
41
70
  >
42
71
  {children}
43
72
  </Box>