@marigold/components 0.3.0 → 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.
- package/CHANGELOG.md +48 -168
- package/dist/Alert/Alert.d.ts +12 -3
- package/dist/Link/Link.d.ts +1 -1
- package/dist/Radio/Radio.d.ts +3 -5
- package/dist/Radio/Radio.stories.d.ts +5 -0
- package/dist/Radio/RadioIcon.d.ts +9 -0
- package/dist/components.cjs.development.js +76 -113
- package/dist/components.cjs.development.js.map +1 -1
- package/dist/components.cjs.production.min.js +1 -1
- package/dist/components.cjs.production.min.js.map +1 -1
- package/dist/components.esm.js +76 -113
- package/dist/components.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/Link/Link.tsx +2 -1
- package/src/Radio/{Radio.stories.mdx → Radio.stories.tsx} +27 -46
- package/src/Radio/Radio.test.tsx +42 -7
- package/src/Radio/Radio.tsx +49 -89
- package/src/Radio/RadioIcon.tsx +49 -0
- package/dist/Radio/RadioIcons.d.ts +0 -10
- package/src/Checkbox/Checkbox.stories.mdx +0 -97
- package/src/Radio/RadioIcons.tsx +0 -39
package/src/Radio/Radio.test.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
3
|
import { Radio } from './Radio';
|
|
4
4
|
import { ThemeProvider } from '@marigold/system';
|
|
5
5
|
|
|
@@ -8,6 +8,9 @@ const theme = {
|
|
|
8
8
|
none: 0,
|
|
9
9
|
small: 2,
|
|
10
10
|
},
|
|
11
|
+
colors: {
|
|
12
|
+
disabled: 'gray',
|
|
13
|
+
},
|
|
11
14
|
radio: {
|
|
12
15
|
__default: {
|
|
13
16
|
m: 'small',
|
|
@@ -60,14 +63,14 @@ test('supports required prop and renders required icon', () => {
|
|
|
60
63
|
});
|
|
61
64
|
|
|
62
65
|
test('supports default type', () => {
|
|
63
|
-
render(<Radio id="radio" title="radio" />);
|
|
66
|
+
render(<Radio id="radio" title="radio" label="test" />);
|
|
64
67
|
|
|
65
68
|
const radio = screen.getByTitle(/radio/);
|
|
66
69
|
expect(radio.getAttribute('type')).toEqual('radio');
|
|
67
70
|
});
|
|
68
71
|
|
|
69
72
|
test('renders <input> element', () => {
|
|
70
|
-
render(<Radio id="radio" title="radio" />);
|
|
73
|
+
render(<Radio id="radio" title="radio" label="test" />);
|
|
71
74
|
|
|
72
75
|
const radio = screen.getByTitle(/radio/);
|
|
73
76
|
expect(radio instanceof HTMLInputElement).toBeTruthy();
|
|
@@ -82,6 +85,8 @@ test('supports disabled prop', () => {
|
|
|
82
85
|
|
|
83
86
|
const radio = screen.getByTitle(/radio/);
|
|
84
87
|
expect(radio).toHaveAttribute('disabled');
|
|
88
|
+
const label = screen.getByText(/label/);
|
|
89
|
+
expect(label).toHaveStyle(`color: gray`);
|
|
85
90
|
});
|
|
86
91
|
|
|
87
92
|
test('supports error and errorMessage prop', () => {
|
|
@@ -98,22 +103,52 @@ test('supports error and errorMessage prop', () => {
|
|
|
98
103
|
test('supports checked radio', () => {
|
|
99
104
|
render(
|
|
100
105
|
<ThemeProvider theme={theme}>
|
|
101
|
-
<Radio id="test" title="radio" onChange={() => {}} checked />
|
|
106
|
+
<Radio id="test" title="radio" label="test" onChange={() => {}} checked />
|
|
102
107
|
</ThemeProvider>
|
|
103
108
|
);
|
|
104
109
|
|
|
105
110
|
const radio = screen.getByTitle(/radio/);
|
|
106
|
-
expect(radio).
|
|
111
|
+
expect(radio).toHaveAttribute('checked');
|
|
107
112
|
});
|
|
108
113
|
|
|
109
114
|
test('supports checked and disabled radio', () => {
|
|
110
115
|
render(
|
|
111
116
|
<ThemeProvider theme={theme}>
|
|
112
|
-
<Radio
|
|
117
|
+
<Radio
|
|
118
|
+
id="test"
|
|
119
|
+
title="radio"
|
|
120
|
+
label="test"
|
|
121
|
+
onChange={() => {}}
|
|
122
|
+
checked
|
|
123
|
+
disabled
|
|
124
|
+
/>
|
|
113
125
|
</ThemeProvider>
|
|
114
126
|
);
|
|
115
127
|
|
|
116
128
|
const radio = screen.getByTitle(/radio/);
|
|
117
|
-
expect(radio).
|
|
129
|
+
expect(radio).toHaveAttribute('checked');
|
|
118
130
|
expect(radio).toHaveAttribute('disabled');
|
|
119
131
|
});
|
|
132
|
+
|
|
133
|
+
test('correctly handles interaction', () => {
|
|
134
|
+
const click = jest.fn();
|
|
135
|
+
const change = jest.fn();
|
|
136
|
+
|
|
137
|
+
render(
|
|
138
|
+
<ThemeProvider theme={theme}>
|
|
139
|
+
<Radio
|
|
140
|
+
id="test"
|
|
141
|
+
title="radio"
|
|
142
|
+
label="Test"
|
|
143
|
+
onClick={click}
|
|
144
|
+
onChange={change}
|
|
145
|
+
/>
|
|
146
|
+
</ThemeProvider>
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const radio = screen.getByTitle(/radio/);
|
|
150
|
+
fireEvent.click(radio);
|
|
151
|
+
|
|
152
|
+
expect(click).toHaveBeenCalledTimes(1);
|
|
153
|
+
expect(change).toHaveBeenCalledTimes(1);
|
|
154
|
+
});
|
package/src/Radio/Radio.tsx
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ComponentProps } from '@marigold/types';
|
|
3
3
|
import { Exclamation } from '@marigold/icons';
|
|
4
|
+
import { useFocusRing } from '@react-aria/focus';
|
|
5
|
+
import { VisuallyHidden } from '@react-aria/visually-hidden';
|
|
4
6
|
|
|
7
|
+
import { RadioIcon, RadioIconProps } from './RadioIcon';
|
|
5
8
|
import { Box } from '../Box';
|
|
6
9
|
import { Label } from '../Label';
|
|
7
10
|
import { ValidationMessage } from '../ValidationMessage';
|
|
8
11
|
|
|
9
|
-
import { RadioChecked, RadioUnchecked } from './RadioIcons';
|
|
10
|
-
|
|
11
12
|
// Theme Extension
|
|
12
13
|
// ---------------
|
|
13
14
|
export interface RadioThemeExtension<Value> {
|
|
@@ -16,78 +17,38 @@ export interface RadioThemeExtension<Value> {
|
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
// Radio
|
|
20
|
+
// Radio Input
|
|
20
21
|
// ---------------
|
|
21
|
-
type
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
error?: boolean;
|
|
26
|
-
children?: never;
|
|
27
|
-
};
|
|
22
|
+
type RadioInputProps = RadioIconProps & ComponentProps<'input'>;
|
|
23
|
+
|
|
24
|
+
const RadioInput: React.FC<RadioInputProps> = ({ error, ...props }) => {
|
|
25
|
+
const { focusProps } = useFocusRing();
|
|
28
26
|
|
|
29
|
-
const RadioIcon: React.FC<RadioIconProps> = ({
|
|
30
|
-
variant,
|
|
31
|
-
checked,
|
|
32
|
-
disabled,
|
|
33
|
-
error,
|
|
34
|
-
}) => {
|
|
35
|
-
if (checked) {
|
|
36
|
-
return (
|
|
37
|
-
<Box as={RadioChecked} variant={`radio.${variant}`} disabled={disabled} />
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
27
|
return (
|
|
41
|
-
<Box
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
28
|
+
<Box pr="xsmall">
|
|
29
|
+
<VisuallyHidden>
|
|
30
|
+
<input
|
|
31
|
+
type="radio"
|
|
32
|
+
disabled={props.disabled}
|
|
33
|
+
{...focusProps}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
</VisuallyHidden>
|
|
37
|
+
<RadioIcon
|
|
38
|
+
variant={props.variant}
|
|
39
|
+
disabled={props.disabled}
|
|
40
|
+
checked={props.checked}
|
|
41
|
+
error={error}
|
|
42
|
+
/>
|
|
43
|
+
</Box>
|
|
47
44
|
);
|
|
48
45
|
};
|
|
49
46
|
|
|
50
|
-
// Radio Input
|
|
51
|
-
// ---------------
|
|
52
|
-
type RadioInputProps = {
|
|
53
|
-
variant?: string;
|
|
54
|
-
error?: boolean;
|
|
55
|
-
} & ComponentProps<'input'>;
|
|
56
|
-
|
|
57
|
-
const RadioInput: React.FC<RadioInputProps> = ({
|
|
58
|
-
className,
|
|
59
|
-
variant = '',
|
|
60
|
-
error,
|
|
61
|
-
...props
|
|
62
|
-
}) => (
|
|
63
|
-
<Box display="inline-block" className={className}>
|
|
64
|
-
<Box
|
|
65
|
-
as="input"
|
|
66
|
-
type="radio"
|
|
67
|
-
css={{
|
|
68
|
-
position: 'absolute',
|
|
69
|
-
opacity: 0,
|
|
70
|
-
zIndex: -1,
|
|
71
|
-
width: 1,
|
|
72
|
-
height: 1,
|
|
73
|
-
overflow: 'hidden',
|
|
74
|
-
}}
|
|
75
|
-
{...props}
|
|
76
|
-
/>
|
|
77
|
-
<RadioIcon
|
|
78
|
-
checked={props.checked}
|
|
79
|
-
variant={variant}
|
|
80
|
-
disabled={props.disabled}
|
|
81
|
-
error={error}
|
|
82
|
-
/>
|
|
83
|
-
</Box>
|
|
84
|
-
);
|
|
85
|
-
|
|
86
47
|
// Radio
|
|
87
48
|
// ---------------
|
|
88
49
|
export type RadioProps = {
|
|
89
50
|
id: string;
|
|
90
|
-
label
|
|
51
|
+
label: string;
|
|
91
52
|
required?: boolean;
|
|
92
53
|
labelVariant?: string;
|
|
93
54
|
error?: boolean;
|
|
@@ -101,28 +62,27 @@ export const Radio: React.FC<RadioProps> = ({
|
|
|
101
62
|
error,
|
|
102
63
|
errorMessage,
|
|
103
64
|
...props
|
|
104
|
-
}) =>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
};
|
|
65
|
+
}) => (
|
|
66
|
+
<>
|
|
67
|
+
<Box
|
|
68
|
+
as={Label}
|
|
69
|
+
htmlFor={props.id}
|
|
70
|
+
required={required}
|
|
71
|
+
variant={`label.${labelVariant}`}
|
|
72
|
+
css={
|
|
73
|
+
props.disabled
|
|
74
|
+
? { color: 'disabled', ':hover': { cursor: 'not-allowed' } }
|
|
75
|
+
: { color: 'text', ':hover': { cursor: 'pointer' } }
|
|
76
|
+
}
|
|
77
|
+
>
|
|
78
|
+
<Box as={RadioInput} error={error} {...props} />
|
|
79
|
+
{label}
|
|
80
|
+
</Box>
|
|
81
|
+
{error && errorMessage && (
|
|
82
|
+
<ValidationMessage>
|
|
83
|
+
<Exclamation size={16} />
|
|
84
|
+
{errorMessage}
|
|
85
|
+
</ValidationMessage>
|
|
86
|
+
)}
|
|
87
|
+
</>
|
|
88
|
+
);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { conditional, State, SVG } from '@marigold/system';
|
|
3
|
+
|
|
4
|
+
import { Box } from '../Box';
|
|
5
|
+
|
|
6
|
+
// Radio Icon
|
|
7
|
+
// ---------------
|
|
8
|
+
export type RadioIconProps = {
|
|
9
|
+
variant?: string;
|
|
10
|
+
checked?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
error?: boolean;
|
|
13
|
+
children?: never;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const RadioIcon: React.FC<RadioIconProps> = ({
|
|
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
|
+
variant={conditional(`radio.${variant}`, conditionalStates)}
|
|
41
|
+
as="circle"
|
|
42
|
+
cx="8"
|
|
43
|
+
cy="16"
|
|
44
|
+
r="7.5"
|
|
45
|
+
/>
|
|
46
|
+
{checked && <circle fill="white" cx="8" cy="16" r="3" />}
|
|
47
|
+
</SVG>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
export declare const RadioChecked: ({ disabled, ...props }: {
|
|
3
|
-
[x: string]: any;
|
|
4
|
-
disabled?: boolean | undefined;
|
|
5
|
-
}) => JSX.Element;
|
|
6
|
-
export declare const RadioUnchecked: ({ disabled, error, ...props }: {
|
|
7
|
-
[x: string]: any;
|
|
8
|
-
disabled?: boolean | undefined;
|
|
9
|
-
error?: boolean | undefined;
|
|
10
|
-
}) => JSX.Element;
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
|
|
2
|
-
import { Checkbox } from './Checkbox';
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
|
|
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
|
-
labelVariant: {
|
|
32
|
-
control: {
|
|
33
|
-
type: 'text',
|
|
34
|
-
},
|
|
35
|
-
description: 'Checkbox label variant',
|
|
36
|
-
table: {
|
|
37
|
-
defaultValue: {
|
|
38
|
-
summary: 'inline',
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
label: {
|
|
43
|
-
control: {
|
|
44
|
-
type: 'text',
|
|
45
|
-
},
|
|
46
|
-
description: 'Label',
|
|
47
|
-
},
|
|
48
|
-
required: {
|
|
49
|
-
control: {
|
|
50
|
-
type: 'boolean',
|
|
51
|
-
},
|
|
52
|
-
description: 'Require',
|
|
53
|
-
table: {
|
|
54
|
-
defaultValue: {
|
|
55
|
-
summary: false,
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
error: {
|
|
60
|
-
control: {
|
|
61
|
-
type: 'boolean',
|
|
62
|
-
},
|
|
63
|
-
description: 'Error',
|
|
64
|
-
table: {
|
|
65
|
-
defaultValue: {
|
|
66
|
-
summary: false,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
errorMessage: {
|
|
71
|
-
control: {
|
|
72
|
-
type: 'text',
|
|
73
|
-
},
|
|
74
|
-
description: 'Error Message',
|
|
75
|
-
},
|
|
76
|
-
}}
|
|
77
|
-
/>
|
|
78
|
-
|
|
79
|
-
# Checkbox
|
|
80
|
-
|
|
81
|
-
export const Template = ({ onChange, checked, ...args }) => {
|
|
82
|
-
const [isChecked, setChecked] = useState(false);
|
|
83
|
-
return (
|
|
84
|
-
<Checkbox
|
|
85
|
-
onChange={() => setChecked(!isChecked)}
|
|
86
|
-
checked={isChecked}
|
|
87
|
-
label="Checkbox Label"
|
|
88
|
-
{...args}
|
|
89
|
-
/>
|
|
90
|
-
);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
<Canvas>
|
|
94
|
-
<Story name="Default">{Template.bind({})}</Story>
|
|
95
|
-
</Canvas>
|
|
96
|
-
|
|
97
|
-
<ArgsTable story="Default" />
|
package/src/Radio/RadioIcons.tsx
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { SVG } from '@marigold/system';
|
|
3
|
-
|
|
4
|
-
import { Box } from '../Box';
|
|
5
|
-
|
|
6
|
-
export const RadioChecked = ({ disabled = false, ...props }) => (
|
|
7
|
-
<SVG width="16" height="32" viewBox="0 0 16 32" fill="none" {...props}>
|
|
8
|
-
<Box
|
|
9
|
-
as="circle"
|
|
10
|
-
cx="8"
|
|
11
|
-
cy="16"
|
|
12
|
-
r="7.5"
|
|
13
|
-
variant={disabled ? 'radio.checked.disabled' : 'radio.checked'}
|
|
14
|
-
/>
|
|
15
|
-
<Box as="circle" cx="8" cy="16" r="3" variant="radio.checked.circle" />
|
|
16
|
-
</SVG>
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
export const RadioUnchecked = ({
|
|
20
|
-
disabled = false,
|
|
21
|
-
error = false,
|
|
22
|
-
...props
|
|
23
|
-
}) => (
|
|
24
|
-
<SVG width="16" height="32" viewBox="0 0 16 32" fill="none" {...props}>
|
|
25
|
-
<Box
|
|
26
|
-
as="circle"
|
|
27
|
-
cx="8"
|
|
28
|
-
cy="16"
|
|
29
|
-
r="7.5"
|
|
30
|
-
variant={
|
|
31
|
-
disabled
|
|
32
|
-
? 'radio.unchecked.disabled'
|
|
33
|
-
: error
|
|
34
|
-
? 'radio.unchecked.error'
|
|
35
|
-
: 'radio.unchecked'
|
|
36
|
-
}
|
|
37
|
-
/>
|
|
38
|
-
</SVG>
|
|
39
|
-
);
|