Skip to content

Commit

Permalink
feat(ui): create <ToggleSwitch /> components
Browse files Browse the repository at this point in the history
  • Loading branch information
renanvalentin committed Jun 2, 2023
1 parent 03ec3f6 commit cd4fae9
Show file tree
Hide file tree
Showing 11 changed files with 490 additions and 2 deletions.
1 change: 1 addition & 0 deletions packages/ui/package.json
Expand Up @@ -30,6 +30,7 @@
},
"dependencies": {
"@radix-ui/react-tabs": "^1.0.3",
"@radix-ui/react-switch": "^1.0.3",
"@vanilla-extract/css": "^1.10.0",
"@vanilla-extract/css-utils": "^0.1.3",
"@vanilla-extract/recipes": "^0.3.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/assets/icons/info.component.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/ui/src/design-system/toggle-switch/index.ts
@@ -0,0 +1 @@
export { ToggleSwitch as Filled } from './toggle-switch.component';
@@ -0,0 +1,52 @@
import type { HTMLAttributes, ReactNode } from 'react';
import React from 'react';

import * as Switch from '@radix-ui/react-switch';

import { Box } from '../box';
import { Flex } from '../flex';
import * as Typography from '../typography';

import * as cx from './toggle-switch.css';

type Props = Omit<
HTMLAttributes<HTMLButtonElement>,
'children' | 'className'
> & {
icon?: ReactNode;
label?: string;
onCheckedChange?: (checked: boolean) => void;
disabled?: boolean;
checked?: boolean;
defaultChecked?: boolean;
required?: boolean;
id?: string;
};

export const ToggleSwitch = ({
label,
id,
icon,
disabled,
...props
}: Readonly<Props>): JSX.Element => {
return (
<Flex
alignItems="center"
className={disabled === true ? cx.disabled : undefined}
>
<label className={cx.label} htmlFor={id}>
<Typography.Body.Normal>{label}</Typography.Body.Normal>
</label>
{icon !== undefined && <Box className={cx.iconContainer}>{icon}</Box>}
<Switch.Root
{...props}
disabled={disabled}
className={cx.toogleSwitch}
id={id}
>
<Switch.Thumb className={cx.thumb} />
</Switch.Root>
</Flex>
);
};
90 changes: 90 additions & 0 deletions packages/ui/src/design-system/toggle-switch/toggle-switch.css.ts
@@ -0,0 +1,90 @@
import { sx, vars, style, createVar } from '../../design-tokens';

const boxShadow = createVar();

export const disabled = sx({
opacity: '$0_24',
});

export const root = style({});

export const toogleSwitch = style([
sx({
width: '$44',
height: '$24',
background: '$toggle_switch_container_bgColor_off',
borderRadius: '$small',
}),
{
padding: '0',
border: 'none',
position: 'relative',
WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',

':disabled': {
background: vars.colors.$toggle_switch_container_bgColor_disabled,
},

selectors: {
'&[data-state="checked"]:not(:disabled)': {
background: vars.colors.$toggle_switch_container_bgColor_on,
},
'&:active': {
outline: 'none',
},
'&:focus:not(:active)': {
outlineColor: `${vars.colors.$buttons_cta_container_outlineColor}`,
outlineWidth: vars.spacing.$4,
outlineStyle: 'solid',
},
},
},
]);

export const thumb = style([
sx({
width: '$20',
height: '$20',
borderRadius: '$circle',
}),
{
display: 'block',
backgroundColor: 'white',
boxShadow: boxShadow,
transition: 'transform 100ms',
transform: 'translateX(2px)',
willChange: 'transform',

vars: {
[boxShadow]:
'0px 1px 3px rgba(0, 0, 0, 0.1), 0px 1px 2px rgba(0, 0, 0, 0.06)',
},

selectors: {
'&[data-state="checked"]': {
transform: 'translateX(22px)',
},
},
},
]);

export const label = sx({
color: '$toggle_switch_label_color',
mr: '$8',
});

export const iconContainer = style([
sx({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
mr: '$8',
width: '$24',
height: '$24',
color: '$toggle_switch_label_color',
fontSize: '$25',
}),
{
overflow: 'hidden',
},
]);
229 changes: 229 additions & 0 deletions packages/ui/src/design-system/toggle-switch/toggle-switch.stories.tsx
@@ -0,0 +1,229 @@
import React from 'react';

import type { Meta } from '@storybook/react';

import { ReactComponent as InfoIcon } from '../../assets/icons/info.component.svg';
import { ThemeColorScheme, ThemeProvider } from '../../design-tokens';
import { Page, Variants, Section } from '../decorators';
import { Divider } from '../divider';
import { Grid } from '../grid';
import { Cell } from '../grid/cell.component';

import { ToggleSwitch } from './toggle-switch.component';

const subtitle = `The toggle switch represents a physical switch that allows users to turn things on or off. Use toggle switch controls to present users with two mutually exclusive options (such as on/off), where choosing an option provides immediate results.`;

export default {
title: 'Basic Input/Toggle switch',
component: ToggleSwitch,
decorators: [
(Story): JSX.Element => (
<Page title="Toggle switch" subtitle={subtitle}>
<Story />
</Page>
),
],
} as Meta;

const ToggleSwitchPreview = (): JSX.Element => (
<>
<Variants.Row>
<Variants.Cell>
<ToggleSwitch
label="Label"
id="rest"
defaultChecked
icon={<InfoIcon />}
/>
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch
label="Label"
id="hover"
defaultChecked
icon={<InfoIcon />}
/>
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch
label="Label"
id="pressed"
defaultChecked
icon={<InfoIcon />}
/>
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch
label="Label"
disabled
defaultChecked
icon={<InfoIcon />}
/>
</Variants.Cell>
</Variants.Row>
<Variants.Row>
<Variants.Cell>
<ToggleSwitch label="Label" id="rest" icon={<InfoIcon />} />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch label="Label" id="hover" icon={<InfoIcon />} />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch label="Label" id="pressed" icon={<InfoIcon />} />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch label="Label" disabled icon={<InfoIcon />} />
</Variants.Cell>
</Variants.Row>
<Variants.Row>
<Variants.Cell>
<ToggleSwitch label="Label" id="rest" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch label="Label" id="hover" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch label="Label" id="pressed" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch label="Label" disabled />
</Variants.Cell>
</Variants.Row>
<Variants.Row>
<Variants.Cell>
<ToggleSwitch id="rest" defaultChecked />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="hover" defaultChecked />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="pressed" defaultChecked />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch disabled defaultChecked />
</Variants.Cell>
</Variants.Row>
<Variants.Row>
<Variants.Cell>
<ToggleSwitch id="rest" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="hover" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="pressed" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch disabled />
</Variants.Cell>
</Variants.Row>
</>
);

const SwitchPreview = (): JSX.Element => (
<>
<Variants.Row>
<Variants.Cell>
<ToggleSwitch id="rest" defaultChecked />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="hover" defaultChecked />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="pressed" defaultChecked />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch disabled defaultChecked />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="focused" defaultChecked />
</Variants.Cell>
</Variants.Row>
<Variants.Row>
<Variants.Cell>
<ToggleSwitch id="rest" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="hover" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="pressed" />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch disabled />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch id="focused" />
</Variants.Cell>
</Variants.Row>
</>
);

export const Overview = (): JSX.Element => (
<Grid columns="$1">
<Cell>
<Section title="Variants">
<Variants.Table
headers={[
'Base control with label and icon',
'Base control with label',
'Simple base control',
]}
>
<Variants.Row>
<Variants.Cell>
<ToggleSwitch
label="Label"
id="toggle"
defaultChecked
icon={<InfoIcon />}
/>
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch label="Label" defaultChecked />
</Variants.Cell>
<Variants.Cell>
<ToggleSwitch defaultChecked />
</Variants.Cell>
</Variants.Row>
</Variants.Table>
<Divider my="$64" />
</Section>
<Section title="Main components">
<Variants.Table
headers={['Rest', 'Hover', 'Active / pressed', 'Disabled']}
>
<ToggleSwitchPreview />
</Variants.Table>

<ThemeProvider colorScheme={ThemeColorScheme.Dark}>
<Variants.Table>
<ToggleSwitchPreview />
</Variants.Table>
</ThemeProvider>
</Section>
<Divider my="$64" />
<Section title="Toggle switch items 🔒">
<Variants.Table
headers={['Rest', 'Hover', 'Active / pressed', 'Disabled', 'Focused']}
>
<SwitchPreview />
</Variants.Table>

<ThemeProvider colorScheme={ThemeColorScheme.Dark}>
<Variants.Table>
<SwitchPreview />
</Variants.Table>
</ThemeProvider>
</Section>
</Cell>
</Grid>
);

Overview.parameters = {
pseudo: {
hover: '#hover',
focus: '#focused',
active: '#pressed',
},
};

0 comments on commit cd4fae9

Please sign in to comment.