Skip to content

Commit 637d19f

Browse files
committed
feat: implement style api for toggle button component
1 parent 06863a3 commit 637d19f

File tree

7 files changed

+282
-7
lines changed

7 files changed

+282
-7
lines changed

build-tools/utils/custom-css-properties.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ const customCssPropertiesList = [
105105
'styleBorderColorFocus',
106106
'styleBoxShadowFocus',
107107
'styleColorFocus',
108+
// Pressed state
109+
'styleBackgroundPressed',
110+
'styleBorderColorPressed',
111+
'styleBoxShadowPressed',
112+
'styleColorPressed',
108113
// Placeholder style properties
109114
'stylePlaceholderColor',
110115
'stylePlaceholderFontSize',
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import React from 'react';
4+
5+
import ToggleButton, { ToggleButtonProps } from '~components/toggle-button';
6+
7+
import createPermutations from '../utils/permutations';
8+
import PermutationsView from '../utils/permutations-view';
9+
import ScreenshotArea from '../utils/screenshot-area';
10+
11+
const permutations = createPermutations<ToggleButtonProps>([
12+
{
13+
variant: ['normal'],
14+
children: ['Subscribe'],
15+
pressed: [false, true],
16+
disabled: [false, true],
17+
iconName: ['thumbs-up'],
18+
pressedIconName: ['thumbs-up-filled'],
19+
onChange: [() => {}],
20+
style: [
21+
{
22+
root: {
23+
background: {
24+
default: '#2563eb',
25+
hover: '#1d4ed8',
26+
active: '#1e40af',
27+
disabled: '#bfdbfe',
28+
pressed: '#1e3a8a',
29+
},
30+
borderColor: {
31+
default: '#2563eb',
32+
hover: '#1d4ed8',
33+
active: '#1e3a8a',
34+
disabled: '#60a5fa',
35+
pressed: '#1e3a8a',
36+
},
37+
borderWidth: '2px',
38+
borderRadius: '0',
39+
boxShadow: {
40+
default: '0 1px 2px rgba(0, 0, 0, 0.05)',
41+
hover: '0 2px 4px rgba(59, 130, 246, 0.15)',
42+
active: '0 1px 2px rgba(0, 0, 0, 0.05)',
43+
disabled: 'none',
44+
pressed: '0 0 0 4px rgba(59, 130, 246, 0.2)',
45+
},
46+
color: {
47+
default: '#ffffff',
48+
hover: '#ffffff',
49+
active: '#ffffff',
50+
disabled: '#0c4a6e',
51+
pressed: '#ffffff',
52+
},
53+
paddingBlock: '10px',
54+
paddingInline: '16px',
55+
focusRing: {
56+
borderColor: '#3b82f6',
57+
borderRadius: '2px',
58+
borderWidth: '3px',
59+
},
60+
},
61+
},
62+
{
63+
root: {
64+
background: {
65+
default: '#7c3aed',
66+
hover: '#6d28d9',
67+
active: '#5b21b6',
68+
disabled: '#ddd6fe',
69+
pressed: '#4c1d95',
70+
},
71+
borderColor: {
72+
default: '#7c3aed',
73+
hover: '#6d28d9',
74+
active: '#5b21b6',
75+
disabled: '#c4b5fd',
76+
pressed: '#5b21b6',
77+
},
78+
borderWidth: '2px',
79+
borderRadius: '12px',
80+
boxShadow: {
81+
default: '0 1px 3px rgba(0, 0, 0, 0.1)',
82+
hover: '0 4px 6px rgba(139, 92, 246, 0.2)',
83+
active: '0 2px 4px rgba(0, 0, 0, 0.1)',
84+
disabled: 'none',
85+
pressed: '0 0 0 4px rgba(139, 92, 246, 0.3)',
86+
},
87+
color: {
88+
default: '#ffffff',
89+
hover: '#ffffff',
90+
active: '#ffffff',
91+
disabled: '#2e1065',
92+
pressed: '#ffffff',
93+
},
94+
paddingBlock: '12px',
95+
paddingInline: '20px',
96+
focusRing: {
97+
borderColor: '#8b5cf6',
98+
borderRadius: '14px',
99+
borderWidth: '3px',
100+
},
101+
},
102+
},
103+
],
104+
},
105+
{
106+
variant: ['icon'],
107+
pressed: [false, true],
108+
disabled: [false, true],
109+
iconName: ['thumbs-up'],
110+
pressedIconName: ['thumbs-up-filled'],
111+
onChange: [() => {}],
112+
ariaLabel: ['Toggle'],
113+
style: [
114+
{
115+
root: {
116+
color: {
117+
default: 'light-dark(#3b82f6, #93c5fd)',
118+
hover: 'light-dark(#2563eb, #60a5fa)',
119+
active: 'light-dark(#1d4ed8, #3b82f6)',
120+
disabled: 'light-dark(#93c5fd, #94a3b8)',
121+
pressed: 'light-dark(#1e40af, #2563eb)',
122+
},
123+
focusRing: {
124+
borderColor: '#3b82f6',
125+
borderRadius: '50%',
126+
borderWidth: '3px',
127+
},
128+
},
129+
},
130+
{
131+
root: {
132+
color: {
133+
default: 'light-dark(#8b5cf6, #c4b5fd)',
134+
hover: 'light-dark(#7c3aed, #a78bfa)',
135+
active: 'light-dark(#6d28d9, #8b5cf6)',
136+
disabled: 'light-dark(#c4b5fd, #94a3b8)',
137+
pressed: 'light-dark(#5b21b6, #7c3aed)',
138+
},
139+
focusRing: {
140+
borderColor: '#8b5cf6',
141+
borderRadius: '10px',
142+
borderWidth: '3px',
143+
},
144+
},
145+
},
146+
],
147+
},
148+
]);
149+
150+
export default function ToggleButtonStylePermutations() {
151+
return (
152+
<>
153+
<h1>Toggle Button Style Permutations</h1>
154+
<ScreenshotArea disableAnimations={true}>
155+
<PermutationsView
156+
permutations={permutations}
157+
render={permutation => <ToggleButton ariaLabel="Toggle button" {...permutation} />}
158+
/>
159+
</ScreenshotArea>
160+
</>
161+
);
162+
}

src/toggle-button/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const ToggleButton = React.forwardRef(
3333
pressed = false,
3434
nativeButtonAttributes,
3535
onChange,
36+
style,
3637
...props
3738
}: ToggleButtonProps,
3839
ref: React.Ref<ToggleButtonProps.Ref>
@@ -68,6 +69,7 @@ const ToggleButton = React.forwardRef(
6869
pressed={pressed}
6970
nativeButtonAttributes={nativeButtonAttributes}
7071
onChange={onChange}
72+
style={style}
7173
>
7274
{children}
7375
</InternalToggleButton>

src/toggle-button/interfaces.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ export interface ToggleButtonProps extends BaseComponentProps, Omit<BaseButtonPr
7272
* The event `detail` contains the current value for the `pressed` property.
7373
*/
7474
onChange?: NonCancelableEventHandler<ToggleButtonProps.ChangeDetail>;
75+
76+
/**
77+
* @awsuiSystem core
78+
*/
79+
style?: ToggleButtonProps.Style;
7580
}
7681

7782
export namespace ToggleButtonProps {
@@ -87,4 +92,46 @@ export namespace ToggleButtonProps {
8792
*/
8893
focus(options?: FocusOptions): void;
8994
}
95+
96+
export interface Style {
97+
root?: {
98+
background?: {
99+
active?: string;
100+
default?: string;
101+
disabled?: string;
102+
hover?: string;
103+
pressed?: string;
104+
};
105+
borderColor?: {
106+
active?: string;
107+
default?: string;
108+
disabled?: string;
109+
hover?: string;
110+
pressed?: string;
111+
};
112+
borderRadius?: string;
113+
borderWidth?: string;
114+
boxShadow?: {
115+
active?: string;
116+
default?: string;
117+
disabled?: string;
118+
hover?: string;
119+
pressed?: string;
120+
};
121+
color?: {
122+
active?: string;
123+
default?: string;
124+
disabled?: string;
125+
hover?: string;
126+
pressed?: string;
127+
};
128+
focusRing?: {
129+
borderColor?: string;
130+
borderRadius?: string;
131+
borderWidth?: string;
132+
};
133+
paddingBlock?: string;
134+
paddingInline?: string;
135+
};
136+
}
90137
}

src/toggle-button/internal.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import InternalButton from '../button/internal';
99
import { fireNonCancelableEvent } from '../internal/events';
1010
import { isDevelopment } from '../internal/is-development';
1111
import { ToggleButtonProps } from './interfaces';
12+
import { getToggleButtonStyles } from './style';
1213
import { getToggleIcon } from './util';
1314

1415
import styles from './styles.css.js';
@@ -28,6 +29,7 @@ export const InternalToggleButton = React.forwardRef(
2829
onChange,
2930
className,
3031
analyticsAction = 'click',
32+
style,
3133
...rest
3234
}: ToggleButtonProps & { __title?: string; analyticsAction?: string },
3335
ref: React.Ref<ToggleButtonProps.Ref>
@@ -62,7 +64,10 @@ export const InternalToggleButton = React.forwardRef(
6264
}}
6365
{...rest}
6466
ref={ref}
65-
nativeButtonAttributes={nativeButtonAttributes}
67+
nativeButtonAttributes={{
68+
...nativeButtonAttributes,
69+
style: { ...nativeButtonAttributes?.style, ...getToggleButtonStyles(style) } as React.CSSProperties,
70+
}}
6671
analyticsAction={analyticsAction}
6772
/>
6873
);

src/toggle-button/style.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
import { SYSTEM } from '../internal/environment';
4+
import customCssProps from '../internal/generated/custom-css-properties';
5+
import { ToggleButtonProps } from './interfaces';
6+
7+
export function getToggleButtonStyles(style: ToggleButtonProps['style']) {
8+
if (SYSTEM !== 'core' || !style?.root) {
9+
return undefined;
10+
}
11+
12+
return {
13+
borderRadius: style?.root?.borderRadius,
14+
borderWidth: style?.root?.borderWidth,
15+
paddingBlock: style?.root?.paddingBlock,
16+
paddingInline: style?.root?.paddingInline,
17+
...(style?.root?.background && {
18+
[customCssProps.styleBackgroundActive]: style.root.background?.active,
19+
[customCssProps.styleBackgroundDefault]: style.root.background?.default,
20+
[customCssProps.styleBackgroundDisabled]: style.root.background?.disabled,
21+
[customCssProps.styleBackgroundHover]: style.root.background?.hover,
22+
[customCssProps.styleBackgroundPressed]: style.root.background?.pressed,
23+
}),
24+
...(style?.root?.borderColor && {
25+
[customCssProps.styleBorderColorActive]: style.root.borderColor?.active,
26+
[customCssProps.styleBorderColorDefault]: style.root.borderColor?.default,
27+
[customCssProps.styleBorderColorDisabled]: style.root.borderColor?.disabled,
28+
[customCssProps.styleBorderColorHover]: style.root.borderColor?.hover,
29+
[customCssProps.styleBorderColorPressed]: style.root.borderColor?.pressed,
30+
}),
31+
...(style?.root?.boxShadow && {
32+
[customCssProps.styleBoxShadowActive]: style.root.boxShadow?.active,
33+
[customCssProps.styleBoxShadowDefault]: style.root.boxShadow?.default,
34+
[customCssProps.styleBoxShadowDisabled]: style.root.boxShadow?.disabled,
35+
[customCssProps.styleBoxShadowHover]: style.root.boxShadow?.hover,
36+
[customCssProps.styleBoxShadowPressed]: style.root.boxShadow?.pressed,
37+
}),
38+
...(style?.root?.color && {
39+
[customCssProps.styleColorActive]: style.root.color?.active,
40+
[customCssProps.styleColorDefault]: style.root.color?.default,
41+
[customCssProps.styleColorDisabled]: style.root.color?.disabled,
42+
[customCssProps.styleColorHover]: style.root.color?.hover,
43+
[customCssProps.styleColorPressed]: style.root.color?.pressed,
44+
}),
45+
...(style?.root?.focusRing && {
46+
[customCssProps.styleFocusRingBorderColor]: style.root.focusRing?.borderColor,
47+
[customCssProps.styleFocusRingBorderRadius]: style.root.focusRing?.borderRadius,
48+
[customCssProps.styleFocusRingBorderWidth]: style.root.focusRing?.borderWidth,
49+
}),
50+
};
51+
}

src/toggle-button/styles.scss

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@
44
*/
55

66
@use '../internal/styles/tokens' as awsui;
7+
@use '../internal/generated/custom-css-properties/index.scss' as custom-props;
78

89
.variant-normal.pressed {
9-
background: awsui.$color-background-toggle-button-normal-pressed;
10-
border-color: awsui.$color-border-toggle-button-normal-pressed;
11-
color: awsui.$color-text-toggle-button-normal-pressed;
10+
background: var(#{custom-props.$styleBackgroundPressed}, awsui.$color-background-toggle-button-normal-pressed);
11+
border-color: var(#{custom-props.$styleBorderColorPressed}, awsui.$color-border-toggle-button-normal-pressed);
12+
color: var(#{custom-props.$styleColorPressed}, awsui.$color-text-toggle-button-normal-pressed);
13+
box-shadow: var(#{custom-props.$styleBoxShadowPressed});
1214
}
1315

1416
.variant-icon.pressed {
15-
background: transparent;
16-
border-color: transparent;
17-
color: awsui.$color-text-toggle-button-icon-pressed;
17+
background: var(#{custom-props.$styleBackgroundPressed}, transparent);
18+
border-color: var(#{custom-props.$styleBorderColorPressed}, transparent);
19+
color: var(#{custom-props.$styleColorPressed}, awsui.$color-text-toggle-button-icon-pressed);
20+
box-shadow: var(#{custom-props.$styleBoxShadowPressed});
1821
}

0 commit comments

Comments
 (0)