Skip to content

Commit

Permalink
docs(Checkbox): update and improve documentation
Browse files Browse the repository at this point in the history
- decouple linkage from InputLabel type as well
  • Loading branch information
booc0mtaco committed Nov 6, 2023
1 parent 42ea7ad commit fd3f8d9
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 423 deletions.
127 changes: 24 additions & 103 deletions src/components/Checkbox/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,18 @@ import type { StoryObj, Meta } from '@storybook/react';
import React from 'react';
import { Checkbox } from './Checkbox';

const defaultArgs = {
disabled: false,
label: 'Checkbox',
};

const meta: Meta<typeof Checkbox> = {
title: 'Components/Checkbox',
component: Checkbox,
args: defaultArgs,
args: {
disabled: false,
label: 'Checkbox',
},
parameters: {
badges: ['1.0'],
},

decorators: [
(Story) => (
<div
// Provides spacing to see focus indicator around checkbox.
className="m-1"
>
{Story()}
</div>
),
],
decorators: [(Story) => <div className="m-1">{Story()}</div>],
};

export default meta;
Expand Down Expand Up @@ -55,60 +44,22 @@ export const MediumChecked: Story = {
},
};

export const Large: Story = {
...Default,
args: {
size: 'lg',
},
};

export const LargeChecked: Story = {
...Large,
args: {
...Checked.args,
...Large.args,
},
};

export const Indeterminate: Story = {
args: {
indeterminate: true,
},
};

/**
* `Checkbox` can be disabled in each available state.
*/
export const Disabled: Story = {
render: () => (
<table className="border-spacing-8">
<tbody>
{/* Un-checked */}
<tr>
<td>
<Checkbox checked={false} disabled label="Disabled" />
</td>
<td>
<Checkbox checked={false} label="Default" readOnly />
</td>
</tr>
{/* Checked */}
<tr>
<td>
<Checkbox checked disabled label="Disabled" />
</td>
<td>
<Checkbox checked label="Default" readOnly />
</td>
</tr>
{/* Indeterminate */}
<tr>
<td>
<Checkbox disabled indeterminate label="Disabled" />
</td>
<td>
<Checkbox indeterminate label="Default" readOnly />
</td>
</tr>
</tbody>
</table>
render: (args) => (
<div className="p-0">
<Checkbox {...args} checked={false} disabled label="Disabled" />
<Checkbox {...args} checked disabled label="Disabled" />
<Checkbox {...args} disabled indeterminate label="Disabled" />
</div>
),
parameters: {
axe: {
Expand All @@ -117,57 +68,27 @@ export const Disabled: Story = {
},
};

/**
* `Checkbox` doesn't require a visible label if `aria-label` is provided.
*/
export const WithoutVisibleLabel: Story = {
args: {
'aria-label': 'a checkbox has no name',
label: undefined,
},
render: (args) => (
<div className="flex flex-col gap-2">
<Checkbox {...args} readOnly />
<Checkbox {...args} checked readOnly />
<Checkbox {...args} indeterminate />
<Checkbox {...args} disabled />
<Checkbox {...args} checked disabled />
<Checkbox {...args} disabled indeterminate />
</div>
),
};

export const LongLabels = {
render: () => {
const label = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit';

return (
<div className="grid w-80 grid-cols-2 gap-4">
<Checkbox label={label} readOnly />
<Checkbox label={label} readOnly size="md" />
<Checkbox disabled label={label} />
<Checkbox disabled label={label} size="md" />
</div>
);
/**
* Long labels will sit adjacent to the text box, and allow clicking to change the state of the checkbox. When constrained,
* the text will wrap, fixing the checkbox to the top edge.
*/
export const LongLabels: Story = {
args: {
label: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
},
parameters: {
axe: {
disabledRules: ['color-contrast'],
},
},
};

export const WithCustomPositioning = {
parameters: {
docs: {
source: {
type: 'dynamic',
},
},
},
render: () => (
<div className="flex items-center">
<Checkbox.Label className="mr-2" htmlFor="test">
Label on Left
</Checkbox.Label>
<Checkbox.Input id="test" />
</div>
),
};
15 changes: 9 additions & 6 deletions src/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { forwardRef } from 'react';
import useForwardedRef from '../../util/useForwardedRef';
import { useId } from '../../util/useId';
import type { EitherInclusive } from '../../util/utility-types';
import type { Size } from '../../util/variant-types';
import { InputLabel, type InputLabelProps } from '../InputLabel/InputLabel';

import styles from './Checkbox.module.css';
Expand Down Expand Up @@ -42,9 +43,11 @@ type CheckboxProps = Omit<CheckboxInputProps, 'id'> & {
*/
id?: string;
/**
* Size of the checkbox label.
* Size of the checkbox and associated label.
*
* **Defaults to 'lg'.**
*/
size?: CheckboxLabelProps['size'];
size?: Extract<Size, 'md' | 'lg'>;
} & EitherInclusive<
{
/**
Expand Down Expand Up @@ -89,8 +92,6 @@ const CheckboxInput = React.forwardRef<HTMLInputElement, CheckboxInputProps>(
},
);

CheckboxInput.displayName = 'CheckboxInput';

const CheckboxLabel = ({ className, size, ...other }: CheckboxLabelProps) => {
const componentClassName = clsx(
size === 'md' && styles['checkbox__label--md'],
Expand All @@ -103,9 +104,10 @@ const CheckboxLabel = ({ className, size, ...other }: CheckboxLabelProps) => {
/**
* `import {Checkbox} from "@chanzuckerberg/eds";`
*
* Checkbox control indicating if something is selected or unselected.
* Checkbox control indicating if something is selected or unselected. Uncontrolled by default,
* it can be used in place of boolean-like form data.
*
* NOTE: Requires either a visible label or `aria-label` prop.
* **NOTE**: Requires either a visible `label` or `aria-label` prop.
*/
export const Checkbox = Object.assign(
forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {
Expand Down Expand Up @@ -138,3 +140,4 @@ export const Checkbox = Object.assign(
);

Checkbox.displayName = 'Checkbox';
CheckboxInput.displayName = 'CheckboxInput';
Loading

0 comments on commit fd3f8d9

Please sign in to comment.