Skip to content

Commit

Permalink
Merge pull request #25 from 8845musign/add-group-for-radio-and-checkbox
Browse files Browse the repository at this point in the history
Imple RadioGroup And CheckboxGroup
  • Loading branch information
takanorip authored Mar 13, 2024
2 parents f3d61ef + e42ec7d commit 33d33f8
Show file tree
Hide file tree
Showing 12 changed files with 235 additions and 47 deletions.
13 changes: 13 additions & 0 deletions src/components/CheckboxGroup/CheckboxGroup.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.wrapper {
border: none;
padding: 0;
margin: 0;
}

.legend {
font-size: var(--text-body-sm-size);
font-weight: bold;
color: var(--color-text-sub);
margin-bottom: var(--size-spacing-md);
padding: 0;
}
23 changes: 23 additions & 0 deletions src/components/CheckboxGroup/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client';

import styles from './CheckboxGroup.module.css';
import { Checkbox } from '../Checkbox/Checkbox';
import { Stack } from '../Stack/Stack';
import type { FC, ReactElement } from 'react';

export type Props = {
children: ReactElement<typeof Checkbox>[];
label: string;
direction?: 'column' | 'row';
};

export const CheckboxGroup: FC<Props> = ({ children, label, direction = 'column' }) => {
return (
<fieldset className={styles.wrapper}>
<legend className={styles.legend}>{label}</legend>
<Stack spacing="md" direction={direction}>
{children}
</Stack>
</fieldset>
);
};
2 changes: 1 addition & 1 deletion src/components/Label/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { ElementType, FC, ReactNode } from 'react';

type Props = {
children: ReactNode;
as?: ElementType<{ className?: string; children: ReactNode }> | 'label' | 'legend' | 'p';
as?: ElementType<{ className?: string; children: ReactNode }> | 'label' | 'p';
htmlFor?: string;
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/RadioCard/RadioCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Props = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'name' | 'value'

/**
* アクセシビリティに配慮したラジオボタン。
* TimeQuestionContentのような、選択した後自動で遷移しないタイプのラジオボタン(選択してもなにもおきないボタン)に使用する。
* 選択した後自動で遷移しないタイプのラジオボタン(選択してもなにもおきないボタン)に使用
*/
const RadioCard: FC<Props> = forwardRef<HTMLInputElement, Props>(
({ name, value, checked, children, className, block = false, ...otherProps }, ref) => {
Expand Down
13 changes: 13 additions & 0 deletions src/components/RadioGroup/RadioGroup.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.wrapper {
border: none;
padding: 0;
margin: 0;
}

.legend {
font-size: var(--text-body-sm-size);
font-weight: bold;
color: var(--color-text-sub);
margin-bottom: var(--size-spacing-md);
padding: 0;
}
33 changes: 33 additions & 0 deletions src/components/RadioGroup/RadioGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use client';

import styles from './RadioGroup.module.css';
import { RadioButton } from '../RadioButton/RadioButton';
import { RadioCard } from '../RadioCard/RadioCard';
import { Stack } from '../Stack/Stack';
import type { FC, ReactElement } from 'react';

type RadioComponent = ReactElement<typeof RadioButton> | ReactElement<typeof RadioCard>;

export type Props = {
children: RadioComponent[];
label: string;
direction?: 'column' | 'row';
};

export const RadioGroup: FC<Props> = ({ children, label, direction = 'column' }) => {
const childrenIsCard = children.some((child) => child.type === RadioCard);
const childenIsBlock = direction === 'row' || (childrenIsCard && direction === 'column');

return (
<fieldset className={styles.wrapper}>
<legend className={styles.legend}>{label}</legend>
<Stack
spacing={childrenIsCard ? 'sm' : 'md'}
alignItems={childenIsBlock ? 'normal' : undefined}
direction={direction}
>
{children}
</Stack>
</fieldset>
);
};
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ export { LinkButton } from './components/Button/LinkButton';
export { ErrorMessage } from './components/ErrorMessage/ErrorMessage';
export { HelperMessage } from './components/HelperMessage/HelperMessage';
export { Checkbox } from './components/Checkbox/Checkbox';
export { CheckboxGroup } from './components/CheckboxGroup/CheckboxGroup';
export { Input } from './components/Input/Input';
export { Label } from './components/Label/Label';
export { LinkCard } from './components/LinkCard/LinkCard';
export { MessageModal } from './components/MessageModal/MessageModal';
export { RadioButton } from './components/RadioButton/RadioButton';
export { RadioCard } from './components/RadioCard/RadioCard';
export { RadioGroup } from './components/RadioGroup/RadioGroup';
export { Select } from './components/Select/Select';
export { Text } from './components/Text/Text';
export { TextArea } from './components/TextArea/TextArea';
Expand Down
68 changes: 55 additions & 13 deletions src/stories/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Meta, StoryObj } from '@storybook/react';
import { useState, useCallback } from 'react';
import { Checkbox, Stack } from '../';
import { Checkbox, CheckboxGroup, Stack } from '../';
import type { ChangeEventHandler } from 'react';

export default {
Expand Down Expand Up @@ -28,18 +28,60 @@ export const Default: Story = {
);

return (
<Stack spacing="md">
{options.map((option) => (
<Checkbox
name="options"
value={option}
onChange={onChange}
checked={selectedItem.includes(option)}
key={option}
>
{option}
</Checkbox>
))}
<Stack spacing="lg">
<CheckboxGroup label="Checkbox">
{options.map((option) => (
<Checkbox
name="default"
value={option}
onChange={onChange}
checked={selectedItem.includes(option)}
key={option}
>
{option}
</Checkbox>
))}
</CheckboxGroup>

<dl>
<dt>Values</dt>
<dd>{selectedItem.join(',')}</dd>
</dl>
</Stack>
);
},
};

export const Horizontally: Story = {
render: () => {
const [selectedItem, setSelectedItem] = useState<string[]>([options[0]]);

const onChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(event) => {
if (event.target.checked) {
setSelectedItem([...selectedItem, event.target.value]);
} else {
setSelectedItem(selectedItem.filter((item) => item !== event.target.value));
}
},
[selectedItem],
);

return (
<Stack spacing="lg">
<CheckboxGroup label="Checkbox" direction="row">
{options.map((option) => (
<Checkbox
name="horizontally"
value={option}
onChange={onChange}
checked={selectedItem.includes(option)}
key={option}
>
{option}
</Checkbox>
))}
</CheckboxGroup>

<dl>
<dt>Values</dt>
Expand Down
14 changes: 8 additions & 6 deletions src/stories/Form.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StoryObj } from '@storybook/react';
import { useCallback, useState } from 'react';
import { Stack, Label, Input, HelperMessage, ErrorMessage, RadioButton } from '..';
import { Stack, Label, Input, HelperMessage, ErrorMessage, RadioButton, RadioGroup } from '..';
import type { ChangeEventHandler } from 'react';

export default {
Expand Down Expand Up @@ -44,7 +44,7 @@ export const Error: StoryObj = {
},
};

export const InputGroup: StoryObj = {
export const RadioButtons: StoryObj = {
render: () => {
const options = ['項目1', '項目2', '項目3'];
const [selectedItem, setSelectedItem] = useState<string>(options[0]);
Expand All @@ -54,9 +54,8 @@ export const InputGroup: StoryObj = {
}, []);

return (
<fieldset style={{ border: 'none', padding: 0 }}>
<Stack spacing="xs" alignItems="normal">
<Label as="legend">通院状況</Label>
<Stack spacing="md" alignItems="normal">
<RadioGroup label="通院状況">
{options.map((option) => (
<RadioButton
name="commuting"
Expand All @@ -68,12 +67,15 @@ export const InputGroup: StoryObj = {
{option}
</RadioButton>
))}
</RadioGroup>

<Stack spacing="xs">
<ErrorMessage>何かしらのエラーメッセージ</ErrorMessage>
<ErrorMessage>何かしらのエラーメッセージ</ErrorMessage>
<HelperMessage>説明文です</HelperMessage>
<HelperMessage>説明文です</HelperMessage>
</Stack>
</fieldset>
</Stack>
);
},
};
4 changes: 0 additions & 4 deletions src/stories/Label.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,3 @@ type Story = StoryObj<typeof Label>;
export const Default: Story = {
render: () => <Label htmlFor="id">全角カタカナでご入力ください</Label>,
};

export const AsLegend: Story = {
render: () => <Label as="legend">選択してください(複数回答可)</Label>,
};
59 changes: 47 additions & 12 deletions src/stories/RadioButton.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Meta, StoryObj } from '@storybook/react';
import { ChangeEventHandler, useState, useCallback } from 'react';
import { RadioButton, Stack } from '../';
import { RadioButton, Stack, RadioGroup } from '../';

export default {
title: 'Form/RadioButton',
Expand All @@ -24,7 +24,46 @@ export const Default: Story = {
}, []);

return (
<Stack spacing="xs">
<Stack spacing="lg">
<RadioGroup label="RadioButton">
{options.map((option) => (
<RadioButton
key={option}
{...args}
value={option}
id={option}
onChange={onChange}
checked={selectedItem === option}
name="default"
>
{option}
</RadioButton>
))}
</RadioGroup>

<dl>
<dt>Values</dt>
<dd>{selectedItem}</dd>
</dl>
</Stack>
);
},
args: {
...defaultArgs,
name: 'default',
},
};

export const Horizontally: Story = {
render: (args) => {
const [selectedItem, setSelectedItem] = useState(options[0]);

const onChange: ChangeEventHandler<HTMLInputElement> = useCallback((event) => {
setSelectedItem(event.target.value);
}, []);

return (
<RadioGroup label="RadioButton" direction="row">
{options.map((option) => (
<RadioButton
key={option}
Expand All @@ -33,16 +72,12 @@ export const Default: Story = {
id={option}
onChange={onChange}
checked={selectedItem === option}
name="horizontally"
>
{option}
</RadioButton>
))}

<dl>
<dt>Values</dt>
<dd>{selectedItem}</dd>
</dl>
</Stack>
</RadioGroup>
);
},
args: {
Expand All @@ -54,10 +89,10 @@ export const Default: Story = {
export const Size: Story = {
render: (args) => (
<Stack spacing="xs">
<RadioButton {...args} value="medium" id="medium">
<RadioButton {...args} value="medium" id="medium" name="size">
Medium
</RadioButton>
<RadioButton {...args} value="small" id="small" size="small">
<RadioButton {...args} value="small" id="small" size="small" name="size">
Small
</RadioButton>
</Stack>
Expand All @@ -71,11 +106,11 @@ export const Size: Story = {
export const Disabled: Story = {
render: (args) => (
<Stack spacing="xs">
<RadioButton {...args} value="checked" id="checked" checked disabled>
<RadioButton {...args} value="checked" id="checked" checked disabled name="disabled">
Checked
</RadioButton>

<RadioButton {...args} value="unchecked" id="unchecked" disabled>
<RadioButton {...args} value="unchecked" id="unchecked" disabled name="disabled">
Unchecked
</RadioButton>
</Stack>
Expand Down
Loading

0 comments on commit 33d33f8

Please sign in to comment.