Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vara-ui): add transitions, dark mode and error state to Radio #1697

Merged
merged 2 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions utils/vara-ui/src/components/checkbox/checkbox.stories.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Meta, StoryObj } from '@storybook/react';

import { Checkbox } from './checkbox';

type Type = typeof Checkbox;
Expand All @@ -23,6 +24,7 @@ const meta: Meta<Type> = {
options: ['checkbox', 'switch'],
control: { type: 'select' },
},
error: { control: 'text' },
},
};

Expand Down
4 changes: 2 additions & 2 deletions utils/vara-ui/src/components/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { InputHTMLAttributes, forwardRef } from 'react';
import { InputHTMLAttributes, ReactNode, forwardRef } from 'react';
import cx from 'clsx';

import styles from './checkbox.module.scss';
Expand All @@ -7,7 +7,7 @@ type Props = Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> & {
label: string;
type?: 'switch' | 'checkbox';
size?: 'small' | 'default';
error?: string;
error?: ReactNode;
};

const Checkbox = forwardRef<HTMLInputElement, Props>(
Expand Down
83 changes: 75 additions & 8 deletions utils/vara-ui/src/components/radio/radio.module.scss
Original file line number Diff line number Diff line change
@@ -1,24 +1,91 @@
@use '../../utils.scss' as *;

.label {
@include lightDark(color, #000, #fff);

display: flex;
align-items: center;
cursor: pointer;

&.disabled {
font-size: var(--font-size);
font-weight: 400;
line-height: var(--line-height);

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

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

.box {
@include lightDark(background-color, transparent, rgba(255, 255, 255, 0.03));
@include lightDark(--border-color, #d0d5dd, rgba(255, 255, 255, 0.04));
@include lightDark(--checked-color, #0ed3a3, #00ffc4);
@include lightDark(--error-color, rgba(255, 50, 49, 0.8), #d73b4f);
@include lightDark(--disabled-color, #eceded, rgba(40, 44, 48, 0.1));

width: var(--size);
height: var(--size);
margin-right: 10px;

display: flex;
align-items: center;
justify-content: center;

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

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

&::before {
content: '';

width: 7px;
height: 7px;

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%3Ccircle cx='7.5' cy='7.5' r='7' stroke='%23909090'/%3E%3C/svg%3E");
border-radius: 50%;

&:checked {
background-image: url("data:image/svg+xml,%3Csvg width='15' height='15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='7.5' cy='7.5' r='3.5' fill='%230ED3A3'/%3E%3Ccircle cx='7.5' cy='7.5' r='7' stroke='%230ED3A3'/%3E%3C/svg%3E");
transition: background-color 0.25s ease;

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

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

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

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

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

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

.small {
--size: 15px;
--font-size: 12px;
--line-height: 22px;
}

.default {
--size: 18px;
--font-size: 14px;
--line-height: 24px;
}
15 changes: 14 additions & 1 deletion utils/vara-ui/src/components/radio/radio.stories.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Meta, StoryObj } from '@storybook/react';

import { Radio } from './radio';

type Type = typeof Radio;
Expand All @@ -7,7 +8,19 @@ type Story = StoryObj<Type>;
const meta: Meta<Type> = {
title: 'Radio',
component: Radio,
args: { label: 'Label' },
args: {
label: 'Label',
disabled: false,
error: undefined,
},
argTypes: {
size: {
options: ['small', 'default'],
control: { type: 'select' },
},
disabled: { control: 'boolean' },
error: { control: 'text' },
},
};

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

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

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

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

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

{label}
</label>
Expand Down
Loading