@indico-data/design-system 2.5.0 → 2.7.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.
- package/.storybook/preview.ts +4 -14
- package/lib/index.css +178 -0
- package/lib/index.d.ts +43 -3
- package/lib/index.esm.css +178 -0
- package/lib/index.esm.js +28 -1
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +30 -0
- package/lib/index.js.map +1 -1
- package/lib/src/components/forms/checkbox/Checkbox.d.ts +12 -0
- package/lib/src/components/forms/checkbox/Checkbox.stories.d.ts +7 -0
- package/lib/src/components/forms/checkbox/__tests__/Checkbox.test.d.ts +1 -0
- package/lib/src/components/forms/checkbox/index.d.ts +1 -0
- package/lib/src/components/forms/radio/Radio.d.ts +11 -0
- package/lib/src/components/forms/radio/Radio.stories.d.ts +6 -0
- package/lib/src/components/forms/radio/__tests__/Radio.test.d.ts +1 -0
- package/lib/src/components/forms/radio/index.d.ts +1 -0
- package/lib/src/components/index.d.ts +2 -0
- package/lib/src/index.d.ts +3 -0
- package/package.json +1 -1
- package/src/components/forms/checkbox/Checkbox.mdx +67 -0
- package/src/components/forms/checkbox/Checkbox.stories.tsx +169 -0
- package/src/components/forms/checkbox/Checkbox.tsx +55 -0
- package/src/components/forms/checkbox/__tests__/Checkbox.test.tsx +35 -0
- package/src/components/forms/checkbox/index.ts +1 -0
- package/src/components/forms/checkbox/styles/Checkbox.scss +98 -0
- package/src/components/forms/radio/Radio.mdx +83 -0
- package/src/components/forms/radio/Radio.stories.tsx +121 -0
- package/src/components/forms/radio/Radio.tsx +47 -0
- package/src/components/forms/radio/__tests__/Radio.test.tsx +35 -0
- package/src/components/forms/radio/index.ts +1 -0
- package/src/components/forms/radio/styles/Radio.scss +98 -0
- package/src/components/index.ts +2 -0
- package/src/index.ts +3 -0
- package/src/styles/index.scss +2 -0
- package/src/styles/storybook.scss +15 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface CheckboxProps {
|
|
3
|
+
ref?: React.LegacyRef<HTMLInputElement>;
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
name: string;
|
|
7
|
+
value?: string;
|
|
8
|
+
isChecked?: boolean | undefined;
|
|
9
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
10
|
+
isDisabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const Checkbox: ({ ref, id, label, name, value, onChange, isDisabled, isChecked, ...rest }: CheckboxProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Checkbox } from './Checkbox';
|
|
3
|
+
declare const meta: Meta;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof Checkbox>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const GroupCheckbox: Story;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Checkbox } from './Checkbox';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface RadioProps {
|
|
3
|
+
ref?: React.LegacyRef<HTMLInputElement>;
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
name: string;
|
|
7
|
+
value?: string;
|
|
8
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
9
|
+
isDisabled?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const Radio: ({ ref, id, label, name, value, onChange, isDisabled, ...rest }: RadioProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Radio } from './Radio';
|
package/lib/src/index.d.ts
CHANGED
|
@@ -7,3 +7,6 @@ export { Container, Row, Col } from './components/grid';
|
|
|
7
7
|
export { Button } from './components/button';
|
|
8
8
|
export { Icon } from './components/icons';
|
|
9
9
|
export { Table } from './components/table';
|
|
10
|
+
export { Input } from './components/forms/input';
|
|
11
|
+
export { Radio as RadioInput } from './components/forms/radio';
|
|
12
|
+
export { Checkbox } from './components/forms/checkbox';
|
package/package.json
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls } from '@storybook/blocks';
|
|
2
|
+
import * as Checkbox from './Checkbox.stories';
|
|
3
|
+
|
|
4
|
+
<Meta title="Forms/Checkbox" name="Checkbox" />
|
|
5
|
+
|
|
6
|
+
# Checkbox
|
|
7
|
+
This component may be used on it's on or as part of a group. The source code is an example of how we would use it as part of a group.
|
|
8
|
+
|
|
9
|
+
<Canvas of={Checkbox.Default} source={{
|
|
10
|
+
code: `
|
|
11
|
+
<div>
|
|
12
|
+
<h2 className="mb-2">Checkbox Buttons</h2>
|
|
13
|
+
<Checkbox
|
|
14
|
+
onChange={onChange}
|
|
15
|
+
id={id}
|
|
16
|
+
label={label}
|
|
17
|
+
name={name}
|
|
18
|
+
value={value}
|
|
19
|
+
isDisabled={isDisabled}
|
|
20
|
+
isChecked={isChecked}
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
`,
|
|
24
|
+
}} />
|
|
25
|
+
<Controls of={Checkbox.Default} />
|
|
26
|
+
|
|
27
|
+
## Handling Required State
|
|
28
|
+
The checkbox component does not have a required state. If you need to enforce a required state, this will be managed in a parent component or wrapper element which handles the state. You will need to verify against a value that matches the value in a state array for the checkbox buttons and make sure it is not null.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
<Canvas of={Checkbox.GroupCheckbox} source={{
|
|
32
|
+
code: `
|
|
33
|
+
const checkboxList = [
|
|
34
|
+
{ id: 'one', label: 'Checkbox Label One', name: 'Checkbox', value: 'check1' },
|
|
35
|
+
{ id: 'two', label: 'Checkbox Label Two', name: 'Checkbox', value: 'check2' },
|
|
36
|
+
{ id: 'three', label: 'Checkbox Label Three', name: 'Checkbox', value: 'check3' },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export const CheckboxGroup = {
|
|
40
|
+
const [selectedCheckboxes, setSelectedCheckboxes] = useState<string[]>([]);
|
|
41
|
+
|
|
42
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
43
|
+
const { value, checked } = e.target;
|
|
44
|
+
checked
|
|
45
|
+
? setSelectedCheckboxes((prev) => [...prev, value])
|
|
46
|
+
: setSelectedCheckboxes((prev) => prev.filter((item) => item !== value));
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div>
|
|
50
|
+
<h2 className="mb-2">Checkbox Buttons</h2>
|
|
51
|
+
{checkboxList.map((checkbox) => (
|
|
52
|
+
<Checkbox
|
|
53
|
+
key={checkbox.id}
|
|
54
|
+
onChange={handleChange}
|
|
55
|
+
id={checkbox.id}
|
|
56
|
+
label={checkbox.label}
|
|
57
|
+
name={checkbox.name}
|
|
58
|
+
value={checkbox.value}
|
|
59
|
+
isDisabled={args.isDisabled}
|
|
60
|
+
isChecked={selectedCheckboxes.includes(checkbox.value)}
|
|
61
|
+
/>
|
|
62
|
+
))}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
},
|
|
66
|
+
`,
|
|
67
|
+
}} />
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Checkbox, CheckboxProps } from './Checkbox';
|
|
3
|
+
import { SetStateAction, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
const meta: Meta = {
|
|
6
|
+
title: 'Forms/Checkbox',
|
|
7
|
+
component: Checkbox,
|
|
8
|
+
argTypes: {
|
|
9
|
+
ref: {
|
|
10
|
+
table: {
|
|
11
|
+
disable: true,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
onChange: {
|
|
15
|
+
control: false,
|
|
16
|
+
description: 'onChange event handler',
|
|
17
|
+
table: {
|
|
18
|
+
category: 'Callbacks',
|
|
19
|
+
type: {
|
|
20
|
+
summary: '(e: React.ChangeEvent<HTMLInputElement>) => void',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
action: 'onChange',
|
|
24
|
+
},
|
|
25
|
+
label: {
|
|
26
|
+
control: 'text',
|
|
27
|
+
description: 'The label for the checkbox field',
|
|
28
|
+
table: {
|
|
29
|
+
category: 'Props',
|
|
30
|
+
type: {
|
|
31
|
+
summary: 'string',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
defaultValue: { summary: '' },
|
|
35
|
+
},
|
|
36
|
+
name: {
|
|
37
|
+
control: 'text',
|
|
38
|
+
description: 'The name for the checkbox field',
|
|
39
|
+
table: {
|
|
40
|
+
category: 'Props',
|
|
41
|
+
type: {
|
|
42
|
+
summary: 'string',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
defaultValue: { summary: '' },
|
|
46
|
+
},
|
|
47
|
+
value: {
|
|
48
|
+
control: 'text',
|
|
49
|
+
description: 'This holds the value that will be emitted when the checkbox is selected',
|
|
50
|
+
table: {
|
|
51
|
+
category: 'Props',
|
|
52
|
+
type: {
|
|
53
|
+
summary: 'string',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
defaultValue: { summary: '' },
|
|
57
|
+
},
|
|
58
|
+
id: {
|
|
59
|
+
control: 'text',
|
|
60
|
+
description: 'This explains what button group this checkbox belongs to.',
|
|
61
|
+
table: {
|
|
62
|
+
category: 'Props',
|
|
63
|
+
type: {
|
|
64
|
+
summary: 'string',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
defaultValue: { summary: '' },
|
|
68
|
+
},
|
|
69
|
+
isDisabled: {
|
|
70
|
+
control: 'boolean',
|
|
71
|
+
description: 'Toggles the disabled state of the checkbox field',
|
|
72
|
+
table: {
|
|
73
|
+
category: 'Props',
|
|
74
|
+
type: {
|
|
75
|
+
summary: 'boolean',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
defaultValue: { summary: false },
|
|
79
|
+
},
|
|
80
|
+
isChecked: {
|
|
81
|
+
control: 'boolean',
|
|
82
|
+
description: 'Toggles the checked state of the checkbox field when true',
|
|
83
|
+
table: {
|
|
84
|
+
category: 'Props',
|
|
85
|
+
type: {
|
|
86
|
+
summary: 'boolean | undefined',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
defaultValue: { summary: false },
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export default meta;
|
|
95
|
+
|
|
96
|
+
type Story = StoryObj<typeof Checkbox>;
|
|
97
|
+
|
|
98
|
+
const checkboxList = [
|
|
99
|
+
{ id: 'one', label: 'Checkbox Label One', name: 'Checkbox', value: 'check1' },
|
|
100
|
+
{ id: 'two', label: 'Checkbox Label Two', name: 'Checkbox', value: 'check2' },
|
|
101
|
+
{ id: 'three', label: 'Checkbox Label Three', name: 'Checkbox', value: 'check3' },
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
export const Default: Story = {
|
|
105
|
+
args: {
|
|
106
|
+
id: 'one',
|
|
107
|
+
label: 'Checkbox Label',
|
|
108
|
+
name: 'checkbox',
|
|
109
|
+
value: 'checkbox',
|
|
110
|
+
isDisabled: false,
|
|
111
|
+
isChecked: false,
|
|
112
|
+
},
|
|
113
|
+
render: (args) => {
|
|
114
|
+
return (
|
|
115
|
+
<div>
|
|
116
|
+
<h2 className="mb-2">Checkbox Buttons</h2>
|
|
117
|
+
<Checkbox
|
|
118
|
+
key={args.id}
|
|
119
|
+
onChange={args.onChange}
|
|
120
|
+
id={args.id}
|
|
121
|
+
label={args.label}
|
|
122
|
+
name={args.name}
|
|
123
|
+
value={args.value}
|
|
124
|
+
isDisabled={args.isDisabled}
|
|
125
|
+
isChecked={args.isChecked}
|
|
126
|
+
/>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export const GroupCheckbox: Story = {
|
|
133
|
+
args: {
|
|
134
|
+
id: 'one',
|
|
135
|
+
label: 'Checkbox Label',
|
|
136
|
+
name: 'checkbox',
|
|
137
|
+
value: 'checkbox',
|
|
138
|
+
isDisabled: false,
|
|
139
|
+
isChecked: false,
|
|
140
|
+
},
|
|
141
|
+
render: (args) => {
|
|
142
|
+
const [selectedCheckboxes, setSelectedCheckboxes] = useState<string[]>([]);
|
|
143
|
+
|
|
144
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
145
|
+
const { value, checked } = e.target;
|
|
146
|
+
checked
|
|
147
|
+
? setSelectedCheckboxes((prev) => [...prev, value])
|
|
148
|
+
: setSelectedCheckboxes((prev) => prev.filter((item) => item !== value));
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<div>
|
|
153
|
+
<h2 className="mb-2">Checkbox Buttons</h2>
|
|
154
|
+
{checkboxList.map((checkbox) => (
|
|
155
|
+
<Checkbox
|
|
156
|
+
key={checkbox.id}
|
|
157
|
+
onChange={handleChange}
|
|
158
|
+
id={checkbox.id}
|
|
159
|
+
label={checkbox.label}
|
|
160
|
+
name={checkbox.name}
|
|
161
|
+
value={checkbox.value}
|
|
162
|
+
isDisabled={args.isDisabled}
|
|
163
|
+
isChecked={selectedCheckboxes.includes(checkbox.value)}
|
|
164
|
+
/>
|
|
165
|
+
))}
|
|
166
|
+
</div>
|
|
167
|
+
);
|
|
168
|
+
},
|
|
169
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { isChecked } from '@indico-data/utils/dist/validators';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface CheckboxProps {
|
|
5
|
+
ref?: React.LegacyRef<HTMLInputElement>;
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
name: string;
|
|
9
|
+
value?: string;
|
|
10
|
+
isChecked?: boolean | undefined;
|
|
11
|
+
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
12
|
+
isDisabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const Checkbox = ({
|
|
16
|
+
ref,
|
|
17
|
+
id,
|
|
18
|
+
label,
|
|
19
|
+
name,
|
|
20
|
+
value,
|
|
21
|
+
onChange,
|
|
22
|
+
isDisabled,
|
|
23
|
+
isChecked = false,
|
|
24
|
+
...rest
|
|
25
|
+
}: CheckboxProps) => {
|
|
26
|
+
return (
|
|
27
|
+
<div className="form-control">
|
|
28
|
+
<div className="checkbox-wrapper">
|
|
29
|
+
<input
|
|
30
|
+
data-testid={`form-checkbox-input-${name}`}
|
|
31
|
+
{...rest}
|
|
32
|
+
className="checkbox-input"
|
|
33
|
+
type="checkbox"
|
|
34
|
+
id={id}
|
|
35
|
+
checked={isChecked}
|
|
36
|
+
name={name}
|
|
37
|
+
value={value}
|
|
38
|
+
disabled={isDisabled}
|
|
39
|
+
ref={ref}
|
|
40
|
+
onChange={onChange}
|
|
41
|
+
tabIndex={0}
|
|
42
|
+
aria-describedby={id}
|
|
43
|
+
aria-label={label}
|
|
44
|
+
/>
|
|
45
|
+
<label
|
|
46
|
+
htmlFor={id}
|
|
47
|
+
className="checkbox-input-label"
|
|
48
|
+
data-testid={`label-checkbox-input-${name}`}
|
|
49
|
+
>
|
|
50
|
+
{label}
|
|
51
|
+
</label>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { Checkbox } from '@/components/forms/checkbox/Checkbox';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
|
|
5
|
+
const handleOnChange = jest.fn();
|
|
6
|
+
|
|
7
|
+
describe('checkbox', () => {
|
|
8
|
+
it('renders the checkbox input field', () => {
|
|
9
|
+
render(
|
|
10
|
+
<Checkbox
|
|
11
|
+
label="Option 1"
|
|
12
|
+
name="name"
|
|
13
|
+
ref={undefined}
|
|
14
|
+
onChange={handleOnChange}
|
|
15
|
+
id={'ButtonGroup'}
|
|
16
|
+
/>,
|
|
17
|
+
);
|
|
18
|
+
expect(screen.getByLabelText('Option 1')).toBeInTheDocument();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('calls the onChange function when the checkbox input is clicked', async () => {
|
|
22
|
+
render(
|
|
23
|
+
<Checkbox
|
|
24
|
+
label="Option 1"
|
|
25
|
+
name="name"
|
|
26
|
+
ref={undefined}
|
|
27
|
+
onChange={handleOnChange}
|
|
28
|
+
id={'ButtonGroup'}
|
|
29
|
+
/>,
|
|
30
|
+
);
|
|
31
|
+
expect(handleOnChange).toHaveBeenCalledTimes(0);
|
|
32
|
+
await userEvent.click(screen.getByLabelText('Option 1'));
|
|
33
|
+
expect(handleOnChange).toHaveBeenCalledTimes(1);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Checkbox } from './Checkbox';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Common Variables
|
|
2
|
+
:root,
|
|
3
|
+
:root [data-theme='light'],
|
|
4
|
+
:root [data-theme='dark'] {
|
|
5
|
+
--pf-checkbox-background-color: var(--pf-white-color);
|
|
6
|
+
--pf-checkbox-check-color: var(--pf-primary-color);
|
|
7
|
+
--pf-checkbox-border-color: var(--pf-gray-color);
|
|
8
|
+
--pf-checkbox-disabled-color: var(--pf-gray-color-400);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Dark Theme Specific Variables
|
|
12
|
+
:root [data-theme='dark'] {
|
|
13
|
+
--pf-checkbox-background-color: transparent;
|
|
14
|
+
--pf-checkbox-check-color: var(--pf-white-color);
|
|
15
|
+
--pf-checkbox-border-color: var(--pf-white-color);
|
|
16
|
+
--pf-checkbox-disabled-color: var(--pf-gray-color-300);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.form-control {
|
|
20
|
+
.checkbox-wrapper {
|
|
21
|
+
display: flex;
|
|
22
|
+
margin-bottom: var(--pf-margin-2);
|
|
23
|
+
align-items: center;
|
|
24
|
+
}
|
|
25
|
+
.checkbox-input {
|
|
26
|
+
margin: 0;
|
|
27
|
+
margin-right: var(--pf-margin-2);
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
}
|
|
30
|
+
.checkbox-input-label {
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
}
|
|
33
|
+
[type='checkbox']:checked,
|
|
34
|
+
[type='checkbox']:not(:checked) {
|
|
35
|
+
position: absolute;
|
|
36
|
+
left: -9999px;
|
|
37
|
+
}
|
|
38
|
+
[type='checkbox']:checked + label,
|
|
39
|
+
[type='checkbox']:not(:checked) + label {
|
|
40
|
+
position: relative;
|
|
41
|
+
padding-left: var(--pf-padding-7);
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
line-height: 20px;
|
|
44
|
+
display: inline-block;
|
|
45
|
+
}
|
|
46
|
+
[type='checkbox']:checked + label:before,
|
|
47
|
+
[type='checkbox']:not(:checked) + label:before {
|
|
48
|
+
content: '';
|
|
49
|
+
position: absolute;
|
|
50
|
+
left: 0;
|
|
51
|
+
top: 0;
|
|
52
|
+
width: 18px;
|
|
53
|
+
height: 18px;
|
|
54
|
+
border: 1px solid var(--pf-checkbox-border-color);
|
|
55
|
+
border-radius: var(--pf-rounded);
|
|
56
|
+
background: var(--pf-checkbox-background-color);
|
|
57
|
+
}
|
|
58
|
+
[type='checkbox']:checked + label:after,
|
|
59
|
+
[type='checkbox']:not(:checked) + label:after {
|
|
60
|
+
content: '';
|
|
61
|
+
width: 12px;
|
|
62
|
+
height: 12px;
|
|
63
|
+
background: var(--pf-checkbox-check-color);
|
|
64
|
+
position: absolute;
|
|
65
|
+
top: 4px;
|
|
66
|
+
left: 4px;
|
|
67
|
+
border-radius: var(--pf-rounded);
|
|
68
|
+
-webkit-transition: all 0.2s ease;
|
|
69
|
+
transition: all 0.2s ease;
|
|
70
|
+
}
|
|
71
|
+
[type='checkbox']:not(:checked) + label:after {
|
|
72
|
+
opacity: 0;
|
|
73
|
+
-webkit-transform: scale(0);
|
|
74
|
+
transform: scale(0);
|
|
75
|
+
}
|
|
76
|
+
[type='checkbox']:checked + label:after {
|
|
77
|
+
opacity: 1;
|
|
78
|
+
-webkit-transform: scale(1);
|
|
79
|
+
transform: scale(1);
|
|
80
|
+
}
|
|
81
|
+
[type='checkbox']:disabled,
|
|
82
|
+
[type='checkbox']:disabled + label {
|
|
83
|
+
cursor: not-allowed;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[type='checkbox']:disabled + label {
|
|
87
|
+
color: var(--pf-checkbox-disabled-color);
|
|
88
|
+
opacity: 0.5;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
[type='checkbox']:disabled + label:before {
|
|
92
|
+
border-color: var(--pf-checkbox-disabled-color);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
[type='checkbox']:disabled + label:after {
|
|
96
|
+
background: var(--pf-checkbox-disabled-color);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls } from '@storybook/blocks';
|
|
2
|
+
import * as Radio from './Radio.stories';
|
|
3
|
+
|
|
4
|
+
<Meta title="Forms/Radio" name="Radio" />
|
|
5
|
+
|
|
6
|
+
# Radio
|
|
7
|
+
This component is intended to use as part of a group. You would apply multiple radio button components and they share the same ID field to form a group.
|
|
8
|
+
|
|
9
|
+
<Canvas of={Radio.Default} source={{
|
|
10
|
+
code: `
|
|
11
|
+
const radioList = [
|
|
12
|
+
{ id: 'one', label: 'Radio Label One', name: 'radio', value: 'radio' },
|
|
13
|
+
{ id: 'two', label: 'Radio Label Two', name: 'radio', value: 'radio' },
|
|
14
|
+
{ id: 'three', label: 'Radio Label Three', name: 'radio', value: 'radio' },
|
|
15
|
+
];
|
|
16
|
+
<h2 className="mb-2">Radio Buttons</h2>
|
|
17
|
+
{radioList.map((radio) => (
|
|
18
|
+
<Radio
|
|
19
|
+
key={radio.id}
|
|
20
|
+
onChange={handleChange}
|
|
21
|
+
id={radio.id}
|
|
22
|
+
label={radio.label}
|
|
23
|
+
name={radio.name}
|
|
24
|
+
value={radio.value}
|
|
25
|
+
isDisabled={args.isDisabled}
|
|
26
|
+
/>
|
|
27
|
+
))}
|
|
28
|
+
`,
|
|
29
|
+
}} />
|
|
30
|
+
<Controls of={Radio.Default} />
|
|
31
|
+
|
|
32
|
+
## Handling Required State
|
|
33
|
+
The radio component does not have a required state. If you need to enforce a required state. This will be managed in a parent component or wrapper element which handles the state. You will need to verify against a value that matches the ID group for the radio buttons and make sure it is not null.
|
|
34
|
+
|
|
35
|
+
### Rough code example
|
|
36
|
+
This is a temporary measure until we build our own component to manage this state.
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
const RadioGroupForm = () => {
|
|
40
|
+
const [selectedValue, setSelectedValue] = useState('');
|
|
41
|
+
const [isSubmittedWithoutSelection, setIsSubmittedWithoutSelection] = useState(false);
|
|
42
|
+
|
|
43
|
+
const handleSubmit = (e) => {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
if (!selectedValue) {
|
|
46
|
+
setIsSubmittedWithoutSelection(true);
|
|
47
|
+
} else {
|
|
48
|
+
setIsSubmittedWithoutSelection(false);
|
|
49
|
+
console.log('Form submitted with selected value:', selectedValue);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const radioList = [
|
|
54
|
+
{ id: 'one', label: 'Radio Label One', name: 'radio', value: 'radio' },
|
|
55
|
+
{ id: 'two', label: 'Radio Label Two', name: 'radio', value: 'radio' },
|
|
56
|
+
{ id: 'three', label: 'Radio Label Three', name: 'radio', value: 'radio' },
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
const handleChange = (e) => {
|
|
60
|
+
setSelectedValue(e.target.value);
|
|
61
|
+
if (isSubmittedWithoutSelection) {
|
|
62
|
+
setIsSubmittedWithoutSelection(false);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<form onSubmit={handleSubmit}>
|
|
68
|
+
{radioList.map((radio) => (
|
|
69
|
+
<Radio
|
|
70
|
+
key={radio.id}
|
|
71
|
+
onChange={handleChange}
|
|
72
|
+
id={radio.id}
|
|
73
|
+
label={radio.label}
|
|
74
|
+
name={radio.name}
|
|
75
|
+
value={radio.value}
|
|
76
|
+
isDisabled={args.isDisabled}
|
|
77
|
+
/>
|
|
78
|
+
))}
|
|
79
|
+
<button type="submit">Submit</button>
|
|
80
|
+
</form>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
```
|