Skip to content

Commit 11ba51b

Browse files
committed
feat: Add radio button component to Core
1 parent 08da1c8 commit 11ba51b

File tree

32 files changed

+1318
-211
lines changed

32 files changed

+1318
-211
lines changed

build-tools/utils/pluralize.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const pluralizationMap = {
5959
ProgressBar: 'ProgressBars',
6060
PromptInput: 'PromptInputs',
6161
PropertyFilter: 'PropertyFilters',
62+
RadioButton: 'RadioButtons',
6263
RadioGroup: 'RadioGroups',
6364
S3ResourceSelector: 'S3ResourceSelectors',
6465
SegmentedControl: 'SegmentedControls',

pages/radio-button/cards.page.tsx

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import React, { useContext, useRef, useState } from 'react';
4+
import clsx from 'clsx';
5+
6+
import Box from '~components/box';
7+
import Checkbox from '~components/checkbox';
8+
import FormField from '~components/form-field';
9+
import RadioButton, { RadioButtonProps } from '~components/radio-button';
10+
import SpaceBetween from '~components/space-between';
11+
12+
import AppContext, { AppContextType } from '../app/app-context';
13+
import ScreenshotArea from '../utils/screenshot-area';
14+
import { options } from './common';
15+
16+
import styles from './cards.scss';
17+
18+
type RadioButtonDemoContext = React.Context<
19+
AppContextType<{
20+
disabled?: boolean;
21+
readOnly?: boolean;
22+
}>
23+
>;
24+
25+
const Card = ({
26+
value,
27+
label,
28+
checked,
29+
setValue,
30+
description,
31+
disabled,
32+
readOnly,
33+
}: Omit<RadioButtonProps, 'name'> & { label: string; setValue: (_a: string) => void }) => {
34+
const ref = useRef<HTMLInputElement>(null);
35+
return (
36+
<li className={clsx(styles.card, checked && styles['card--selected'])}>
37+
<div>
38+
<h2 className={styles.heading}>
39+
<a href="#">{label}</a>
40+
</h2>
41+
<p className={styles.description}>{description}</p>
42+
</div>
43+
<label aria-label={`Select ${label}`}>
44+
<RadioButton
45+
value={value}
46+
name="quantity"
47+
checked={checked}
48+
disabled={disabled}
49+
readOnly={readOnly}
50+
onChange={({ detail }) => {
51+
setValue(detail.value);
52+
ref.current?.focus();
53+
}}
54+
ref={ref}
55+
/>
56+
</label>
57+
</li>
58+
);
59+
};
60+
61+
export default function RadioButtonsCardsPage() {
62+
const { urlParams, setUrlParams } = useContext(AppContext as RadioButtonDemoContext);
63+
64+
const [value, setValue] = useState<string>('');
65+
66+
return (
67+
<article>
68+
<h1>Radio button — custom card selection</h1>
69+
<Box margin={{ horizontal: 'm' }}>
70+
<SpaceBetween size="s">
71+
<FormField label="Options">
72+
<SpaceBetween size="s">
73+
<Checkbox
74+
checked={!!urlParams.disabled}
75+
onChange={({ detail }) => setUrlParams({ ...urlParams, disabled: detail.checked })}
76+
description="Make one of the radio buttons disabled"
77+
>
78+
Disabled
79+
</Checkbox>
80+
81+
<Checkbox
82+
checked={!!urlParams.readOnly}
83+
onChange={({ detail }) => setUrlParams({ ...urlParams, readOnly: detail.checked })}
84+
description="Make one of the radio buttons read-only"
85+
>
86+
Read-only
87+
</Checkbox>
88+
</SpaceBetween>
89+
</FormField>
90+
</SpaceBetween>
91+
</Box>
92+
<hr />
93+
<ScreenshotArea disableAnimations={true}>
94+
<ul className={styles.cards}>
95+
{options.map((option, index) => (
96+
<Card
97+
key={index}
98+
value={option.value}
99+
label={option.label}
100+
description={option.description}
101+
checked={option.value === value}
102+
setValue={setValue}
103+
disabled={option.allowDisabled && urlParams.disabled}
104+
readOnly={option.allowReadOnly && urlParams.readOnly}
105+
/>
106+
))}
107+
</ul>
108+
</ScreenshotArea>
109+
</article>
110+
);
111+
}

pages/radio-button/cards.scss

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
@use '~design-tokens' as awsui;
7+
8+
.cards {
9+
display: flex;
10+
flex-wrap: wrap;
11+
gap: awsui.$space-scaled-xs;
12+
list-style-type: none;
13+
margin-block: 0;
14+
margin-inline: 0;
15+
padding-block: 0;
16+
padding-inline: 0;
17+
}
18+
19+
.card {
20+
$border-radius: awsui.$space-scaled-s;
21+
align-items: start;
22+
border-color: awsui.$color-border-control-default;
23+
border-start-start-radius: $border-radius;
24+
border-start-end-radius: $border-radius;
25+
border-end-start-radius: $border-radius;
26+
border-end-end-radius: $border-radius;
27+
border-block-style: solid;
28+
border-inline-style: solid;
29+
border-block-width: 1px;
30+
border-inline-width: 1px;
31+
display: flex;
32+
gap: awsui.$space-scaled-s;
33+
inline-size: 300px;
34+
justify-content: space-between;
35+
padding-block: awsui.$space-scaled-l;
36+
padding-inline: awsui.$space-scaled-l;
37+
38+
&--selected {
39+
border-color: awsui.$color-border-item-focused;
40+
}
41+
}
42+
43+
.heading {
44+
margin-block: 0;
45+
}
46+
.description {
47+
margin-block: awsui.$space-scaled-xs 0;
48+
}

pages/radio-button/common.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
export const options = [
4+
{ value: 'one', label: 'One', description: 'First option' },
5+
{ value: 'two', label: 'Two', description: 'Second option', allowDisabled: true, allowReadOnly: true },
6+
{ value: 'three', label: 'Three', description: 'Third option' },
7+
];

pages/radio-button/styles.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
@use '~design-tokens' as awsui;
7+
8+
.radio-group {
9+
display: flex;
10+
column-gap: awsui.$space-scaled-m;
11+
row-gap: awsui.$space-scaled-xs;
12+
&--horizontal {
13+
flex-direction: row;
14+
flex-wrap: wrap;
15+
}
16+
&--vertical {
17+
flex-direction: column;
18+
}
19+
}

pages/radio-button/table.page.tsx

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import React, { useContext, useRef, useState } from 'react';
4+
import clsx from 'clsx';
5+
6+
import Box from '~components/box';
7+
import Checkbox from '~components/checkbox';
8+
import FormField from '~components/form-field';
9+
import RadioButton, { RadioButtonProps } from '~components/radio-button';
10+
import SpaceBetween from '~components/space-between';
11+
12+
import AppContext, { AppContextType } from '../app/app-context';
13+
import ScreenshotArea from '../utils/screenshot-area';
14+
import { options } from './common';
15+
16+
import styles from './table.scss';
17+
18+
type RadioButtonDemoContext = React.Context<
19+
AppContextType<{
20+
disabled?: boolean;
21+
readOnly?: boolean;
22+
}>
23+
>;
24+
25+
const Row = ({
26+
value,
27+
label,
28+
checked,
29+
setValue,
30+
description,
31+
disabled,
32+
readOnly,
33+
}: Omit<RadioButtonProps, 'name'> & { label: string; setValue: (_a: string) => void }) => {
34+
const ref = useRef<HTMLInputElement>(null);
35+
return (
36+
<tr className={clsx(styles.row, checked && styles['row--selected'])}>
37+
<td className={styles.cell}>
38+
<label aria-label={`Select ${label}`}>
39+
<RadioButton
40+
value={value}
41+
name="quantity"
42+
checked={checked}
43+
disabled={disabled}
44+
readOnly={readOnly}
45+
onChange={({ detail }) => {
46+
setValue(detail.value);
47+
ref.current?.focus();
48+
}}
49+
ref={ref}
50+
/>
51+
</label>
52+
</td>
53+
<td className={styles.cell}>
54+
<a href="#">{label}</a>
55+
</td>
56+
<td className={styles.cell}>{description}</td>
57+
</tr>
58+
);
59+
};
60+
61+
export default function RadioButtonsTablePage() {
62+
const { urlParams, setUrlParams } = useContext(AppContext as RadioButtonDemoContext);
63+
64+
const [value, setValue] = useState<string>('');
65+
66+
return (
67+
<article>
68+
<h1>Radio button — custom table selection</h1>
69+
<Box margin={{ horizontal: 'm' }}>
70+
<SpaceBetween size="s">
71+
<FormField label="Options">
72+
<SpaceBetween size="s">
73+
<Checkbox
74+
checked={!!urlParams.disabled}
75+
onChange={({ detail }) => setUrlParams({ ...urlParams, disabled: detail.checked })}
76+
description="Make one of the radio buttons disabled"
77+
>
78+
Disabled
79+
</Checkbox>
80+
81+
<Checkbox
82+
checked={!!urlParams.readOnly}
83+
onChange={({ detail }) => setUrlParams({ ...urlParams, readOnly: detail.checked })}
84+
description="Make one of the radio buttons read-only"
85+
>
86+
Read-only
87+
</Checkbox>
88+
</SpaceBetween>
89+
</FormField>
90+
</SpaceBetween>
91+
</Box>
92+
<hr />
93+
<ScreenshotArea disableAnimations={true}>
94+
<table className={styles.table}>
95+
<thead className={styles.head}>
96+
<tr className={styles.row}>
97+
<th className={styles['header-cell']}></th>
98+
<th className={styles['header-cell']}>Name</th>
99+
<th className={styles['header-cell']}>Description</th>
100+
</tr>
101+
</thead>
102+
<tbody>
103+
{options.map((option, index) => (
104+
<Row
105+
key={index}
106+
value={option.value}
107+
label={option.label}
108+
description={option.description}
109+
checked={option.value === value}
110+
setValue={setValue}
111+
disabled={option.allowDisabled && urlParams.disabled}
112+
readOnly={option.allowReadOnly && urlParams.readOnly}
113+
>
114+
{option.label}
115+
</Row>
116+
))}
117+
</tbody>
118+
</table>
119+
</ScreenshotArea>
120+
</article>
121+
);
122+
}

pages/radio-button/table.scss

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
@use '~design-tokens' as awsui;
7+
8+
.table {
9+
border-collapse: collapse;
10+
}
11+
12+
.head {
13+
background-color: awsui.$color-background-cell-shaded;
14+
}
15+
16+
.cell,
17+
.header-cell {
18+
padding-inline: awsui.$space-scaled-s;
19+
}
20+
21+
.cell {
22+
padding-block: awsui.$space-scaled-xs;
23+
}
24+
25+
.header-cell,
26+
.row {
27+
border-block-style: solid;
28+
border-inline-style: solid;
29+
border-block-width: 1px;
30+
border-inline-width: 1px;
31+
border-color: awsui.$color-border-divider-default;
32+
}
33+
34+
.header-cell {
35+
padding-block: awsui.$space-scaled-xxs;
36+
text-align: start;
37+
}
38+
39+
.row {
40+
&--selected {
41+
outline: 1px solid awsui.$color-border-item-focused;
42+
}
43+
}

0 commit comments

Comments
 (0)