Skip to content

Commit

Permalink
feat(vara-ui): add transitions and dark mode to Checkbox (#1690)
Browse files Browse the repository at this point in the history
Co-authored-by: Nikita Yutanov <[email protected]>
  • Loading branch information
ereburg and nikitayutanov authored Jan 9, 2025
1 parent 9260f69 commit 8772cf4
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 33 deletions.
10 changes: 10 additions & 0 deletions utils/vara-ui/src/components/checkbox/assets/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
173 changes: 158 additions & 15 deletions utils/vara-ui/src/components/checkbox/checkbox.module.scss
Original file line number Diff line number Diff line change
@@ -1,36 +1,179 @@
@use '../../utils' as *;

.label {
--color: #000;
--error-color: rgba(255, 51, 51, 0.8);

@include darkMode() {
--color: #fff;
--error-color: #d73b4f;
}

display: flex;
align-items: center;
gap: var(--gap);

font-size: var(--font-size);
font-weight: 400;
line-height: var(--line-height);
color: var(--color);

cursor: pointer;

&.disabled {
&:has(.input:disabled) {
pointer-events: none;
opacity: 0.3;
}
}

.input {
appearance: none;
cursor: inherit;
margin: 0 10px 0 0;
margin: 0;
}

.checkbox {
width: 15px;
height: 15px;
background-image: url("data:image/svg+xml,%3Csvg width='15' height='15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='.5' y='.5' width='14' height='14' rx='1.5' stroke='%23909090'/%3E%3C/svg%3E");
.checkbox.box {
--background-color: transparent;
--border-color: #d0d5dd;
--disabled-background-color: #eceded;
--checked-color: #00ffc4;

@include darkMode() {
--background-color: rgba(255, 255, 255, 0.03);
--border-color: rgba(255, 255, 255, 0.04);
--disabled-background-color: rgba(40, 44, 48, 0.1);
--checked-color: #30ffcf;
}

width: var(--checkbox-size);
height: var(--checkbox-size);

display: flex;
align-items: center;

background-color: var(--background-color);
border: 1px solid var(--border-color);
border-radius: 2px;

transition: 0.25s border-color ease, 0.25s background-color ease;

&::before {
content: '';
opacity: 0;

width: 100%;
height: 100%;

background-color: #000;
mask: url(./assets/check.svg) center/cover no-repeat;

transition: 0.25s opacity ease, 0.25s background-color ease;

.input:checked + & {
opacity: 1;
}

.input:not(:disabled)[aria-invalid='true'] + & {
background-color: #fff;
}

.input:disabled + & {
background-color: var(--border-color);
}
}

.input:not(:disabled):checked + & {
background-color: var(--checked-color);
border-color: var(--checked-color);
}

.input:not(:disabled)[aria-invalid='true'] + & {
border-color: var(--error-color);
}

.input:not(:disabled):checked[aria-invalid='true'] + & {
background-color: var(--error-color);
}

&:checked {
background-image: url("data:image/svg+xml,%3Csvg width='15' height='15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='.5' y='.5' width='14' height='14' rx='1.5' stroke='%230ED3A3'/%3E%3Cpath d='M12.163 4.45a.75.75 0 0 1 0 1.058l-5.595 5.955a.75.75 0 0 1-.547.232.75.75 0 0 1-.548-.232L3.643 9.49a.75.75 0 1 1 1.088-1.027l1.32 1.402 5.047-5.37a.75.75 0 0 1 1.065-.045Z' fill='%230ED3A3'/%3E%3C/svg%3E");
.input:disabled + & {
background-color: var(--disabled-background-color);
}
}

.switch {
width: 25px;
.switch.box {
--border-color: #909090;
--checked-color: #0ed3a3;
--disabled-color: rgba(144, 144, 144, 0.3);

@include darkMode() {
--border-color: rgba(255, 255, 255, 0.08);
--checked-color: #00ffc4;
--disabled-color: rgba(255, 255, 255, 0.03);
}

width: 26px;
height: 15px;
background-image: url("data:image/svg+xml,%3Csvg width='25' height='15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='.5' y='.5' width='24' height='14' rx='7'/%3E%3Ccircle cx='7.5' cy='7.5' r='3.5' fill='%23909090'/%3E%3Crect x='.5' y='.5' width='24' height='14' rx='7' stroke='%23909090'/%3E%3C/svg%3E");
padding: 0 4px;

display: flex;
align-items: center;

border: 1px solid var(--border-color);
border-radius: 16px;

transition: 0.25s border-color ease;

&::before {
content: '';

width: 7px;
height: 7px;

background-color: var(--border-color);
border-radius: 50%;

transition: transform 0.25s ease, background-color 0.25s ease;

.input:checked + & {
transform: translateX(9px);
}

&:checked {
background-image: url("data:image/svg+xml,%3Csvg width='25' height='15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='17.5' cy='7.5' r='3.5' fill='%230ED3A3'/%3E%3Crect x='.5' y='.5' width='24' height='14' rx='7' stroke='%230ED3A3'/%3E%3C/svg%3E");
.input:not(:disabled):checked + & {
background-color: var(--checked-color);
}

.input:not(:disabled)[aria-invalid='true'] + & {
background-color: var(--error-color);
}

.input:disabled + & {
background-color: var(--disabled-color);
}
}

.input:not(:disabled):checked + & {
border-color: var(--checked-color);
}

.input:not(:disabled)[aria-invalid='true'] + & {
border-color: var(--error-color);
}

.input:disabled + & {
border-color: var(--disabled-color);
}
}

.default {
--gap: 12px;
--font-size: 14px;
--line-height: 20px;

--checkbox-size: 18px;
}

.small {
--gap: 10px;
--font-size: 12px;
--line-height: 22px;

--checkbox-size: 15px;
}
18 changes: 17 additions & 1 deletion utils/vara-ui/src/components/checkbox/checkbox.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,23 @@ type Story = StoryObj<Type>;
const meta: Meta<Type> = {
title: 'Checkbox',
component: Checkbox,
args: { label: 'Label' },
args: {
label: 'Label',
disabled: false,
size: 'default',
type: 'checkbox',
error: undefined,
},
argTypes: {
size: {
options: ['small', 'default'],
control: { type: 'select' },
},
type: {
options: ['checkbox', 'switch'],
control: { type: 'select' },
},
},
};

const Default: Story = {
Expand Down
33 changes: 16 additions & 17 deletions utils/vara-ui/src/components/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import { InputHTMLAttributes, forwardRef } from 'react';
import cx from 'clsx';

import styles from './checkbox.module.scss';

type Props = InputHTMLAttributes<HTMLInputElement> & {
type Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> & {
label: string;
type?: 'switch';
type?: 'switch' | 'checkbox';
size?: 'small' | 'default';
error?: string;
};

const Checkbox = forwardRef<HTMLInputElement, Props>(({ label, className, type, ...attrs }, ref) => {
const { disabled } = attrs;

return (
<label className={cx(styles.label, className, disabled && styles.disabled)}>
<input
type="checkbox"
className={cx(styles.input, type === 'switch' ? styles.switch : styles.checkbox)}
ref={ref}
{...attrs}
/>
const Checkbox = forwardRef<HTMLInputElement, Props>(
({ label, className, type = 'checkbox', size = 'default', error, ...attrs }, ref) => {
return (
<label className={cx(styles.label, className, styles[size])}>
<input type="checkbox" className={styles.input} ref={ref} aria-invalid={Boolean(error)} {...attrs} />
<span className={cx(styles.box, styles[type])} />

{label}
</label>
);
});
{label}
</label>
);
},
);

export { Checkbox };
export type { Props as CheckboxProps };

0 comments on commit 8772cf4

Please sign in to comment.