@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,64 +1,101 @@
1
1
  import React from 'react';
2
- import { useStyles, system } from '@marigold/system';
3
- import { Required, SquareUnchecked, SquareChecked } from '@marigold/icons';
4
- import { Label } from '@marigold/components';
2
+ import { useFocusRing } from '@react-aria/focus';
3
+ import { VisuallyHidden } from '@react-aria/visually-hidden';
4
+ import { useCheckbox } from '@react-aria/checkbox';
5
+ import { useToggleState } from '@react-stately/toggle';
6
+ import { ToggleProps } from '@react-types/checkbox';
5
7
 
6
- type CheckboxProps = {
7
- id: string;
8
- variant?: string;
9
- label?: string;
10
- required?: boolean;
11
- };
8
+ import { ComponentProps } from '@marigold/types';
9
+ import { Exclamation } from '@marigold/icons';
10
+
11
+ import { CheckboxIcon, CheckboxIconProps } from './CheckboxIcons';
12
+ import { Box } from '../Box';
13
+ import { Label } from '../Label';
14
+ import { ValidationMessage } from '../ValidationMessage';
15
+
16
+ // Theme Extension
17
+ // ---------------
18
+ export interface CheckboxThemeExtension<Value> {
19
+ checkbox?: {
20
+ [key: string]: Value;
21
+ };
22
+ }
12
23
 
13
- export const Checkbox = system<CheckboxProps, 'input'>(
14
- ({ id, variant = 'checkbox', label, required, className, ...props }) => {
15
- const checkboxStyles = useStyles({
16
- position: 'absolute',
17
- opacity: 0,
18
- zIndex: -1,
19
- width: 1,
20
- height: 1,
21
- overflow: 'hidden',
22
- });
24
+ // Checkbox Input
25
+ // ---------------
26
+ type CheckboxInputProps = CheckboxIconProps &
27
+ ToggleProps &
28
+ ComponentProps<'input'>;
23
29
 
24
- const checkboxIconStyles = useStyles(
25
- {
26
- variant: `form.${variant}`,
27
- ariaHidden: 'true',
28
- mr: 2,
29
- verticalAlign: 'middle',
30
- ':hover': { cursor: 'pointer' },
31
- 'input:disabled ~ &': {
32
- color: 'muted',
33
- cursor: 'not-allowed',
34
- },
35
- },
36
- className
37
- );
30
+ const CheckboxInput: React.FC<CheckboxInputProps> = ({ error, ...props }) => {
31
+ const state = useToggleState(props);
32
+ const ref = React.useRef<HTMLInputElement>(null);
33
+ const { inputProps } = useCheckbox(props, state, ref);
34
+ const { focusProps } = useFocusRing();
38
35
 
39
- const checkbox = (
40
- <div className={useStyles({ display: 'inline-block' })}>
41
- <input type="checkbox" id={id} className={checkboxStyles} {...props} />
42
- {props.checked ? (
43
- <SquareChecked className={checkboxIconStyles} />
44
- ) : (
45
- <SquareUnchecked className={checkboxIconStyles} />
46
- )}
47
- </div>
48
- );
36
+ return (
37
+ <Box pr="xsmall">
38
+ <VisuallyHidden>
39
+ <Box
40
+ as="input"
41
+ type="checkbox"
42
+ disabled={props.disabled}
43
+ {...inputProps}
44
+ {...focusProps}
45
+ ref={ref}
46
+ {...props}
47
+ />
48
+ </VisuallyHidden>
49
+ <CheckboxIcon
50
+ checked={props.checked}
51
+ variant={props.variant}
52
+ disabled={props.disabled}
53
+ error={error}
54
+ />
55
+ </Box>
56
+ );
57
+ };
49
58
 
50
- return (
51
- <>
52
- {label ? (
53
- <Label htmlFor={id}>
54
- {checkbox}
55
- {label}
56
- {required ? <Required size={16} /> : ''}
57
- </Label>
58
- ) : (
59
- <>{checkbox}</>
60
- )}
61
- </>
62
- );
63
- }
64
- );
59
+ // Checkbox
60
+ // ---------------
61
+ export type CheckboxProps = {
62
+ id: string;
63
+ label: string;
64
+ required?: boolean;
65
+ labelVariant?: string;
66
+ error?: boolean;
67
+ errorMessage?: string;
68
+ } & CheckboxInputProps;
69
+
70
+ export const Checkbox: React.FC<CheckboxProps> = ({
71
+ label,
72
+ required,
73
+ labelVariant = 'inline',
74
+ error,
75
+ errorMessage,
76
+ ...props
77
+ }) => {
78
+ return (
79
+ <>
80
+ <Box
81
+ as={Label}
82
+ __baseCSS={{
83
+ ':hover': { cursor: props.disabled ? 'not-allowed' : 'pointer' },
84
+ }}
85
+ htmlFor={props.id}
86
+ required={required}
87
+ variant={`label.${labelVariant}`}
88
+ color={props.disabled ? 'disabled' : 'text'}
89
+ >
90
+ <Box as={CheckboxInput} error={error} {...props} />
91
+ {label}
92
+ </Box>
93
+ {error && errorMessage && (
94
+ <ValidationMessage>
95
+ <Exclamation size={16} />
96
+ {errorMessage}
97
+ </ValidationMessage>
98
+ )}
99
+ </>
100
+ );
101
+ };
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { conditional, State, SVG } from '@marigold/system';
3
+
4
+ import { Box } from '../Box';
5
+
6
+ // Checkbox Icon
7
+ // ---------------
8
+ export type CheckboxIconProps = {
9
+ variant?: string;
10
+ checked?: boolean;
11
+ disabled?: boolean;
12
+ error?: boolean;
13
+ children?: never;
14
+ };
15
+
16
+ export const CheckboxIcon: React.FC<CheckboxIconProps> = ({
17
+ variant = '',
18
+ checked = false,
19
+ disabled = false,
20
+ error = false,
21
+ }) => {
22
+ const conditionalStates: State = disabled
23
+ ? {
24
+ disabled: disabled,
25
+ }
26
+ : {
27
+ checked: checked,
28
+ error: error,
29
+ };
30
+
31
+ return (
32
+ <SVG
33
+ width="16"
34
+ height="32"
35
+ viewBox="0 0 16 32"
36
+ fill="none"
37
+ aria-hidden="true"
38
+ >
39
+ <Box
40
+ as="rect"
41
+ x="0.5"
42
+ y="8.5"
43
+ width="15px"
44
+ height="15px"
45
+ rx="1.5"
46
+ variant={conditional(`checkbox.${variant}`, conditionalStates)}
47
+ />
48
+ {checked && (
49
+ <Box
50
+ __baseCSS={{ fill: 'gray00' }}
51
+ as="path"
52
+ fillRule="evenodd"
53
+ clipRule="evenodd"
54
+ d="M13.9571 12.8338L12.4085 11.2852L6.08699 17.6007L3.59887 15.1126L2.04163 16.6588L6.08682 20.704L13.9571 12.8338Z"
55
+ />
56
+ )}
57
+ </SVG>
58
+ );
59
+ };
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+
4
+ import { Column } from './Column';
5
+ import { Box } from '../Box';
6
+
7
+ export default {
8
+ title: 'Components/Column',
9
+ argTypes: {
10
+ width: {
11
+ control: {
12
+ type: 'range',
13
+ min: 0,
14
+ max: 12,
15
+ step: 1,
16
+ },
17
+ description: 'Absolute width in 12 grid',
18
+ table: {
19
+ defaultValue: {
20
+ summary: 12,
21
+ },
22
+ },
23
+ },
24
+ },
25
+ } as Meta;
26
+
27
+ export const Basic: ComponentStory<typeof Column> = args => (
28
+ <Column width={12} {...args}>
29
+ <Box p="small" border="1px solid gray" borderRadius="4px">
30
+ width=12
31
+ </Box>
32
+ </Column>
33
+ );
@@ -1,76 +1,32 @@
1
1
  import React from 'react';
2
2
  import { render, screen } from '@testing-library/react';
3
- import { ThemeProvider } from '@marigold/system';
4
- import { Column } from '@marigold/components';
5
-
6
- const theme = {
7
- layout: {
8
- column: {
9
- alignItems: 'center',
10
- },
11
- grid: {
12
- alignItems: 'right',
13
- },
14
- },
15
- };
16
-
17
- test('supports default variant and themeSection', () => {
18
- render(
19
- <ThemeProvider theme={theme}>
20
- <Column title="column">Default</Column>
21
- </ThemeProvider>
22
- );
23
- const column = screen.getByTitle(/column/);
24
-
25
- expect(column).toHaveStyle(`align-items: center`);
26
- });
27
-
28
- test('accepts other variant than default', () => {
29
- render(
30
- <ThemeProvider theme={theme}>
31
- <Column title="column" variant="grid">
32
- Grid
33
- </Column>
34
- </ThemeProvider>
35
- );
36
- const column = screen.getByTitle(/column/);
37
-
38
- expect(column).toHaveStyle(`align-items: right`);
39
- });
3
+ import { Column } from './Column';
40
4
 
41
5
  test('supports width prop', () => {
42
- render(
43
- <ThemeProvider theme={theme}>
44
- <Column title="column" width={6}>
45
- column
46
- </Column>
47
- </ThemeProvider>
48
- );
49
- const column = screen.getByTitle(/column/);
6
+ render(<Column width={6}>column</Column>);
7
+ const column = screen.getByText('column');
50
8
 
51
9
  expect(column).toHaveStyle(`width: 50%`);
52
10
  });
53
11
 
54
12
  test('renders correct HTML element', () => {
55
- render(
56
- <ThemeProvider theme={theme}>
57
- <Column title="column">Default</Column>
58
- </ThemeProvider>
59
- );
60
- const column = screen.getByTitle(/column/);
13
+ render(<Column>column</Column>);
14
+ const column = screen.getByText('column');
61
15
 
62
16
  expect(column instanceof HTMLDivElement).toBeTruthy();
63
17
  });
64
18
 
65
19
  test('accepts custom styles prop className', () => {
66
- render(
67
- <ThemeProvider theme={theme}>
68
- <Column className="custom-class-name" title="column">
69
- text
70
- </Column>
71
- </ThemeProvider>
72
- );
73
- const column = screen.getByTitle(/column/);
20
+ render(<Column className="custom-class-name">column</Column>);
21
+ const column = screen.getByText('column');
74
22
 
75
23
  expect(column.className).toMatch('custom-class-name');
76
24
  });
25
+
26
+ test('accepts responsive values', () => {
27
+ render(<Column width={[12, 6]}>column</Column>);
28
+ const column = screen.getByText('column');
29
+
30
+ // Note: as of November 2021 jest-dom does not support media queries...
31
+ expect(column).toHaveStyle('width: 100%');
32
+ });
@@ -1,25 +1,27 @@
1
1
  import React from 'react';
2
- import { useStyles, system } from '@marigold/system';
2
+ import { Box } from '../Box';
3
3
 
4
- type ColumnProps = {
5
- variant?: string;
6
- width?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
7
- };
4
+ type WidthValues = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
8
5
 
9
- export const Column = system<ColumnProps, 'div'>(
10
- ({ variant = 'column', width = 12, className, children, ...props }) => {
11
- const classNames = useStyles(
12
- {
13
- variant: `layout.${variant}`,
14
- width: `${(width / 12) * 100}%`,
15
- },
16
- className
17
- );
6
+ export type ColumnProps = {
7
+ className?: string;
8
+ width?: WidthValues | WidthValues[];
9
+ };
18
10
 
19
- return (
20
- <div className={classNames} {...props}>
21
- {children}
22
- </div>
23
- );
11
+ const transform = (width: WidthValues | WidthValues[]) => {
12
+ if (Array.isArray(width)) {
13
+ return width.map(v => `${(v / 12) * 100}%`);
24
14
  }
15
+
16
+ return `${(width / 12) * 100}%`;
17
+ };
18
+
19
+ export const Column: React.FC<ColumnProps> = ({
20
+ width = 12,
21
+ children,
22
+ ...props
23
+ }) => (
24
+ <Box {...props} width={transform(width)}>
25
+ {children}
26
+ </Box>
25
27
  );
@@ -0,0 +1,75 @@
1
+ import React from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+ import { Column, Columns, Text } from '@marigold/components';
4
+
5
+ export default {
6
+ title: 'Components/Columns',
7
+ argTypes: {
8
+ space: {
9
+ control: {
10
+ type: 'select',
11
+ },
12
+ options: [
13
+ 'none',
14
+ 'xxsmall',
15
+ 'xsmall',
16
+ 'small',
17
+ 'medium',
18
+ 'large',
19
+ 'xlarge',
20
+ 'xxlarge',
21
+ ],
22
+ description: 'Responsive Style Value',
23
+ table: {
24
+ defaultValue: {
25
+ summary: 'none',
26
+ },
27
+ },
28
+ },
29
+ horizontalAlign: {
30
+ control: {
31
+ type: 'select',
32
+ },
33
+ options: ['left', 'right', 'center'],
34
+ description: 'where to place',
35
+ table: {
36
+ defaultValue: {
37
+ summary: 'left',
38
+ },
39
+ },
40
+ },
41
+ verticalAlign: {
42
+ control: {
43
+ type: 'select',
44
+ },
45
+ options: ['top', 'bottom', 'center'],
46
+ description: 'where to place',
47
+ table: {
48
+ defaultValue: {
49
+ summary: 'top',
50
+ },
51
+ },
52
+ },
53
+ },
54
+ } as Meta;
55
+
56
+ export const Basic: ComponentStory<typeof Columns> = args => (
57
+ <Columns {...args}>
58
+ <Column width={6}>
59
+ <Text>First column</Text>
60
+ <Text>
61
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
62
+ dignissim dapibus elit, vel egestas felis pharetra non. Cras malesuada,
63
+ massa nec ultricies efficitur.
64
+ </Text>
65
+ </Column>
66
+ <Column width={6}>
67
+ <Text>Second column</Text>
68
+ <Text>
69
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
70
+ dignissim dapibus elit, vel egestas felis pharetra non. Cras malesuada,
71
+ massa nec ultricies efficitur.
72
+ </Text>
73
+ </Column>
74
+ </Columns>
75
+ );
@@ -0,0 +1,113 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { Column, Columns, MarigoldProvider } from '@marigold/components';
4
+
5
+ const theme = {
6
+ space: {
7
+ none: 0,
8
+ large: 24,
9
+ },
10
+ };
11
+
12
+ test('supports default space prop', () => {
13
+ render(
14
+ <MarigoldProvider theme={theme}>
15
+ <Columns data-testid="column">
16
+ <Column>column</Column>
17
+ </Columns>
18
+ </MarigoldProvider>
19
+ );
20
+ const column = screen.getByTestId(/column/);
21
+
22
+ expect(column).toHaveStyle(`margin: 0px`);
23
+ });
24
+
25
+ test('supports custom space prop', () => {
26
+ render(
27
+ <MarigoldProvider theme={theme}>
28
+ <Columns space="large" data-testid="column">
29
+ <Column>column</Column>
30
+ </Columns>
31
+ </MarigoldProvider>
32
+ );
33
+ const column = screen.getByTestId(/column/);
34
+
35
+ expect(column).toHaveStyle(`margin: -12px`);
36
+ });
37
+
38
+ test('supports default horizontalAlign prop: left', () => {
39
+ render(
40
+ <Columns data-testid="column">
41
+ <Column>column</Column>
42
+ </Columns>
43
+ );
44
+ const column = screen.getByTestId(/column/);
45
+
46
+ expect(column).toHaveStyle(`justify-content: flex-start`);
47
+ });
48
+
49
+ test('supports custom horizontalAlign prop: center', () => {
50
+ render(
51
+ <Columns horizontalAlign="center" data-testid="column">
52
+ <Column>column</Column>
53
+ </Columns>
54
+ );
55
+ const column = screen.getByTestId(/column/);
56
+
57
+ expect(column).toHaveStyle(`justify-content: center`);
58
+ });
59
+
60
+ test('supports custom horizontalAlign prop: right', () => {
61
+ render(
62
+ <Columns horizontalAlign="right" data-testid="column">
63
+ <Column>column</Column>
64
+ </Columns>
65
+ );
66
+ const column = screen.getByTestId(/column/);
67
+
68
+ expect(column).toHaveStyle(`justify-content: flex-end`);
69
+ });
70
+
71
+ test('supports default verticalAlign prop: top', () => {
72
+ render(
73
+ <Columns data-testid="column">
74
+ <Column>column</Column>
75
+ </Columns>
76
+ );
77
+ const column = screen.getByTestId(/column/);
78
+
79
+ expect(column).toHaveStyle(`align-items: flex-start`);
80
+ });
81
+
82
+ test('supports custom verticalAlign prop: center', () => {
83
+ render(
84
+ <Columns verticalAlign="center" data-testid="column">
85
+ <Column>column</Column>
86
+ </Columns>
87
+ );
88
+ const column = screen.getByTestId(/column/);
89
+
90
+ expect(column).toHaveStyle(`align-items: center`);
91
+ });
92
+
93
+ test('supports custom verticalAlign prop: bottom', () => {
94
+ render(
95
+ <Columns verticalAlign="bottom" data-testid="column">
96
+ <Column>column</Column>
97
+ </Columns>
98
+ );
99
+ const column = screen.getByTestId(/column/);
100
+
101
+ expect(column).toHaveStyle(`align-items: flex-end`);
102
+ });
103
+
104
+ test('renders correct HTML element', () => {
105
+ render(
106
+ <Columns data-testid="column">
107
+ <Column>column</Column>
108
+ </Columns>
109
+ );
110
+ const column = screen.getByTestId(/column/);
111
+
112
+ expect(column instanceof HTMLDivElement).toBeTruthy();
113
+ });
@@ -0,0 +1,69 @@
1
+ import React, { Children } from 'react';
2
+ import { Box } from '../Box';
3
+ import flattenChildren from 'react-keyed-flatten-children';
4
+ import { ResponsiveStyleValue, useTheme } from '@marigold/system';
5
+
6
+ type ColumnsProps = {
7
+ className?: string;
8
+ space?: ResponsiveStyleValue<string>;
9
+ horizontalAlign?: 'left' | 'right' | 'center';
10
+ verticalAlign?: 'top' | 'bottom' | 'center';
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';
23
+ };
24
+
25
+ export const Columns: React.FC<ColumnsProps> = ({
26
+ space = 'none',
27
+ horizontalAlign = 'left',
28
+ verticalAlign = 'top',
29
+ className,
30
+ children,
31
+ ...props
32
+ }) => {
33
+ const justifyContent = useAlignment(horizontalAlign);
34
+ const alignItems = useAlignment(verticalAlign);
35
+
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];
42
+
43
+ return (
44
+ <Box p={space} display="flex" className={className}>
45
+ <Box
46
+ width={`calc(100% + ${spaceValue}px)`}
47
+ m={`${-spaceValue / 2}px`}
48
+ display="flex"
49
+ flexWrap="wrap"
50
+ alignItems={alignItems}
51
+ justifyContent={justifyContent}
52
+ {...props}
53
+ >
54
+ {Children.map(
55
+ flattenChildren(children) as unknown as React.ReactElement,
56
+ (child: React.ReactElement) => {
57
+ return React.cloneElement(
58
+ child,
59
+ {},
60
+ <Box css={{ p: `${spaceValue / 2}px` }}>
61
+ {child.props.children}
62
+ </Box>
63
+ );
64
+ }
65
+ )}
66
+ </Box>
67
+ </Box>
68
+ );
69
+ };
@@ -0,0 +1 @@
1
+ export * from './Columns';
@@ -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
+ );