@marigold/components 0.0.3 → 0.3.1

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 (220) hide show
  1. package/CHANGELOG.md +174 -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 +22 -1
  6. package/dist/Alert/Alert.stories.d.ts +5 -0
  7. package/dist/Badge/Badge.d.ts +5 -0
  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 -6
  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 +15 -3
  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 +3 -1
  19. package/dist/Column/Column.stories.d.ts +5 -0
  20. package/dist/Columns/Columns.d.ts +2 -2
  21. package/dist/Columns/Columns.stories.d.ts +5 -0
  22. package/dist/Container/Container.stories.d.ts +5 -0
  23. package/dist/Dialog/Dialog.d.ts +12 -2
  24. package/dist/Dialog/Dialog.stories.d.ts +5 -0
  25. package/dist/Dialog/ModalDialog.d.ts +8 -0
  26. package/dist/Divider/Divider.d.ts +5 -0
  27. package/dist/Divider/Divider.stories.d.ts +5 -0
  28. package/dist/Field/Field.d.ts +5 -1
  29. package/dist/Field/Field.stories.d.ts +5 -0
  30. package/dist/Image/Image.d.ts +5 -0
  31. package/dist/Image/Image.stories.d.ts +5 -0
  32. package/dist/Inline/Inline.d.ts +7 -0
  33. package/dist/Inline/Inline.stories.d.ts +5 -0
  34. package/dist/Inline/index.d.ts +1 -0
  35. package/dist/Input/Input.d.ts +5 -0
  36. package/dist/Input/Input.stories.d.ts +5 -0
  37. package/dist/Label/Label.d.ts +14 -2
  38. package/dist/Label/Label.stories.d.ts +5 -0
  39. package/dist/Link/Link.d.ts +10 -6
  40. package/dist/Link/Link.stories.d.ts +5 -0
  41. package/dist/Menu/Menu.d.ts +3 -0
  42. package/dist/Menu/Menu.stories.d.ts +5 -0
  43. package/dist/MenuItem/MenuItem.d.ts +5 -0
  44. package/dist/MenuItem/MenuItem.stories.d.ts +5 -0
  45. package/dist/Message/Message.d.ts +5 -0
  46. package/dist/Message/Message.stories.d.ts +5 -0
  47. package/dist/Provider/MarigoldProvider.d.ts +11 -0
  48. package/dist/Provider/index.d.ts +3 -0
  49. package/dist/Radio/Radio.d.ts +11 -4
  50. package/dist/Radio/Radio.stories.d.ts +5 -0
  51. package/dist/Radio/RadioIcon.d.ts +9 -0
  52. package/dist/Select/ListBox.d.ts +9 -0
  53. package/dist/Select/ListBoxSection.d.ts +9 -0
  54. package/dist/Select/Option.d.ts +9 -0
  55. package/dist/Select/Popover.d.ts +9 -0
  56. package/dist/Select/Select.d.ts +25 -4
  57. package/dist/Select/Select.stories.d.ts +5 -0
  58. package/dist/Slider/Slider.d.ts +5 -0
  59. package/dist/Slider/Slider.stories.d.ts +5 -0
  60. package/dist/Stack/Stack.d.ts +1 -3
  61. package/dist/Stack/Stack.stories.d.ts +5 -0
  62. package/dist/Text/Text.d.ts +17 -10
  63. package/dist/Text/Text.stories.d.ts +5 -0
  64. package/dist/Textarea/Textarea.d.ts +7 -1
  65. package/dist/Textarea/Textarea.stories.d.ts +5 -0
  66. package/dist/ValidationMessage/ValidationMessage.d.ts +5 -0
  67. package/dist/ValidationMessage/ValidationMessage.stories.d.ts +5 -0
  68. package/dist/VisuallyHidden/VisuallyHidden.d.ts +1 -0
  69. package/dist/VisuallyHidden/VisuallyHidden.stories.d.ts +5 -0
  70. package/dist/VisuallyHidden/index.d.ts +1 -0
  71. package/dist/components.cjs.development.js +1075 -562
  72. package/dist/components.cjs.development.js.map +1 -1
  73. package/dist/components.cjs.production.min.js +1 -1
  74. package/dist/components.cjs.production.min.js.map +1 -1
  75. package/dist/components.esm.js +1012 -542
  76. package/dist/components.esm.js.map +1 -1
  77. package/dist/index.d.ts +6 -2
  78. package/dist/theme.d.ts +23 -48
  79. package/package.json +21 -2
  80. package/src/ActionGroup/ActionGroup.stories.tsx +47 -0
  81. package/src/ActionGroup/ActionGroup.test.tsx +83 -0
  82. package/src/ActionGroup/ActionGroup.tsx +32 -0
  83. package/src/ActionGroup/index.ts +1 -0
  84. package/src/Alert/Alert.stories.tsx +32 -0
  85. package/src/Alert/Alert.test.tsx +5 -2
  86. package/src/Alert/Alert.tsx +27 -34
  87. package/src/Badge/Badge.stories.tsx +38 -0
  88. package/src/Badge/Badge.test.tsx +12 -16
  89. package/src/Badge/Badge.tsx +14 -3
  90. package/src/Box.ts +2 -0
  91. package/src/Button/Button.stories.tsx +57 -0
  92. package/src/Button/Button.test.tsx +76 -13
  93. package/src/Button/Button.tsx +61 -18
  94. package/src/Card/Card.stories.tsx +41 -0
  95. package/src/Card/Card.test.tsx +71 -0
  96. package/src/Card/Card.tsx +48 -0
  97. package/src/Card/index.ts +1 -0
  98. package/src/Checkbox/Checkbox.stories.tsx +78 -0
  99. package/src/Checkbox/Checkbox.test.tsx +138 -23
  100. package/src/Checkbox/Checkbox.tsx +81 -52
  101. package/src/Checkbox/CheckboxIcons.tsx +59 -0
  102. package/src/Column/Column.stories.tsx +33 -0
  103. package/src/Column/Column.test.tsx +8 -0
  104. package/src/Column/Column.tsx +12 -2
  105. package/src/Columns/Columns.stories.tsx +75 -0
  106. package/src/Columns/Columns.test.tsx +34 -23
  107. package/src/Columns/Columns.tsx +30 -30
  108. package/src/Container/Container.stories.tsx +14 -0
  109. package/src/Dialog/Dialog.stories.tsx +88 -0
  110. package/src/Dialog/Dialog.test.tsx +129 -18
  111. package/src/Dialog/Dialog.tsx +113 -15
  112. package/src/Dialog/ModalDialog.tsx +76 -0
  113. package/src/Divider/Divider.stories.tsx +30 -0
  114. package/src/Divider/Divider.test.tsx +13 -5
  115. package/src/Divider/Divider.tsx +12 -0
  116. package/src/Field/Field.stories.tsx +110 -0
  117. package/src/Field/Field.test.tsx +74 -33
  118. package/src/Field/Field.tsx +27 -20
  119. package/src/Image/Image.stories.tsx +34 -0
  120. package/src/Image/Image.test.tsx +4 -1
  121. package/src/Image/Image.tsx +13 -1
  122. package/src/Inline/Inline.stories.tsx +39 -0
  123. package/src/Inline/Inline.test.tsx +99 -0
  124. package/src/Inline/Inline.tsx +38 -0
  125. package/src/Inline/index.ts +1 -0
  126. package/src/Input/Input.stories.tsx +54 -0
  127. package/src/Input/Input.test.tsx +7 -3
  128. package/src/Input/Input.tsx +13 -1
  129. package/src/Label/Label.stories.tsx +41 -0
  130. package/src/Label/Label.test.tsx +40 -5
  131. package/src/Label/Label.tsx +54 -8
  132. package/src/Link/Link.stories.tsx +35 -0
  133. package/src/Link/Link.test.tsx +51 -21
  134. package/src/Link/Link.tsx +39 -13
  135. package/src/Menu/Menu.stories.tsx +62 -0
  136. package/src/Menu/Menu.test.tsx +11 -6
  137. package/src/Menu/Menu.tsx +22 -14
  138. package/src/MenuItem/MenuItem.stories.tsx +30 -0
  139. package/src/MenuItem/MenuItem.test.tsx +22 -13
  140. package/src/MenuItem/MenuItem.tsx +19 -10
  141. package/src/Message/Message.stories.tsx +30 -0
  142. package/src/Message/Message.test.tsx +4 -1
  143. package/src/Message/Message.tsx +18 -14
  144. package/src/Provider/MarigoldProvider.test.tsx +136 -0
  145. package/src/Provider/MarigoldProvider.tsx +47 -0
  146. package/src/Provider/index.ts +4 -0
  147. package/src/Radio/Radio.stories.tsx +78 -0
  148. package/src/Radio/Radio.test.tsx +129 -18
  149. package/src/Radio/Radio.tsx +62 -71
  150. package/src/Radio/RadioIcon.tsx +49 -0
  151. package/src/Select/ListBox.tsx +40 -0
  152. package/src/Select/ListBoxSection.tsx +40 -0
  153. package/src/Select/Option.tsx +48 -0
  154. package/src/Select/Popover.tsx +50 -0
  155. package/src/Select/Select.stories.tsx +81 -0
  156. package/src/Select/Select.test.tsx +317 -35
  157. package/src/Select/Select.tsx +162 -18
  158. package/src/Slider/Slider.stories.tsx +24 -0
  159. package/src/Slider/Slider.test.tsx +10 -6
  160. package/src/Slider/Slider.tsx +25 -13
  161. package/src/Stack/Stack.stories.tsx +57 -0
  162. package/src/Stack/Stack.test.tsx +93 -65
  163. package/src/Stack/Stack.tsx +27 -32
  164. package/src/Text/Text.stories.tsx +61 -0
  165. package/src/Text/Text.test.tsx +41 -36
  166. package/src/Text/Text.tsx +56 -31
  167. package/src/Textarea/Textarea.stories.tsx +64 -0
  168. package/src/Textarea/Textarea.test.tsx +11 -8
  169. package/src/Textarea/Textarea.tsx +41 -38
  170. package/src/ValidationMessage/ValidationMessage.stories.tsx +27 -0
  171. package/src/ValidationMessage/ValidationMessage.test.tsx +9 -4
  172. package/src/ValidationMessage/ValidationMessage.tsx +23 -12
  173. package/src/VisuallyHidden/VisuallyHidden.stories.tsx +19 -0
  174. package/src/VisuallyHidden/VisuallyHidden.test.tsx +10 -0
  175. package/src/VisuallyHidden/VisuallyHidden.tsx +1 -0
  176. package/src/VisuallyHidden/index.ts +1 -0
  177. package/src/index.ts +7 -2
  178. package/src/theme.ts +49 -48
  179. package/dist/Box/Box.d.ts +0 -45
  180. package/dist/Box/index.d.ts +0 -1
  181. package/dist/Heading/Heading.d.ts +0 -7
  182. package/dist/Heading/index.d.ts +0 -1
  183. package/dist/Hidden/Hidden.d.ts +0 -5
  184. package/dist/Hidden/index.d.ts +0 -1
  185. package/src/Alert/Alert.stories.mdx +0 -45
  186. package/src/Badge/Badge.stories.mdx +0 -43
  187. package/src/Box/Box.stories.mdx +0 -38
  188. package/src/Box/Box.test.tsx +0 -133
  189. package/src/Box/Box.tsx +0 -152
  190. package/src/Box/index.ts +0 -1
  191. package/src/Button/Button.stories.mdx +0 -176
  192. package/src/Checkbox/Checkbox.stories.mdx +0 -119
  193. package/src/Column/Column.stories.mdx +0 -74
  194. package/src/Columns/Columns.stories.mdx +0 -247
  195. package/src/Container/Container.stories.mdx +0 -36
  196. package/src/Dialog/Dialog.stories.mdx +0 -64
  197. package/src/Divider/Divider.stories.mdx +0 -43
  198. package/src/Field/Field.stories.mdx +0 -57
  199. package/src/Heading/Heading.stories.mdx +0 -91
  200. package/src/Heading/Heading.test.tsx +0 -77
  201. package/src/Heading/Heading.tsx +0 -19
  202. package/src/Heading/index.ts +0 -1
  203. package/src/Hidden/Hidden.stories.mdx +0 -64
  204. package/src/Hidden/Hidden.test.tsx +0 -24
  205. package/src/Hidden/Hidden.tsx +0 -16
  206. package/src/Hidden/index.ts +0 -1
  207. package/src/Image/Image.stories.mdx +0 -40
  208. package/src/Input/Input.stories.mdx +0 -45
  209. package/src/Label/Label.stories.mdx +0 -34
  210. package/src/Link/Link.stories.mdx +0 -38
  211. package/src/Menu/Menu.stories.mdx +0 -49
  212. package/src/MenuItem/MenuItem.stories.mdx +0 -32
  213. package/src/Message/Message.stories.mdx +0 -44
  214. package/src/Radio/Radio.stories.mdx +0 -100
  215. package/src/Select/Select.stories.mdx +0 -44
  216. package/src/Slider/Slider.stories.mdx +0 -58
  217. package/src/Stack/Stack.stories.mdx +0 -105
  218. package/src/Text/Text.stories.mdx +0 -60
  219. package/src/Textarea/Textarea.stories.mdx +0 -65
  220. package/src/ValidationMessage/ValidationMessage.stories.mdx +0 -36
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ import { ResponsiveStyleValue } from '@marigold/system';
3
+ import { ComponentProps } from '@marigold/types';
4
+
5
+ import { Box } from '../Box';
6
+
7
+ // Theme Extension
8
+ // ---------------
9
+ export interface CardThemeExtension<Value> {
10
+ card?: {
11
+ [key: string]: Value;
12
+ };
13
+ }
14
+
15
+ // Props
16
+ // ---------------
17
+ export type CardProps = {
18
+ title?: string;
19
+ width?: ResponsiveStyleValue<string>;
20
+ variant?: string;
21
+ } & ComponentProps<'div'>;
22
+
23
+ // Component
24
+ // ---------------
25
+ export const Card: React.FC<CardProps> = ({
26
+ variant = '',
27
+ title,
28
+ width,
29
+ className,
30
+ children,
31
+ ...props
32
+ }) => {
33
+ return (
34
+ <Box
35
+ {...props}
36
+ variant={`card.${variant}`}
37
+ maxWidth={width}
38
+ className={className}
39
+ >
40
+ {title && (
41
+ <Box as="h2" variant="text.h2" pb="small">
42
+ {title}
43
+ </Box>
44
+ )}
45
+ {children}
46
+ </Box>
47
+ );
48
+ };
@@ -0,0 +1 @@
1
+ export * from './Card';
@@ -0,0 +1,78 @@
1
+ import React, { useState } from 'react';
2
+ import type { Meta, ComponentStory } from '@storybook/react';
3
+
4
+ import { Checkbox } from './Checkbox';
5
+
6
+ export default {
7
+ title: 'Components/Checkbox',
8
+ parameters: {
9
+ actions: {
10
+ handles: ['click'],
11
+ },
12
+ },
13
+ argTypes: {
14
+ variant: {
15
+ control: {
16
+ type: 'text',
17
+ },
18
+ description: 'Checkbox variant',
19
+ defaultValue: '__default',
20
+ },
21
+ labelVariant: {
22
+ control: {
23
+ type: 'text',
24
+ },
25
+ description: 'Checkbox label variant',
26
+ defaultValue: 'inline',
27
+ },
28
+ label: {
29
+ control: {
30
+ type: 'text',
31
+ },
32
+ description: 'Label',
33
+ defaultValue: 'Checkbox Label',
34
+ },
35
+ required: {
36
+ control: {
37
+ type: 'boolean',
38
+ },
39
+ description: 'Required',
40
+ defaultValue: false,
41
+ },
42
+ disabled: {
43
+ control: {
44
+ type: 'boolean',
45
+ },
46
+ description: 'Disabled',
47
+ defaultValue: false,
48
+ },
49
+ error: {
50
+ control: {
51
+ type: 'boolean',
52
+ },
53
+ description: 'Error',
54
+ defaultValue: false,
55
+ },
56
+ errorMessage: {
57
+ control: {
58
+ type: 'text',
59
+ },
60
+ description: 'Error Message',
61
+ },
62
+ },
63
+ } as Meta;
64
+
65
+ export const Basic: ComponentStory<typeof Checkbox> = ({
66
+ onChange,
67
+ checked,
68
+ ...args
69
+ }) => {
70
+ const [isChecked, setChecked] = useState(false);
71
+ return (
72
+ <Checkbox
73
+ onChange={() => setChecked(!isChecked)}
74
+ checked={isChecked}
75
+ {...args}
76
+ />
77
+ );
78
+ };
@@ -1,51 +1,166 @@
1
1
  import React from 'react';
2
- import { render, screen, fireEvent } from '@testing-library/react';
2
+ import { fireEvent, render, screen } from '@testing-library/react';
3
3
  import { Checkbox } from './Checkbox';
4
+ import { ThemeProvider } from '@marigold/system';
5
+
6
+ const theme = {
7
+ space: {
8
+ none: 0,
9
+ small: 2,
10
+ },
11
+ colors: {
12
+ disabled: 'gray',
13
+ },
14
+ checkbox: {
15
+ __default: {
16
+ m: 'small',
17
+ },
18
+ },
19
+ label: {
20
+ inline: {
21
+ fontSize: '14px',
22
+ },
23
+ above: {
24
+ fontSize: '8px',
25
+ },
26
+ },
27
+ };
28
+
29
+ test('supports default labelVariant', () => {
30
+ render(
31
+ <ThemeProvider theme={theme}>
32
+ <Checkbox id="test" title="checkbox" label="label" />
33
+ </ThemeProvider>
34
+ );
35
+
36
+ const label = screen.getByText(/label/);
37
+ expect(label).toHaveStyle(`font-size: 14px`);
38
+ });
39
+
40
+ test('supports other labelVariant than default', () => {
41
+ render(
42
+ <ThemeProvider theme={theme}>
43
+ <Checkbox id="test" title="checkbox" label="label" labelVariant="above" />
44
+ </ThemeProvider>
45
+ );
46
+
47
+ const label = screen.getByText(/label/);
48
+ expect(label).toHaveStyle(`font-size: 8px`);
49
+ });
4
50
 
5
51
  test('supports label prop', () => {
6
52
  render(<Checkbox label="Test" id="test" title="checkbox" />);
7
- const checkbox = screen.getByText(/Test/);
8
53
 
9
- expect(checkbox).toBeDefined();
54
+ const checkboxLabel = screen.getByText(/Test/);
55
+ expect(checkboxLabel).toBeDefined();
10
56
  });
11
57
 
12
- test('supports required prop an renders required icon', () => {
58
+ test('supports required prop and renders required icon', () => {
13
59
  render(<Checkbox label="Test" id="test" required title="checkbox" />);
14
- const checkbox = screen.getByText(/Test/);
15
60
 
16
- expect(checkbox).toContainHTML('path d="M10.8');
61
+ const label = screen.getByText(/Test/);
62
+ expect(label.nextSibling).toContainHTML('path d="M10.8');
17
63
  });
18
64
 
19
65
  test('supports default type', () => {
20
- render(<Checkbox id="test" title="checkbox" />);
21
- const checkbox = screen.getByTitle(/checkbox/);
66
+ render(<Checkbox id="checkbox" title="checkbox" label="Test" />);
22
67
 
68
+ const checkbox = screen.getByTitle(/checkbox/);
23
69
  expect(checkbox.getAttribute('type')).toEqual('checkbox');
24
70
  });
25
71
 
26
72
  test('renders <input> element', () => {
27
- render(<Checkbox id="test" title="checkbox" />);
28
- const checkbox = screen.getByTitle(/checkbox/);
73
+ render(<Checkbox id="checkbox" title="checkbox" label="Test" />);
29
74
 
75
+ const checkbox = screen.getByTitle(/checkbox/);
30
76
  expect(checkbox instanceof HTMLInputElement).toBeTruthy();
31
77
  });
32
78
 
33
- test('renders <SVG> CircleUnchecked element', () => {
34
- render(<Checkbox id="checkbox" label="Test" />);
35
- const checkbox = screen.getByText(/Test/);
36
- expect(checkbox).toContainHTML('path d="M19.2917');
79
+ test('supports disabled prop', () => {
80
+ render(
81
+ <ThemeProvider theme={theme}>
82
+ <Checkbox id="test" title="checkbox" label="label" disabled />
83
+ </ThemeProvider>
84
+ );
85
+
86
+ const checkbox = screen.getByTitle(/checkbox/);
87
+ expect(checkbox).toHaveAttribute('disabled');
88
+ const label = screen.getByText(/label/);
89
+ expect(label).toHaveStyle(`color: gray`);
90
+ });
91
+
92
+ test('supports error and errorMessage prop', () => {
93
+ render(
94
+ <ThemeProvider theme={theme}>
95
+ <Checkbox
96
+ id="test"
97
+ title="checkbox"
98
+ label="test"
99
+ error
100
+ errorMessage="error"
101
+ />
102
+ </ThemeProvider>
103
+ );
104
+
105
+ const errorMessage = screen.getByText(/error/);
106
+ expect(errorMessage).toBeDefined();
37
107
  });
38
108
 
39
- test('renders <SVG> CircleChecked element', () => {
40
- render(<Checkbox id="checkbox" label="Test" checked onChange={() => {}} />);
41
- const checkbox = screen.getByText(/Test/);
42
- expect(checkbox).toContainHTML('path d="M19.2917');
109
+ test('supports checked checkbox', () => {
110
+ render(
111
+ <ThemeProvider theme={theme}>
112
+ <Checkbox
113
+ id="test"
114
+ title="checkbox"
115
+ label="Test"
116
+ onChange={() => {}}
117
+ checked
118
+ />
119
+ </ThemeProvider>
120
+ );
121
+
122
+ const checkbox = screen.getByTitle(/checkbox/);
123
+ expect(checkbox).toHaveAttribute('checked');
43
124
  });
44
125
 
45
- test('change state onClick', () => {
46
- render(<Checkbox id="checkbox" label="Test" />);
47
- const checkbox = screen.getByText(/Test/);
48
- expect(checkbox).toContainHTML('path d="M19.2917');
126
+ test('supports checked and disabled checkbox', () => {
127
+ render(
128
+ <ThemeProvider theme={theme}>
129
+ <Checkbox
130
+ id="test"
131
+ title="checkbox"
132
+ label="Test"
133
+ onChange={() => {}}
134
+ checked
135
+ disabled
136
+ />
137
+ </ThemeProvider>
138
+ );
139
+
140
+ const checkbox = screen.getByTitle(/checkbox/);
141
+ expect(checkbox).toHaveAttribute('checked');
142
+ expect(checkbox).toHaveAttribute('disabled');
143
+ });
144
+
145
+ test('correctly handles interaction', () => {
146
+ const click = jest.fn();
147
+ const change = jest.fn();
148
+
149
+ render(
150
+ <ThemeProvider theme={theme}>
151
+ <Checkbox
152
+ id="test"
153
+ title="checkbox"
154
+ label="Test"
155
+ onClick={click}
156
+ onChange={change}
157
+ />
158
+ </ThemeProvider>
159
+ );
160
+
161
+ const checkbox = screen.getByTitle(/checkbox/);
49
162
  fireEvent.click(checkbox);
50
- expect(checkbox).toContainHTML('path d="M19.2917');
163
+
164
+ expect(click).toHaveBeenCalledTimes(1);
165
+ expect(change).toHaveBeenCalledTimes(1);
51
166
  });
@@ -1,71 +1,100 @@
1
1
  import React from 'react';
2
- import { Required, SquareUnchecked, SquareChecked } from '@marigold/icons';
3
- import { useStyles } from '@marigold/system';
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';
7
+
4
8
  import { ComponentProps } from '@marigold/types';
9
+ import { Exclamation } from '@marigold/icons';
5
10
 
11
+ import { CheckboxIcon, CheckboxIconProps } from './CheckboxIcons';
6
12
  import { Box } from '../Box';
7
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
+ }
23
+
24
+ // Checkbox Input
25
+ // ---------------
26
+ type CheckboxInputProps = CheckboxIconProps &
27
+ ToggleProps &
28
+ ComponentProps<'input'>;
29
+
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();
8
35
 
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
+ };
58
+
59
+ // Checkbox
60
+ // ---------------
9
61
  export type CheckboxProps = {
10
62
  id: string;
11
- variant?: string;
12
- label?: string;
13
- } & Omit<ComponentProps<'input'>, 'type' | 'id'>;
63
+ label: string;
64
+ required?: boolean;
65
+ labelVariant?: string;
66
+ error?: boolean;
67
+ errorMessage?: string;
68
+ } & CheckboxInputProps;
14
69
 
15
70
  export const Checkbox: React.FC<CheckboxProps> = ({
16
- id,
17
- variant = 'default',
18
71
  label,
19
72
  required,
20
- className,
73
+ labelVariant = 'inline',
74
+ error,
75
+ errorMessage,
21
76
  ...props
22
77
  }) => {
23
- const checkboxStyles = useStyles({
24
- css: {
25
- position: 'absolute',
26
- opacity: 0,
27
- zIndex: -1,
28
- width: 1,
29
- height: 1,
30
- overflow: 'hidden',
31
- },
32
- });
33
-
34
- const checkboxIconStyles = useStyles({
35
- variant: `checkbox.${variant}`,
36
- css: {
37
- mr: 2,
38
- verticalAlign: 'middle',
39
- ':hover': { cursor: 'pointer' },
40
- 'input:disabled ~ &': {
41
- color: 'muted',
42
- cursor: 'not-allowed',
43
- },
44
- },
45
- className,
46
- });
47
-
48
- const checkbox = (
49
- <Box display="inline-block">
50
- <input type="checkbox" className={checkboxStyles} {...props} />
51
- {props.checked ? (
52
- <SquareChecked aria-hidden="true" className={checkboxIconStyles} />
53
- ) : (
54
- <SquareUnchecked aria-hidden="true" className={checkboxIconStyles} />
55
- )}
56
- </Box>
57
- );
58
-
59
78
  return (
60
79
  <>
61
- {label ? (
62
- <Label htmlFor={id}>
63
- {checkbox}
64
- {label}
65
- {required ? <Required size={16} /> : ''}
66
- </Label>
67
- ) : (
68
- <>{checkbox}</>
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>
69
98
  )}
70
99
  </>
71
100
  );
@@ -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
+ );
@@ -22,3 +22,11 @@ test('accepts custom styles prop className', () => {
22
22
 
23
23
  expect(column.className).toMatch('custom-class-name');
24
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,9 +1,19 @@
1
1
  import React from 'react';
2
2
  import { Box } from '../Box';
3
3
 
4
+ type WidthValues = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
5
+
4
6
  export type ColumnProps = {
5
7
  className?: string;
6
- width?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
8
+ width?: WidthValues | WidthValues[];
9
+ };
10
+
11
+ const transform = (width: WidthValues | WidthValues[]) => {
12
+ if (Array.isArray(width)) {
13
+ return width.map(v => `${(v / 12) * 100}%`);
14
+ }
15
+
16
+ return `${(width / 12) * 100}%`;
7
17
  };
8
18
 
9
19
  export const Column: React.FC<ColumnProps> = ({
@@ -11,7 +21,7 @@ export const Column: React.FC<ColumnProps> = ({
11
21
  children,
12
22
  ...props
13
23
  }) => (
14
- <Box {...props} width={`${(width / 12) * 100}%`}>
24
+ <Box {...props} width={transform(width)}>
15
25
  {children}
16
26
  </Box>
17
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
+ );