Skip to content

Commit

Permalink
Merge pull request #113 from 8845musign/checkboxcard-and-checkboxgroup
Browse files Browse the repository at this point in the history
Support CheckboxGroup to ChekboxCard + α
  • Loading branch information
takanorip committed Jun 27, 2024
2 parents bf6c456 + 0889b7c commit 05a731a
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 39 deletions.
1 change: 0 additions & 1 deletion src/components/Checkbox/Checkbox.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
background-color: var(--color-ubie-white);
border: 2px solid var(--color-border);
border-radius: var(--radius-sm);
transition: background-color 200ms;
}

.symbol.medium {
Expand Down
10 changes: 0 additions & 10 deletions src/components/CheckboxCard/CheckboxCard.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,12 @@
border-radius: 8px;
outline: 1px solid var(--color-border);
outline-offset: -1px;
}

.label,
.label::before {
transition:
outline-color 0.3s var(--ease-out-quint),
background-color 0.3s var(--ease-out-quint),
border-color 0.3s var(--ease-out-quint);
}

.label.checked {
background: var(--color-background-primary);
outline: 2px solid var(--color-primary);
outline-offset: -2px;
}

.label::before {
position: absolute;
top: 50%;
Expand Down
64 changes: 52 additions & 12 deletions src/components/CheckboxCard/CheckboxCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ export const Default: Story = {

const onChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(event) => {
if (event.target.checked) {
setSelectedItem([...selectedItem, event.target.value]);
if (event.currentTarget.checked) {
setSelectedItem([...selectedItem, event.currentTarget.value]);
} else {
setSelectedItem(selectedItem.filter((item) => item !== event.target.value));
setSelectedItem(selectedItem.filter((item) => item !== event.currentTarget.value));
}
},
[selectedItem],
Expand Down Expand Up @@ -61,10 +61,10 @@ export const Disabled: Story = {

const onChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(event) => {
if (event.target.checked) {
setSelectedItem([...selectedItem, event.target.value]);
if (event.currentTarget.checked) {
setSelectedItem([...selectedItem, event.currentTarget.value]);
} else {
setSelectedItem(selectedItem.filter((item) => item !== event.target.value));
setSelectedItem(selectedItem.filter((item) => item !== event.currentTarget.value));
}
},
[selectedItem],
Expand Down Expand Up @@ -95,10 +95,10 @@ export const Horizontally: Story = {

const onChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(event) => {
if (event.target.checked) {
setSelectedItem([...selectedItem, event.target.value]);
if (event.currentTarget.checked) {
setSelectedItem([...selectedItem, event.currentTarget.value]);
} else {
setSelectedItem(selectedItem.filter((item) => item !== event.target.value));
setSelectedItem(selectedItem.filter((item) => item !== event.currentTarget.value));
}
},
[selectedItem],
Expand Down Expand Up @@ -129,10 +129,10 @@ export const Block: Story = {

const onChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(event) => {
if (event.target.checked) {
setSelectedItem([...selectedItem, event.target.value]);
if (event.currentTarget.checked) {
setSelectedItem([...selectedItem, event.currentTarget.value]);
} else {
setSelectedItem(selectedItem.filter((item) => item !== event.target.value));
setSelectedItem(selectedItem.filter((item) => item !== event.currentTarget.value));
}
},
[selectedItem],
Expand Down Expand Up @@ -162,3 +162,43 @@ export const Block: Story = {
block: true,
},
};

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

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

return (
<CheckboxGroup>
{options.map((option) => (
<CheckboxCard
block
{...args}
key={option}
checked={selectedItem.includes(option)}
value={option}
onChange={onChange}
name="block"
>
{option}
</CheckboxCard>
))}
</CheckboxGroup>
);
},
args: {
...defaultArgs,
name: 'block',
block: true,
},
};
42 changes: 34 additions & 8 deletions src/components/CheckboxGroup/CheckboxGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,55 @@
'use client';

import { forwardRef } from 'react';
import { forwardRef, useMemo } from 'react';
import styles from './CheckboxGroup.module.css';
import { RequiredLabel } from '../../sharedComponents/RequiredLabel/RequiredLabel';
import { CustomDataAttributeProps } from '../../types/attributes';
import { Checkbox } from '../Checkbox/Checkbox';
import { CheckboxCard } from '../CheckboxCard/CheckboxCard';
import { Flex } from '../Flex/Flex';
import type { ReactElement } from 'react';

/**
* チェックボックス系コンポーネントをグルーピングするコンテナー
*/
export type Props = {
children: ReactElement<typeof Checkbox>[];
label: string;
/**
* チェックボックス系のコンポーネント
*/
children: ReactElement<typeof Checkbox>[] | ReactElement<typeof CheckboxCard>[];
/**
* グループの見出し
*/
label?: string;
/**
* 必須ラベルの表示
*/
showRequiredLabel?: boolean;
/**
* 配置方向
*/
direction?: 'column' | 'row';
} & CustomDataAttributeProps;

const includesCheckboxCard = (children: Props['children']): boolean => {
return children.some((child) => child.type === CheckboxCard);
};

export const CheckboxGroup = forwardRef<HTMLFieldSetElement, Props>(
({ children, label, showRequiredLabel, direction = 'column', ...otherProps }, ref) => {
const spacing = useMemo(() => {
return includesCheckboxCard(children) ? 'sm' : 'md';
}, [children]);

return (
<fieldset className={styles.wrapper} ref={ref} {...otherProps}>
<legend className={styles.legend}>
{label}
{showRequiredLabel && <RequiredLabel />}
</legend>
<Flex spacing="md" direction={direction}>
{label && (
<legend className={styles.legend}>
{label}
{showRequiredLabel && <RequiredLabel />}
</legend>
)}
<Flex spacing={spacing} direction={direction}>
{children}
</Flex>
</fieldset>
Expand Down
16 changes: 8 additions & 8 deletions src/components/RadioGroup/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ import { RadioButton } from '../RadioButton/RadioButton';
import { RadioCard } from '../RadioCard/RadioCard';
import type { ReactElement } from 'react';

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

export type Props = {
children: RadioComponent[];
children: ReactElement<typeof RadioButton>[] | ReactElement<typeof RadioCard>[];
/**
* ラジオグループの見出し(legend要素)
*/
label: string;
label?: string;
/**
* 必須マークを表示するか
* 注意: trueとしてもinput要素のrequired属性は付与されません
Expand All @@ -36,10 +34,12 @@ export const RadioGroup = forwardRef<HTMLFieldSetElement, Props>(

return (
<fieldset className={styles.wrapper} ref={ref} {...otherProps}>
<legend className={styles.legend}>
{label}
{showRequiredLabel && <RequiredLabel />}
</legend>
{label && (
<legend className={styles.legend}>
{label}
{showRequiredLabel && <RequiredLabel />}
</legend>
)}
<Flex
spacing={childrenIsCard ? 'sm' : 'md'}
alignItems={childenIsBlock ? 'normal' : undefined}
Expand Down
34 changes: 34 additions & 0 deletions src/stories/RadioCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,37 @@ export const Disabled: Story = {
);
},
};

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

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

return (
<Stack spacing="lg" alignItems="normal">
<RadioGroup>
{options.map((option) => (
<RadioCard
name="options"
value={option}
onChange={onChange}
checked={selectedItem === option}
id={option}
key={option}
>
{option}
</RadioCard>
))}
</RadioGroup>

<dl>
<dt>Values</dt>
<dd>{selectedItem}</dd>
</dl>
</Stack>
);
},
};

0 comments on commit 05a731a

Please sign in to comment.