Skip to content

Commit

Permalink
[Checkbox] Component and Hook (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
atomiks authored Apr 2, 2024
1 parent 087276d commit 6f74390
Show file tree
Hide file tree
Showing 36 changed files with 2,367 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as React from 'react';
import { styled } from '@mui/system';
import { Checkbox as BaseCheckbox } from '@mui/base/Checkbox';
import HorizontalRule from '@mui/icons-material/HorizontalRule';

export default function UnstyledCheckboxIndeterminate() {
return (
<div style={{ display: 'flex', gap: 12 }}>
<Checkbox aria-label="Indeterminate checkbox" indeterminate>
<Indicator>
<HorizontalRuleIcon />
</Indicator>
</Checkbox>
<Checkbox aria-label="Indeterminate disabled checkbox" indeterminate disabled>
<Indicator>
<HorizontalRuleIcon />
</Indicator>
</Checkbox>
</div>
);
}

const blue = {
400: '#3399FF',
600: '#0072E6',
800: '#004C99',
};

const grey = {
100: '#E5EAF2',
};

const Checkbox = styled(BaseCheckbox)(
({ theme }) => `
width: 24px;
height: 24px;
padding: 0;
border-radius: 4px;
border: 2px solid ${blue[600]};
background: none;
transition-property: background, border-color;
transition-duration: 0.15s;
outline: none;
&[data-disabled] {
opacity: 0.4;
cursor: not-allowed;
}
&:focus-visible {
outline: 2px solid ${theme.palette.mode === 'dark' ? blue[800] : blue[400]};
outline-offset: 2px;
}
&[data-state='checked'],
&[data-state='mixed'] {
border-color: transparent;
background: ${blue[600]};
}
`,
);

const HorizontalRuleIcon = styled(HorizontalRule)`
height: 100%;
width: 100%;
`;

const Indicator = styled(BaseCheckbox.Indicator)`
color: ${grey[100]};
height: 100%;
display: inline-block;
visibility: hidden;
&[data-state='checked'],
&[data-state='mixed'] {
visibility: visible;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as React from 'react';
import { styled } from '@mui/system';
import { Checkbox as BaseCheckbox } from '@mui/base/Checkbox';
import HorizontalRule from '@mui/icons-material/HorizontalRule';

export default function UnstyledCheckboxIndeterminate() {
return (
<div style={{ display: 'flex', gap: 12 }}>
<Checkbox aria-label="Indeterminate checkbox" indeterminate>
<Indicator>
<HorizontalRuleIcon />
</Indicator>
</Checkbox>
<Checkbox aria-label="Indeterminate disabled checkbox" indeterminate disabled>
<Indicator>
<HorizontalRuleIcon />
</Indicator>
</Checkbox>
</div>
);
}

const blue = {
400: '#3399FF',
600: '#0072E6',
800: '#004C99',
};

const grey = {
100: '#E5EAF2',
};

const Checkbox = styled(BaseCheckbox)(
({ theme }) => `
width: 24px;
height: 24px;
padding: 0;
border-radius: 4px;
border: 2px solid ${blue[600]};
background: none;
transition-property: background, border-color;
transition-duration: 0.15s;
outline: none;
&[data-disabled] {
opacity: 0.4;
cursor: not-allowed;
}
&:focus-visible {
outline: 2px solid ${theme.palette.mode === 'dark' ? blue[800] : blue[400]};
outline-offset: 2px;
}
&[data-state='checked'],
&[data-state='mixed'] {
border-color: transparent;
background: ${blue[600]};
}
`,
);

const HorizontalRuleIcon = styled(HorizontalRule)`
height: 100%;
width: 100%;
`;

const Indicator = styled(BaseCheckbox.Indicator)`
color: ${grey[100]};
height: 100%;
display: inline-block;
visibility: hidden;
&[data-state='checked'],
&[data-state='mixed'] {
visibility: visible;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Checkbox aria-label="Indeterminate checkbox" indeterminate>
<Indicator>
<HorizontalRuleIcon />
</Indicator>
</Checkbox>
<Checkbox aria-label="Indeterminate disabled checkbox" indeterminate disabled>
<Indicator>
<HorizontalRuleIcon />
</Indicator>
</Checkbox>
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import * as React from 'react';
import { styled } from '@mui/system';
import { Checkbox as BaseCheckbox } from '@mui/base/Checkbox';
import HorizontalRule from '@mui/icons-material/HorizontalRule';
import Check from '@mui/icons-material/Check';

const colors = ['Red', 'Green', 'Blue'];

export default function UnstyledCheckboxIndeterminateGroup() {
const [checkedValues, setCheckedValues] = React.useState([false, true, false]);

const isChecked = checkedValues.every((value) => value);
const isIndeterminate = checkedValues.some((value) => value) && !isChecked;

const id = React.useId();

return (
<div style={{ display: 'flex', flexDirection: 'column' }}>
<ListRoot>
<Checkbox
id={id}
aria-controls={colors.map((color) => `${id}-${color}`).join(' ')}
indeterminate={isIndeterminate}
checked={isChecked}
onChange={(event) => {
const checked = event.target.checked;
setCheckedValues([checked, checked, checked]);
}}
>
<Indicator>
{isIndeterminate ? <HorizontalRuleIcon /> : <CheckIcon />}
</Indicator>
</Checkbox>
<Label htmlFor={id} onMouseDown={(e) => e.preventDefault()}>
Colors
</Label>
</ListRoot>
<List>
{colors.map((color, index) => (
<ListItem key={color}>
<Checkbox
id={`${id}-${color}`}
checked={checkedValues[index]}
onChange={(event) => {
const newCheckedValues = [...checkedValues];
newCheckedValues[index] = event.target.checked;
setCheckedValues(newCheckedValues);
}}
>
<Indicator>
<CheckIcon />
</Indicator>
</Checkbox>
<Label
htmlFor={`${id}-${color}`}
onMouseDown={(e) => e.preventDefault()}
>
{color}
</Label>
</ListItem>
))}
</List>
</div>
);
}

const blue = {
400: '#3399FF',
600: '#0072E6',
800: '#004C99',
};

const grey = {
100: '#E5EAF2',
400: '#B0B8C4',
800: '#303740',
};

const Checkbox = styled(BaseCheckbox)(
({ theme }) => `
width: 24px;
height: 24px;
padding: 0;
border-radius: 4px;
border: 2px solid ${blue[600]};
background: none;
transition-property: background, border-color;
transition-duration: 0.15s;
outline: none;
&[data-disabled] {
opacity: 0.4;
cursor: not-allowed;
}
&:focus-visible {
outline: 2px solid ${theme.palette.mode === 'dark' ? blue[800] : blue[400]};
outline-offset: 2px;
}
&[data-state="checked"], &[data-state="mixed"] {
border-color: transparent;
background: ${blue[600]};
}
`,
);

const HorizontalRuleIcon = styled(HorizontalRule)`
height: 100%;
width: 100%;
`;

const CheckIcon = styled(Check)`
height: 100%;
width: 100%;
`;

const Indicator = styled(BaseCheckbox.Indicator)`
height: 100%;
display: inline-block;
visibility: hidden;
color: ${grey[100]};
&[data-state='checked'],
&[data-state='mixed'] {
visibility: visible;
}
`;

const ListRoot = styled('div')`
display: flex;
align-items: center;
margin-bottom: 8px;
`;

const List = styled('ul')`
list-style: none;
padding: 0;
margin: 0;
margin-left: 32px;
`;

const ListItem = styled('li')`
display: flex;
align-items: center;
&:not(:last-child) {
margin-bottom: 8px;
}
`;

const Label = styled('label')(
({ theme }) => `
padding-left: 8px;
color: ${theme.palette.mode === 'dark' ? grey[400] : grey[800]};
`,
);
Loading

0 comments on commit 6f74390

Please sign in to comment.