@marigold/components 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/ActionGroup/ActionGroup.d.ts +9 -0
  2. package/dist/ActionGroup/index.d.ts +1 -0
  3. package/dist/Alert/Alert.d.ts +20 -2
  4. package/dist/Badge/Badge.d.ts +8 -0
  5. package/dist/Badge/index.d.ts +1 -0
  6. package/dist/Box/Box.d.ts +47 -0
  7. package/dist/Box/index.d.ts +1 -0
  8. package/dist/Button/Button.d.ts +4 -3
  9. package/dist/Card/Card.d.ts +9 -0
  10. package/dist/Card/index.d.ts +1 -0
  11. package/dist/Checkbox/Checkbox.d.ts +14 -2
  12. package/dist/Checkbox/CheckboxIcons.d.ts +9 -0
  13. package/dist/Column/Column.d.ts +8 -0
  14. package/dist/Column/index.d.ts +1 -0
  15. package/dist/Columns/Columns.d.ts +10 -0
  16. package/dist/Columns/index.d.ts +1 -0
  17. package/dist/Container/Container.d.ts +6 -0
  18. package/dist/Container/index.d.ts +1 -0
  19. package/dist/Dialog/Dialog.d.ts +14 -0
  20. package/dist/Dialog/ModalDialog.d.ts +5 -0
  21. package/dist/Dialog/index.d.ts +1 -0
  22. package/dist/Divider/Divider.d.ts +7 -0
  23. package/dist/Divider/index.d.ts +1 -0
  24. package/dist/Field/Field.d.ts +11 -0
  25. package/dist/Field/index.d.ts +1 -0
  26. package/dist/Heading/Heading.d.ts +7 -5
  27. package/dist/Hidden/Hidden.d.ts +5 -0
  28. package/dist/Hidden/index.d.ts +1 -0
  29. package/dist/Image/Image.d.ts +7 -0
  30. package/dist/Image/index.d.ts +1 -0
  31. package/dist/Input/Input.d.ts +6 -0
  32. package/dist/Input/index.d.ts +1 -0
  33. package/dist/Label/Label.d.ts +8 -5
  34. package/dist/Link/Link.d.ts +7 -3
  35. package/dist/Menu/Menu.d.ts +12 -0
  36. package/dist/Menu/index.d.ts +1 -0
  37. package/dist/MenuItem/MenuItem.d.ts +7 -0
  38. package/dist/MenuItem/index.d.ts +1 -0
  39. package/dist/Message/Message.d.ts +7 -0
  40. package/dist/Message/index.d.ts +1 -0
  41. package/dist/Provider/MarigoldProvider.d.ts +3 -0
  42. package/dist/Provider/index.d.ts +3 -0
  43. package/dist/Radio/Radio.d.ts +14 -2
  44. package/dist/Radio/RadioIcons.d.ts +9 -0
  45. package/dist/Select/ListBox.d.ts +8 -0
  46. package/dist/Select/ListBoxSection.d.ts +8 -0
  47. package/dist/Select/Option.d.ts +8 -0
  48. package/dist/Select/Popover.d.ts +9 -0
  49. package/dist/Select/Select.d.ts +13 -3
  50. package/dist/Slider/Slider.d.ts +6 -3
  51. package/dist/Stack/Stack.d.ts +7 -0
  52. package/dist/Stack/index.d.ts +1 -0
  53. package/dist/Text/Text.d.ts +12 -3
  54. package/dist/Textarea/Textarea.d.ts +11 -3
  55. package/dist/ValidationMessage/ValidationMessage.d.ts +6 -0
  56. package/dist/ValidationMessage/index.d.ts +1 -0
  57. package/dist/components.cjs.development.js +1308 -195
  58. package/dist/components.cjs.development.js.map +1 -1
  59. package/dist/components.cjs.production.min.js +1 -1
  60. package/dist/components.cjs.production.min.js.map +1 -1
  61. package/dist/components.esm.js +1267 -185
  62. package/dist/components.esm.js.map +1 -1
  63. package/dist/index.d.ts +21 -4
  64. package/dist/theme.d.ts +24 -4
  65. package/package.json +24 -4
  66. package/src/ActionGroup/ActionGroup.stories.mdx +62 -0
  67. package/src/ActionGroup/ActionGroup.test.tsx +83 -0
  68. package/src/ActionGroup/ActionGroup.tsx +43 -0
  69. package/src/ActionGroup/index.ts +1 -0
  70. package/src/Alert/Alert.stories.mdx +30 -42
  71. package/src/Alert/Alert.test.tsx +37 -22
  72. package/src/Alert/Alert.tsx +31 -21
  73. package/src/Badge/Badge.stories.mdx +57 -0
  74. package/src/Badge/Badge.test.tsx +61 -0
  75. package/src/Badge/Badge.tsx +25 -0
  76. package/src/Badge/index.ts +1 -0
  77. package/src/Box/Box.stories.mdx +334 -0
  78. package/src/Box/Box.test.tsx +133 -0
  79. package/src/Box/Box.tsx +165 -0
  80. package/src/Box/index.ts +1 -0
  81. package/src/Button/Button.stories.mdx +58 -134
  82. package/src/Button/Button.test.tsx +65 -23
  83. package/src/Button/Button.tsx +48 -14
  84. package/src/Card/Card.stories.mdx +49 -0
  85. package/src/Card/Card.test.tsx +66 -0
  86. package/src/Card/Card.tsx +36 -0
  87. package/src/Card/index.ts +1 -0
  88. package/src/Checkbox/Checkbox.stories.mdx +79 -101
  89. package/src/Checkbox/Checkbox.test.tsx +73 -32
  90. package/src/Checkbox/Checkbox.tsx +114 -35
  91. package/src/Checkbox/CheckboxIcons.tsx +49 -0
  92. package/src/Column/Column.stories.mdx +49 -0
  93. package/src/Column/Column.test.tsx +32 -0
  94. package/src/Column/Column.tsx +27 -0
  95. package/src/Column/index.ts +1 -0
  96. package/src/Columns/Columns.stories.mdx +65 -0
  97. package/src/Columns/Columns.test.tsx +102 -0
  98. package/src/Columns/Columns.tsx +69 -0
  99. package/src/Columns/index.ts +1 -0
  100. package/src/Container/Container.stories.mdx +19 -0
  101. package/src/Container/Container.test.tsx +26 -0
  102. package/src/Container/Container.tsx +13 -0
  103. package/src/Container/index.ts +1 -0
  104. package/src/Dialog/Dialog.stories.mdx +73 -0
  105. package/src/Dialog/Dialog.test.tsx +87 -0
  106. package/src/Dialog/Dialog.tsx +84 -0
  107. package/src/Dialog/ModalDialog.tsx +47 -0
  108. package/src/Dialog/index.ts +1 -0
  109. package/src/Divider/Divider.stories.mdx +37 -0
  110. package/src/Divider/Divider.test.tsx +63 -0
  111. package/src/Divider/Divider.tsx +13 -0
  112. package/src/Divider/index.ts +1 -0
  113. package/src/Field/Field.stories.mdx +97 -0
  114. package/src/Field/Field.test.tsx +80 -0
  115. package/src/Field/Field.tsx +54 -0
  116. package/src/Field/index.ts +1 -0
  117. package/src/Heading/Heading.stories.mdx +36 -76
  118. package/src/Heading/Heading.test.tsx +31 -17
  119. package/src/Heading/Heading.tsx +15 -12
  120. package/src/Hidden/Hidden.stories.mdx +39 -0
  121. package/src/Hidden/Hidden.test.tsx +24 -0
  122. package/src/Hidden/Hidden.tsx +16 -0
  123. package/src/Hidden/index.ts +1 -0
  124. package/src/Image/Image.stories.mdx +36 -0
  125. package/src/Image/Image.test.tsx +70 -0
  126. package/src/Image/Image.tsx +13 -0
  127. package/src/Image/index.ts +1 -0
  128. package/src/Input/Input.stories.mdx +61 -0
  129. package/src/Input/Input.test.tsx +70 -0
  130. package/src/Input/Input.tsx +13 -0
  131. package/src/Input/index.ts +1 -0
  132. package/src/Label/Label.stories.mdx +50 -34
  133. package/src/Label/Label.test.tsx +45 -16
  134. package/src/Label/Label.tsx +26 -17
  135. package/src/Link/Link.stories.mdx +40 -31
  136. package/src/Link/Link.test.tsx +53 -28
  137. package/src/Link/Link.tsx +32 -14
  138. package/src/Menu/Menu.stories.mdx +81 -0
  139. package/src/Menu/Menu.test.tsx +79 -0
  140. package/src/Menu/Menu.tsx +41 -0
  141. package/src/Menu/index.ts +1 -0
  142. package/src/MenuItem/MenuItem.stories.mdx +37 -0
  143. package/src/MenuItem/MenuItem.test.tsx +63 -0
  144. package/src/MenuItem/MenuItem.tsx +23 -0
  145. package/src/MenuItem/index.ts +1 -0
  146. package/src/Message/Message.stories.mdx +44 -0
  147. package/src/Message/Message.test.tsx +87 -0
  148. package/src/Message/Message.tsx +43 -0
  149. package/src/Message/index.ts +1 -0
  150. package/src/Provider/MarigoldProvider.test.tsx +126 -0
  151. package/src/Provider/MarigoldProvider.tsx +29 -0
  152. package/src/Provider/index.ts +3 -0
  153. package/src/Radio/Radio.stories.mdx +80 -83
  154. package/src/Radio/Radio.test.tsx +63 -22
  155. package/src/Radio/Radio.tsx +110 -35
  156. package/src/Radio/RadioIcons.tsx +39 -0
  157. package/src/Select/ListBox.tsx +39 -0
  158. package/src/Select/ListBoxSection.tsx +40 -0
  159. package/src/Select/Option.tsx +48 -0
  160. package/src/Select/Popover.tsx +50 -0
  161. package/src/Select/Select.stories.mdx +72 -37
  162. package/src/Select/Select.test.tsx +271 -28
  163. package/src/Select/Select.tsx +158 -23
  164. package/src/Slider/Slider.stories.mdx +26 -54
  165. package/src/Slider/Slider.test.tsx +13 -13
  166. package/src/Slider/Slider.tsx +20 -18
  167. package/src/Stack/Stack.stories.mdx +51 -0
  168. package/src/Stack/Stack.test.tsx +129 -0
  169. package/src/Stack/Stack.tsx +39 -0
  170. package/src/Stack/index.ts +1 -0
  171. package/src/Text/Text.stories.mdx +53 -47
  172. package/src/Text/Text.test.tsx +55 -15
  173. package/src/Text/Text.tsx +44 -10
  174. package/src/Textarea/Textarea.stories.mdx +68 -21
  175. package/src/Textarea/Textarea.test.tsx +47 -16
  176. package/src/Textarea/Textarea.tsx +46 -14
  177. package/src/ValidationMessage/ValidationMessage.stories.mdx +36 -0
  178. package/src/ValidationMessage/ValidationMessage.test.tsx +63 -0
  179. package/src/ValidationMessage/ValidationMessage.tsx +28 -0
  180. package/src/ValidationMessage/index.ts +1 -0
  181. package/src/index.ts +22 -4
  182. package/src/theme.ts +24 -4
  183. package/dist/Svg/Svg.d.ts +0 -5
  184. package/dist/Svg/index.d.ts +0 -1
  185. package/dist/TextInput/TextInput.d.ts +0 -3
  186. package/dist/TextInput/index.d.ts +0 -1
  187. package/src/Svg/Svg.stories.mdx +0 -47
  188. package/src/Svg/Svg.test.tsx +0 -58
  189. package/src/Svg/Svg.tsx +0 -25
  190. package/src/Svg/index.ts +0 -1
  191. package/src/TextInput/TextInput.stories.mdx +0 -37
  192. package/src/TextInput/TextInput.test.tsx +0 -71
  193. package/src/TextInput/TextInput.tsx +0 -21
  194. package/src/TextInput/index.ts +0 -1
@@ -1,16 +1,50 @@
1
- import React from 'react';
2
- import { Box, system } from '@marigold/system';
1
+ import React, { forwardRef, RefObject } from 'react';
2
+ import { useButton } from '@react-aria/button';
3
+ import {
4
+ PolymorphicComponentWithRef,
5
+ PolymorphicPropsWithRef,
6
+ } from '@marigold/types';
3
7
 
4
- type ButtonProps = {};
8
+ import { Box, BoxOwnProps } from '../Box';
5
9
 
6
- export const Button = system<ButtonProps, 'button'>(
7
- ({ variant = 'primary.large', children, ...props }) => {
8
- return (
9
- <Box as="button" themeSection="button" variant={variant} {...props}>
10
- <span style={{ display: 'inline-flex', alignItems: 'center' }}>
11
- {children}
12
- </span>
13
- </Box>
14
- );
15
- }
16
- );
10
+ export type ButtonProps = PolymorphicPropsWithRef<BoxOwnProps, 'button'>;
11
+
12
+ export const Button: PolymorphicComponentWithRef<BoxOwnProps, 'button'> =
13
+ forwardRef(
14
+ (
15
+ {
16
+ as = 'button',
17
+ variant = 'primary',
18
+ size = 'large',
19
+ disabled,
20
+ children,
21
+ className,
22
+ ...props
23
+ },
24
+ ref
25
+ ) => {
26
+ const { buttonProps } = useButton(
27
+ {
28
+ ...props,
29
+ elementType: typeof as === 'string' ? as : 'span',
30
+ isDisabled: disabled,
31
+ },
32
+ ref as RefObject<HTMLSpanElement>
33
+ );
34
+
35
+ return (
36
+ <Box
37
+ {...buttonProps}
38
+ {...props}
39
+ as={as}
40
+ variant={[`button.${variant}`, `button.${size}`]}
41
+ className={className}
42
+ ref={ref}
43
+ >
44
+ <Box as="span" display="inline-flex" alignItems="center">
45
+ {children}
46
+ </Box>
47
+ </Box>
48
+ );
49
+ }
50
+ );
@@ -0,0 +1,49 @@
1
+ import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
2
+ import { Heading } from '../Heading';
3
+ import { Card } from './Card';
4
+ import { Text } from '../Text';
5
+
6
+ <Meta
7
+ title="Components/Card"
8
+ argTypes={{
9
+ variant: {
10
+ control: {
11
+ type: 'text',
12
+ },
13
+ table: {
14
+ defaultValue: {
15
+ summary: 'default',
16
+ },
17
+ },
18
+ },
19
+ title: {
20
+ control: {
21
+ type: 'text',
22
+ },
23
+ description: 'card title',
24
+ },
25
+ width: {
26
+ control: {
27
+ type: 'text',
28
+ },
29
+ description: 'max width of the card',
30
+ },
31
+ }}
32
+ />
33
+
34
+ # Card
35
+
36
+ export const Template = args => (
37
+ <Card title="Card" {...args}>
38
+ <Text>
39
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
40
+ dignissim dapibus elit.
41
+ </Text>
42
+ </Card>
43
+ );
44
+
45
+ <Canvas>
46
+ <Story name="Default">{Template.bind({})}</Story>
47
+ </Canvas>
48
+
49
+ <ArgsTable story="Default" />
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { ThemeProvider } from '@marigold/system';
4
+
5
+ import { Card } from './Card';
6
+
7
+ const theme = {
8
+ card: {
9
+ default: {
10
+ p: '8px',
11
+ },
12
+ custom: {
13
+ p: '4px',
14
+ },
15
+ },
16
+ };
17
+
18
+ test('supports default variant', () => {
19
+ render(
20
+ <ThemeProvider theme={theme}>
21
+ <Card>card</Card>
22
+ </ThemeProvider>
23
+ );
24
+ const card = screen.getByText(/card/);
25
+ expect(card).toHaveStyle(`padding: 8px`);
26
+ });
27
+
28
+ test('supports other variant than default', () => {
29
+ render(
30
+ <ThemeProvider theme={theme}>
31
+ <Card variant="custom">card</Card>
32
+ </ThemeProvider>
33
+ );
34
+ const card = screen.getByText(/card/);
35
+ expect(card).toHaveStyle(`padding: 4px`);
36
+ });
37
+
38
+ test('accepts title prop', () => {
39
+ render(
40
+ <ThemeProvider theme={theme}>
41
+ <Card title="title">content</Card>
42
+ </ThemeProvider>
43
+ );
44
+ const title = screen.getByText(/title/);
45
+ expect(title).toBeDefined();
46
+ });
47
+
48
+ test('accepts width prop', () => {
49
+ render(
50
+ <ThemeProvider theme={theme}>
51
+ <Card width="320px">content</Card>
52
+ </ThemeProvider>
53
+ );
54
+ const card = screen.getByText(/content/);
55
+ expect(card).toHaveStyle(`maxWidth: 320px`);
56
+ });
57
+
58
+ test('renders correct HTMl element', () => {
59
+ render(
60
+ <ThemeProvider theme={theme}>
61
+ <Card>card</Card>
62
+ </ThemeProvider>
63
+ );
64
+ const card = screen.getByText(/card/);
65
+ expect(card instanceof HTMLDivElement).toBeTruthy();
66
+ });
@@ -0,0 +1,36 @@
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
+ export type CardProps = {
8
+ title?: string;
9
+ width?: ResponsiveStyleValue<string>;
10
+ variant?: string;
11
+ } & ComponentProps<'div'>;
12
+
13
+ export const Card: React.FC<CardProps> = ({
14
+ variant = 'default',
15
+ title,
16
+ width,
17
+ className,
18
+ children,
19
+ ...props
20
+ }) => {
21
+ return (
22
+ <Box
23
+ {...props}
24
+ variant={`card.${variant}`}
25
+ maxWidth={width}
26
+ className={className}
27
+ >
28
+ {title && (
29
+ <Box as="h2" variant="text.h2" pb="small">
30
+ {title}
31
+ </Box>
32
+ )}
33
+ {children}
34
+ </Box>
35
+ );
36
+ };
@@ -0,0 +1 @@
1
+ export * from './Card';
@@ -1,108 +1,86 @@
1
- import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
2
- import { Label, Checkbox } from '@marigold/components';
1
+ import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
2
+ import { Checkbox } from './Checkbox';
3
3
  import { useState } from 'react';
4
4
 
5
- <Meta title="Components/Form/Checkbox" />
5
+ <Meta
6
+ title="Components/Checkbox"
7
+ parameters={{
8
+ actions: {
9
+ handles: ['click'],
10
+ },
11
+ }}
12
+ argTypes={{
13
+ id: {
14
+ control: {
15
+ type: 'text',
16
+ },
17
+ type: { required: true },
18
+ description: 'Unique ID',
19
+ },
20
+ variant: {
21
+ control: {
22
+ type: 'text',
23
+ },
24
+ description: 'Checkbox variant',
25
+ table: {
26
+ defaultValue: {
27
+ summary: 'default',
28
+ },
29
+ },
30
+ },
31
+ label: {
32
+ control: {
33
+ type: 'text',
34
+ },
35
+ description: 'Label',
36
+ },
37
+ required: {
38
+ control: {
39
+ type: 'boolean',
40
+ },
41
+ description: 'Require',
42
+ table: {
43
+ defaultValue: {
44
+ summary: false,
45
+ },
46
+ },
47
+ },
48
+ error: {
49
+ control: {
50
+ type: 'boolean',
51
+ },
52
+ description: 'Error',
53
+ table: {
54
+ defaultValue: {
55
+ summary: false,
56
+ },
57
+ },
58
+ },
59
+ errorMessage: {
60
+ control: {
61
+ type: 'text',
62
+ },
63
+ description: 'Error Message',
64
+ },
65
+ }}
66
+ />
6
67
 
7
68
  # Checkbox
8
69
 
9
- ## Description
70
+ export const Template = ({ onChange, checked, ...args }) => {
71
+ const [isChecked, setChecked] = useState(false);
72
+ return (
73
+ <Checkbox
74
+ onChange={() => setChecked(!isChecked)}
75
+ checked={isChecked}
76
+ label="Checkbox Label"
77
+ {...args}
78
+ />
79
+ );
80
+ };
10
81
 
11
- With the Checkbox component you can add a HTML `<input>` element with `type="checkbox"` to your form.
12
- The element uses always the themeSection with the name: `form` in your given theme. The variant in your section can be added with the variant prop. The default variant is `checkbox`.
13
- Specific css style prop can also be added.
82
+ <Canvas>
83
+ <Story name="Default">{Template.bind({})}</Story>
84
+ </Canvas>
14
85
 
15
- ## Properties
16
-
17
- | Property | Type | Default |
18
- | :-------- | :---------- | :----------- |
19
- | `variant` | `string` | `'checkbox'` |
20
- | `css` | `css props` | |
21
-
22
- ## Import
23
-
24
- ```tsx
25
- import { Checkbox } from '@marigold/components';
26
- ```
27
-
28
- ## Usage
29
-
30
- ### Checkbox standard labeled
31
-
32
- <Preview>
33
- <Story name="CheckboxOne">
34
- {() => {
35
- const [state, setState] = React.useState({
36
- bi: false,
37
- ca: false,
38
- bo: false,
39
- je: false,
40
- });
41
- const onChange = changeEvent => {
42
- setState({
43
- ...state,
44
- [changeEvent.target.name]: changeEvent.target.checked,
45
- });
46
- };
47
- return (
48
- <div>
49
- <Label htmlFor="bi">
50
- <Checkbox
51
- id="bi"
52
- name="bi"
53
- onChange={onChange}
54
- checked={state.bi}
55
- value="Bike"
56
- />
57
- Bike
58
- </Label>
59
- <br />
60
- <Label htmlFor="ca">
61
- <Checkbox
62
- id="ca"
63
- name="ca"
64
- onChange={onChange}
65
- checked={state.ca}
66
- value="Car"
67
- />
68
- Car
69
- </Label>
70
- <br />
71
- <Label htmlFor="bo">
72
- <Checkbox
73
- id="bo"
74
- name="bo"
75
- onChange={onChange}
76
- checked={state.bo}
77
- value="Boat"
78
- />
79
- Boat
80
- </Label>
81
- <br />
82
- <Label htmlFor="je">
83
- <Checkbox
84
- id="je"
85
- name="je"
86
- onChange={onChange}
87
- checked={state.je}
88
- value="Jet"
89
- />
90
- Jet
91
- </Label>
92
- </div>
93
- );
94
- }}
95
- </Story>
96
- </Preview>
97
-
98
- ### Checkbox checked and disabled
99
-
100
- <Preview>
101
- <Story name="CheckboxTwo">
102
- <div>
103
- <Checkbox checked />
104
- <Checkbox disabled />
105
- <Checkbox checked disabled />
106
- </div>
107
- </Story>
108
- </Preview>
86
+ <ArgsTable story="Default" />
@@ -1,56 +1,97 @@
1
1
  import React from 'react';
2
- import { render, screen, fireEvent } from '@testing-library/react';
3
- import { Label, Checkbox } from '@marigold/components';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { Checkbox } from './Checkbox';
4
+ import { ThemeProvider } from '@marigold/system';
4
5
 
5
- test('supports default type', () => {
6
- render(<Checkbox title="checkbox" />);
7
- const checkbox = screen.getByTitle(/checkbox/);
6
+ const theme = {
7
+ checkbox: {
8
+ default: {
9
+ m: '2px',
10
+ },
11
+ },
12
+ };
8
13
 
9
- expect(checkbox.getAttribute('type')).toEqual('checkbox');
14
+ test('supports label prop', () => {
15
+ render(<Checkbox label="Test" id="test" title="checkbox" />);
16
+
17
+ const checkboxLabel = screen.getByText(/Test/);
18
+ expect(checkboxLabel).toBeDefined();
10
19
  });
11
20
 
12
- test('variant styles cannot be overridden with CSS prop', () => {
13
- render(<Checkbox title="checkbox" css={{ color: 'blue' }} />);
14
- const checkbox = screen.getByTitle(/checkbox/);
21
+ test('supports required prop and renders required icon', () => {
22
+ render(<Checkbox label="Test" id="test" required title="checkbox" />);
15
23
 
16
- expect(checkbox).not.toHaveStyle('color: blue');
24
+ const label = screen.getByText(/Test/);
25
+ expect(label.nextSibling).toContainHTML('path d="M10.8');
17
26
  });
18
27
 
19
- test('renders <input> element', () => {
20
- render(<Checkbox title="checkbox" />);
28
+ test('supports default type', () => {
29
+ render(<Checkbox id="checkbox" title="checkbox" />);
30
+
21
31
  const checkbox = screen.getByTitle(/checkbox/);
32
+ expect(checkbox.getAttribute('type')).toEqual('checkbox');
33
+ });
34
+
35
+ test('renders <input> element', () => {
36
+ render(<Checkbox id="checkbox" title="checkbox" />);
22
37
 
38
+ const checkbox = screen.getByTitle(/checkbox/);
23
39
  expect(checkbox instanceof HTMLInputElement).toBeTruthy();
24
40
  });
25
41
 
26
- test('renders <SVG> CircleUnchecked element', () => {
42
+ test('supports disabled prop', () => {
43
+ render(
44
+ <ThemeProvider theme={theme}>
45
+ <Checkbox id="test" title="checkbox" label="label" disabled />
46
+ </ThemeProvider>
47
+ );
48
+
49
+ const checkbox = screen.getByTitle(/checkbox/);
50
+ expect(checkbox).toHaveAttribute('disabled');
51
+ });
52
+
53
+ test('supports error and errorMessage prop', () => {
27
54
  render(
28
- <Label htmlFor="checkbox">
29
- <Checkbox id="checkbox" /> Test
30
- </Label>
55
+ <ThemeProvider theme={theme}>
56
+ <Checkbox
57
+ id="test"
58
+ title="checkbox"
59
+ label="test"
60
+ error
61
+ errorMessage="error"
62
+ />
63
+ </ThemeProvider>
31
64
  );
32
- const checkbox = screen.getByText(/Test/);
33
- expect(checkbox).toContainHTML('path d="M19.2917');
65
+
66
+ const errorMessage = screen.getByText(/error/);
67
+ expect(errorMessage).toBeDefined();
34
68
  });
35
69
 
36
- test('renders <SVG> CircleChecked element', () => {
70
+ test('supports checked checkbox', () => {
37
71
  render(
38
- <Label htmlFor="checkbox">
39
- <Checkbox id="checkbox" checked /> Test
40
- </Label>
72
+ <ThemeProvider theme={theme}>
73
+ <Checkbox id="test" title="checkbox" onChange={() => {}} checked />
74
+ </ThemeProvider>
41
75
  );
42
- const checkbox = screen.getByText(/Test/);
43
- expect(checkbox).toContainHTML('path d="M19.2917');
76
+
77
+ const checkbox = screen.getByTitle(/checkbox/);
78
+ expect(checkbox).toBeDefined();
44
79
  });
45
80
 
46
- test('change state onClick ', () => {
81
+ test('supports checked and disabled checkbox', () => {
47
82
  render(
48
- <Label htmlFor="checkbox">
49
- <Checkbox id="checkbox" /> Test
50
- </Label>
83
+ <ThemeProvider theme={theme}>
84
+ <Checkbox
85
+ id="test"
86
+ title="checkbox"
87
+ onChange={() => {}}
88
+ checked
89
+ disabled
90
+ />
91
+ </ThemeProvider>
51
92
  );
52
- const checkbox = screen.getByText(/Test/);
53
- expect(checkbox).toContainHTML('path d="M19.2917');
54
- fireEvent.click(checkbox);
55
- expect(checkbox).toContainHTML('path d="M19.2917');
93
+
94
+ const checkbox = screen.getByTitle(/checkbox/);
95
+ expect(checkbox).toBeDefined();
96
+ expect(checkbox).toHaveAttribute('disabled');
56
97
  });
@@ -1,42 +1,121 @@
1
1
  import React from 'react';
2
- import { Box, system } from '@marigold/system';
3
- import { SquareUnchecked, SquareChecked } from '@marigold/icons';
2
+ import { ComponentProps } from '@marigold/types';
3
+ import { Exclamation } from '@marigold/icons';
4
4
 
5
- type CheckboxProps = {};
5
+ import { CheckboxChecked, CheckboxUnchecked } from './CheckboxIcons';
6
6
 
7
- export const Checkbox = system<CheckboxProps, 'input'>(
8
- ({ variant = 'checkbox', ...props }) => {
7
+ import { Box } from '../Box';
8
+ import { Label } from '../Label';
9
+ import { ValidationMessage } from '../ValidationMessage';
10
+
11
+ // Checkbox Icon
12
+ // ---------------
13
+ type CheckboxIconProps = {
14
+ variant?: string;
15
+ checked?: boolean;
16
+ disabled?: boolean;
17
+ children?: never;
18
+ error?: boolean;
19
+ };
20
+
21
+ const CheckboxIcon: React.FC<CheckboxIconProps> = ({
22
+ variant,
23
+ checked,
24
+ disabled,
25
+ error,
26
+ }) => {
27
+ if (checked) {
9
28
  return (
10
- <Box css={{ display: 'inline-block' }}>
11
- <Box
12
- as="input"
13
- type="checkbox"
14
- {...props}
15
- css={{
16
- position: 'absolute',
17
- opacity: 0,
18
- zIndex: -1,
19
- width: 1,
20
- height: 1,
21
- overflow: 'hidden',
22
- }}
23
- />
24
- <Box
25
- as={props.checked ? SquareChecked : SquareUnchecked}
26
- aria-hidden="true"
27
- themeSection="form"
28
- variant={variant}
29
- css={{
30
- mr: 2,
31
- verticalAlign: 'middle',
32
- ':hover': { cursor: 'pointer' },
33
- 'input:disabled ~ &': {
34
- color: 'muted',
35
- cursor: 'not-allowed',
36
- },
37
- }}
38
- />
39
- </Box>
29
+ <Box
30
+ as={CheckboxChecked}
31
+ variant={`checkbox.${variant}`}
32
+ disabled={disabled}
33
+ />
40
34
  );
41
35
  }
36
+ return (
37
+ <Box
38
+ as={CheckboxUnchecked}
39
+ variant={`checkbox.${variant}`}
40
+ disabled={disabled}
41
+ error={error}
42
+ />
43
+ );
44
+ };
45
+
46
+ // Checkbox Input
47
+ // ---------------
48
+ type CheckboxInputProps = {
49
+ variant?: string;
50
+ error?: boolean;
51
+ } & ComponentProps<'input'>;
52
+
53
+ const CheckboxInput: React.FC<CheckboxInputProps> = ({
54
+ className,
55
+ variant = 'default',
56
+ error,
57
+ ...props
58
+ }) => (
59
+ <Box display="inline-block" className={className}>
60
+ <Box
61
+ as="input"
62
+ type="checkbox"
63
+ css={{
64
+ position: 'absolute',
65
+ opacity: 0,
66
+ zIndex: -1,
67
+ width: 1,
68
+ height: 1,
69
+ overflow: 'hidden',
70
+ }}
71
+ {...props}
72
+ />
73
+ <CheckboxIcon
74
+ checked={props.checked}
75
+ variant={variant}
76
+ disabled={props.disabled}
77
+ error={error}
78
+ />
79
+ </Box>
42
80
  );
81
+
82
+ // Checkbox
83
+ // ---------------
84
+ export type CheckboxProps = {
85
+ id: string;
86
+ label?: string;
87
+ required?: boolean;
88
+ error?: boolean;
89
+ errorMessage?: string;
90
+ } & CheckboxInputProps;
91
+
92
+ export const Checkbox: React.FC<CheckboxProps> = ({
93
+ label,
94
+ required,
95
+ error,
96
+ errorMessage,
97
+ ...props
98
+ }) => {
99
+ if (label) {
100
+ return (
101
+ <>
102
+ <Label
103
+ htmlFor={props.id}
104
+ required={required}
105
+ variant={props.disabled ? 'disabled' : 'inline'}
106
+ >
107
+ <Box as={CheckboxInput} pr="8px" error={error} {...props} />
108
+ {label}
109
+ </Label>
110
+ {error && errorMessage && (
111
+ <ValidationMessage>
112
+ <Exclamation size={16} />
113
+ {errorMessage}
114
+ </ValidationMessage>
115
+ )}
116
+ </>
117
+ );
118
+ }
119
+
120
+ return <CheckboxInput {...props} />;
121
+ };