Skip to content

Commit c136525

Browse files
R894charlesBochetlucasbordeau
authored andcommitted
4848 - Update Checkbox component (#4883)
# Summary * Add hover state which defaults to **false** * Add disable state ![chrome_KV2AltSmBK](https://github.com/twentyhq/twenty/assets/54629307/976fba28-b975-4acc-9d06-c14c4fe339d8) closes #4848 --------- Co-authored-by: Charles Bochet <[email protected]> Co-authored-by: Lucas Bordeau <[email protected]>
1 parent b3f54e4 commit c136525

File tree

2 files changed

+78
-24
lines changed

2 files changed

+78
-24
lines changed

packages/twenty-front/src/modules/ui/input/components/Checkbox.tsx

+63-19
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,63 @@ export enum CheckboxSize {
2222
type CheckboxProps = {
2323
checked: boolean;
2424
indeterminate?: boolean;
25+
hoverable?: boolean;
2526
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
2627
onCheckedChange?: (value: boolean) => void;
2728
variant?: CheckboxVariant;
2829
size?: CheckboxSize;
2930
shape?: CheckboxShape;
3031
className?: string;
32+
disabled?: boolean;
3133
};
3234

33-
const StyledInputContainer = styled.div`
34-
align-items: center;
35-
display: flex;
36-
position: relative;
37-
`;
38-
3935
type InputProps = {
4036
checkboxSize: CheckboxSize;
4137
variant: CheckboxVariant;
4238
indeterminate?: boolean;
39+
hoverable?: boolean;
4340
shape?: CheckboxShape;
4441
isChecked?: boolean;
42+
disabled?: boolean;
4543
};
4644

45+
const StyledInputContainer = styled.div<InputProps>`
46+
--size: ${({ checkboxSize }) =>
47+
checkboxSize === CheckboxSize.Large ? '32px' : '24px'};
48+
align-items: center;
49+
border-radius: ${({ theme, shape }) =>
50+
shape === CheckboxShape.Rounded
51+
? theme.border.radius.rounded
52+
: theme.border.radius.sm};
53+
54+
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
55+
display: flex;
56+
padding: ${({ checkboxSize }) =>
57+
checkboxSize === CheckboxSize.Large ? '6px' : '5px'};
58+
position: relative;
59+
${({ hoverable, isChecked, theme, indeterminate, disabled }) => {
60+
if (!hoverable || disabled === true) return '';
61+
return `&:hover{
62+
background-color: ${
63+
indeterminate || isChecked
64+
? theme.color.blue10
65+
: theme.background.transparent.light
66+
};
67+
}}
68+
}`;
69+
}}
70+
`;
71+
4772
const StyledInput = styled.input<InputProps>`
48-
cursor: pointer;
73+
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
4974
margin: 0;
5075
opacity: 0;
5176
position: absolute;
5277
z-index: 10;
53-
5478
& + label {
5579
--size: ${({ checkboxSize }) =>
5680
checkboxSize === CheckboxSize.Large ? '18px' : '12px'};
57-
cursor: pointer;
81+
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
5882
height: calc(var(--size) + 2px);
5983
padding: 0;
6084
position: relative;
@@ -66,8 +90,16 @@ const StyledInput = styled.input<InputProps>`
6690
checkboxSize === CheckboxSize.Large ? '18px' : '12px'};
6791
background: ${({ theme, indeterminate, isChecked }) =>
6892
indeterminate || isChecked ? theme.color.blue : 'transparent'};
69-
border-color: ${({ theme, indeterminate, isChecked, variant }) => {
93+
border-color: ${({
94+
theme,
95+
indeterminate,
96+
isChecked,
97+
variant,
98+
disabled,
99+
}) => {
70100
switch (true) {
101+
case disabled:
102+
return theme.background.transparent.medium;
71103
case indeterminate || isChecked:
72104
return theme.color.blue;
73105
case variant === CheckboxVariant.Primary:
@@ -83,21 +115,21 @@ const StyledInput = styled.input<InputProps>`
83115
? theme.border.radius.rounded
84116
: theme.border.radius.sm};
85117
border-style: solid;
86-
border-width: ${({ variant }) =>
87-
variant === CheckboxVariant.Tertiary ? '2px' : '1px'};
118+
border-width: ${({ variant, checkboxSize }) =>
119+
checkboxSize === CheckboxSize.Large ||
120+
variant === CheckboxVariant.Tertiary
121+
? '1.43px'
122+
: '1px'};
88123
content: '';
89-
cursor: pointer;
124+
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
90125
display: inline-block;
91126
height: var(--size);
92127
width: var(--size);
93128
}
94129
95130
& + label > svg {
96-
--padding: ${({ checkboxSize, variant }) =>
97-
checkboxSize === CheckboxSize.Large ||
98-
variant === CheckboxVariant.Tertiary
99-
? '2px'
100-
: '1px'};
131+
--padding: ${({ checkboxSize }) =>
132+
checkboxSize === CheckboxSize.Large ? '2px' : '1px'};
101133
--size: ${({ checkboxSize }) =>
102134
checkboxSize === CheckboxSize.Large ? '16px' : '12px'};
103135
height: var(--size);
@@ -117,7 +149,9 @@ export const Checkbox = ({
117149
variant = CheckboxVariant.Primary,
118150
size = CheckboxSize.Small,
119151
shape = CheckboxShape.Squared,
152+
hoverable = false,
120153
className,
154+
disabled = false,
121155
}: CheckboxProps) => {
122156
const [isInternalChecked, setIsInternalChecked] =
123157
React.useState<boolean>(false);
@@ -135,7 +169,16 @@ export const Checkbox = ({
135169
const checkboxId = 'checkbox' + v4();
136170

137171
return (
138-
<StyledInputContainer className={className}>
172+
<StyledInputContainer
173+
checkboxSize={size}
174+
variant={variant}
175+
shape={shape}
176+
isChecked={isInternalChecked}
177+
hoverable={hoverable}
178+
indeterminate={indeterminate}
179+
className={className}
180+
disabled={disabled}
181+
>
139182
<StyledInput
140183
autoComplete="off"
141184
type="checkbox"
@@ -149,6 +192,7 @@ export const Checkbox = ({
149192
shape={shape}
150193
isChecked={isInternalChecked}
151194
onChange={handleChange}
195+
disabled={disabled}
152196
/>
153197
<label htmlFor={checkboxId}>
154198
{indeterminate ? (

packages/twenty-front/src/modules/ui/input/components/__stories__/Checkbox.stories.tsx

+15-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export const Default: Story = {
2020
args: {
2121
checked: false,
2222
indeterminate: false,
23+
hoverable: false,
24+
disabled: false,
2325
variant: CheckboxVariant.Primary,
2426
size: CheckboxSize.Small,
2527
shape: CheckboxShape.Squared,
@@ -34,19 +36,22 @@ export const Catalog: CatalogStory<Story, typeof Checkbox> = {
3436
size: { control: false },
3537
indeterminate: { control: false },
3638
checked: { control: false },
39+
hoverable: { control: false },
3740
shape: { control: false },
3841
},
3942
parameters: {
4043
catalog: {
4144
dimensions: [
4245
{
4346
name: 'state',
44-
values: ['unchecked', 'checked', 'indeterminate'],
47+
values: ['disabled', 'unchecked', 'checked', 'indeterminate'],
4548
props: (state: string) => {
49+
if (state === 'disabled') {
50+
return { disabled: true };
51+
}
4652
if (state === 'checked') {
4753
return { checked: true };
4854
}
49-
5055
if (state === 'indeterminate') {
5156
return { indeterminate: true };
5257
}
@@ -59,9 +64,14 @@ export const Catalog: CatalogStory<Story, typeof Checkbox> = {
5964
props: (shape: CheckboxShape) => ({ shape }),
6065
},
6166
{
62-
name: 'variant',
63-
values: Object.values(CheckboxVariant),
64-
props: (variant: CheckboxVariant) => ({ variant }),
67+
name: 'isHoverable',
68+
values: ['default', 'hoverable'],
69+
props: (isHoverable: string) => {
70+
if (isHoverable === 'hoverable') {
71+
return { hoverable: true };
72+
}
73+
return {};
74+
},
6575
},
6676
{
6777
name: 'size',

0 commit comments

Comments
 (0)