Skip to content

Commit

Permalink
Merge pull request #17 from fortanix/feature/radio
Browse files Browse the repository at this point in the history
Radio Button
  • Loading branch information
mkrause authored Nov 14, 2024
2 parents 4c00c20 + 1cf0f18 commit be59715
Show file tree
Hide file tree
Showing 9 changed files with 515 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/components/forms/controls/Radio/Radio.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

@use '../../../../styling/defs.scss' as bk;

@layer baklava.components {
.bk-radio {
@include bk.component-base(bk-radio);

cursor: pointer;

appearance: none;
width: 18px;
aspect-ratio: 1;

border-radius: bk.$border-radius-circle;
background: transparent;
border: 1px solid bk.$theme-radio-default;

// doing the inner cicle on checked / disabled+checked options without SVG.
background-clip: content-box;
padding: 3px; // distance between background filling and the center of border
// since the border is 2px when checked, it's center is 1px, thus for a distance of 2px we need to have 1 + 2 = 3px.

&:checked {
background-color: bk.$theme-radio-selected;
border: 2px solid bk.$theme-radio-selected;
}
&:disabled {
border: 1px solid bk.$theme-radio-disabled;
background-color: transparent;

&:checked {
border: 2px solid bk.$theme-radio-non-active;
background-color: bk.$theme-radio-non-active;
}
}
&:focus-visible, &.pseudo-focused {
// those have !important to override CSS rules on layer accessibility
outline: 2px solid bk.$theme-radio-focus !important;
outline-offset: 0 !important;
}

@media (prefers-reduced-motion: no-preference) {
transition: none 100ms ease-out;
transition-property: background-color, background-position, border-color;
}
}
}
76 changes: 76 additions & 0 deletions src/components/forms/controls/Radio/Radio.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import type { Meta, StoryObj } from '@storybook/react';

import * as React from 'react';

import { Radio } from './Radio.tsx';

import cl from './Radio.module.scss';


type RadioArgs = React.ComponentProps<typeof Radio>;
type Story = StoryObj<RadioArgs>;

export default {
component: Radio,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
},
args: {},
decorators: [
Story => <form onSubmit={event => { event.preventDefault(); }}><Story/></form>,
],
render: (args) => <Radio {...args}/>,
} satisfies Meta<RadioArgs>;


export const Checked: Story = {
args: { defaultChecked: true },
};

export const Unchecked: Story = {
args: {},
};

export const DisabledSelected: Story = {
name: 'Disabled (selected)',
args: {
defaultChecked: true,
disabled: true,
},
};

export const DisabledUnselected: Story = {
name: 'Disabled (unselected)',
args: { disabled: true },
};

export const FocusedSelected: Story = {
name: 'Focused (selected)',
args: {
className: cl['pseudo-focused'],
defaultChecked: true,
},
};

export const FocusedUnselected: Story = {
name: 'Focused (unselected)',
args: {
className: cl['pseudo-focused'],
},
};

export const FocusedDisabledSelected: Story = {
name: 'Focused & Disabled (selected)',
args: {
className: cl['pseudo-focused'],
defaultChecked: true,
disabled: true,
},
};
37 changes: 37 additions & 0 deletions src/components/forms/controls/Radio/Radio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { classNames as cx, type ComponentProps } from '../../../../util/componentUtil.ts';
import * as React from 'react';

import cl from './Radio.module.scss';


export { cl as RadioClassNames };

export type RadioProps = ComponentProps<'input'> & {
/** Whether this component should be unstyled. */
unstyled?: undefined | boolean,
};
/**
* A simple Radio control, just the &lt;input type="radio"&gt; and nothing else..
*/
export const Radio = (props: RadioProps) => {
const {
unstyled = false,
...propsRest
} = props;

return (
<input
type="radio"
{...propsRest}
className={cx(
'bk',
{ [cl['bk-radio']]: !unstyled },
propsRest.className,
)}
/>
);
};
46 changes: 46 additions & 0 deletions src/components/forms/fields/RadioField/RadioField.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

@use '../../../../styling/defs.scss' as bk;

@layer baklava.components {
.bk-radio-field {
@include bk.component-base(bk-radio-field);

.bk-radio-field__title {
color: bk.$theme-text-label-default;
font-weight: bk.$font-weight-semibold;
margin-bottom: bk.$spacing-1;

.bk-radio-field__title__icon {
font-size: 18px;
margin-left: bk.$spacing-1;
}

.bk-radio-field__title__optional {
font-size: bk.$font-size-xs;
font-weight: bk.$font-weight-regular;
margin-left: bk.$spacing-1;
}
}

.bk-radio-field__label {
display: flex;
align-items: flex-start;
}

.bk-radio-field__label__content {
color: bk.$theme-text-label-default;
cursor: pointer;
position: relative;
padding-left: bk.$spacing-2;
top: -2px;
}

.bk-radio-field__sublabel {
font-size: bk.$font-size-xs;
padding-left: 26px;
}
}
}
74 changes: 74 additions & 0 deletions src/components/forms/fields/RadioField/RadioField.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/* Copyright (c) Fortanix, Inc.
|* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import type { Meta, StoryObj } from '@storybook/react';

import * as React from 'react';

import { RadioField } from './RadioField.tsx';


type RadioFieldArgs = React.ComponentProps<typeof RadioField>;
type Story = StoryObj<RadioFieldArgs>;

export default {
component: RadioField,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
},
args: {},
decorators: [
Story => <form onSubmit={event => { event.preventDefault(); }}><Story/></form>,
],
render: (args) => <RadioField {...args}/>,
} satisfies Meta<RadioFieldArgs>;


export const RadioFieldWithLabel: Story = {
args: {
label: 'Label',
},
};

export const RadioFieldWithLabelAndTitle: Story = {
args: {
title: 'Title',
label: 'Label',
},
};

export const RadioFieldWithLabelWithTitleWithTooltip: Story = {
args: {
title: 'Title',
label: 'Label',
titleTooltip: 'This is a tooltip',
}
};

export const RadioFieldWithLabelWithTitleWithOptional: Story = {
args: {
title: 'Title',
label: 'Label',
optional: true,
},
};

export const RadioFieldWithLabelWithTitleWithTooltipWithOptional: Story = {
args: {
title: 'Title',
label: 'Label',
titleTooltip: 'This is a tooltip',
optional: true,
},
};

export const RadioFieldWithLabelAndSublabel: Story = {
args: {
label: 'Label',
sublabel: 'Supporting copy',
},
};
Loading

0 comments on commit be59715

Please sign in to comment.