Skip to content

Commit

Permalink
feat(core): RadioButton revisited!
Browse files Browse the repository at this point in the history
  • Loading branch information
ggdaltoso committed Feb 9, 2024
1 parent c590910 commit cbf52c6
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 324 deletions.
1 change: 1 addition & 0 deletions packages/core/.storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ImageLoader } from 'esbuild-vanilla-image-loader';
export default {
// stories: [, '../stories/(?!all)*.stories.tsx'],
stories: [
'../stories/radiobutton.stories.tsx',
'../stories/titlebar.stories.tsx',
'../stories/range.stories.tsx',
'../stories/progressbar.stories.tsx',
Expand Down
62 changes: 62 additions & 0 deletions packages/core/components/RadioButton/RadioButton.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {
radioChecked,
radioCheckedDisabled,
radioUnchecked,
radioUncheckedDisabled,
} from './radioButtonStates';
import { globalStyle, style } from '@vanilla-extract/css';
import { contract } from '../ThemeProvider/themes/contract.css';

export const icon = style({
width: contract.space[12],
height: contract.space[12],
display: 'inline-block',
position: 'absolute',
left: contract.space[0],
top: contract.space[0],
backgroundImage: `url('${radioUnchecked}')`,
imageRendering: 'pixelated',
});

export const text = style({
padding: contract.space[1],
userSelect: 'none',
position: 'absolute',
top: '0',
left: contract.space[18],
});

export const label = style({
position: 'relative',
marginBottom: contract.space[10],
display: 'block',
selectors: {
'&:has(:disabled)': {
color: contract.colors.materialTextDisabled,
textShadow: `0.5px 0.5px ${contract.colors.materialTextDisabledShadow}`,
},
},
});

export const field = style({
margin: 0,
opacity: 0,
});

globalStyle(`${field}:focus ~ ${text}, &:active + ${text}`, {
borderWidth: contract.space[1],
borderStyle: 'dotted',
padding: 0,
});

globalStyle(`${field}:checked + ${icon}`, {
backgroundImage: `url('${radioChecked}')`,
});

globalStyle(`${field}:disabled + ${icon}`, {
backgroundImage: `url('${radioUncheckedDisabled}')`,
});

globalStyle(`${field}:checked:disabled + ${icon}`, {
backgroundImage: `url('${radioCheckedDisabled}')`,
});
2 changes: 1 addition & 1 deletion packages/core/components/RadioButton/RadioButton.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import { fireEvent, render } from '../shared/test/utils';
import RadioButton from './RadioButton';
import { RadioButton } from './RadioButton';

describe('<RadioButton />', () => {
describe('Snapshots', () => {
Expand Down
95 changes: 13 additions & 82 deletions packages/core/components/RadioButton/RadioButton.tsx
Original file line number Diff line number Diff line change
@@ -1,89 +1,20 @@
import React, { forwardRef } from 'react';
import styled, { css, th } from '@xstyled/styled-components';

import {
radioChecked,
radioCheckedDisabled,
radioUnchecked,
radioUncheckedDisabled,
} from './radioButtonStates';
import { field, icon, label, text } from './RadioButton.css';

export type RadioButtonProps = React.InputHTMLAttributes<HTMLInputElement>;

const Icon = styled.span`
width: 12px;
height: 12px;
content: '';
display: inline-block;
position: absolute;
left: 0;
top: 0;
background-image: url(${radioUnchecked});
`;

const Text = styled.span`
padding: 1;
user-select: none;
position: absolute;
top: 0;
left: 18px;
`;

const Field = styled.input.attrs<RadioButtonProps>({
type: 'radio',
})`
margin: 0;
opacity: 0;
&:focus ~ ${Text}, &:active + ${Text} {
border-width: 1;
border-style: dotted;
padding: 0;
}
&:checked + ${Icon} {
background-image: url(${radioChecked});
}
&:disabled + ${Icon} {
background-image: url(${radioUncheckedDisabled});
}
&:checked:disabled + ${Icon} {
background-image: url(${radioCheckedDisabled});
}
`;

const Label = styled.label<Pick<RadioButtonProps, 'disabled'>>`
position: relative;
margin-bottom: 10;
display: block;
${({ disabled }) =>
disabled &&
css`
color: materialTextDisabled;
text-shadow: 0.5px 0.5px ${th('colors.materialTextDisabledShadow')};
`}
`;

const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(
export const RadioButton = forwardRef<HTMLInputElement, RadioButtonProps>(
({ children, disabled, ...props }, ref) => (
<Label disabled={disabled}>
<Field disabled={disabled} {...props} ref={ref} />
<Icon />
<Text>{children}</Text>
</Label>
<label className={label}>
<input
type="radio"
disabled={disabled}
className={field}
ref={ref}
{...props}
/>
<span className={icon} />
<span className={text}>{children}</span>
</label>
),
);

RadioButton.defaultProps = {
children: '',
disabled: false,
};

export default RadioButton;

0 comments on commit cbf52c6

Please sign in to comment.