Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] refactor: Checkbox, CheckboxItem 컴포넌트 역할 분리 #1005

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
Open
59 changes: 0 additions & 59 deletions frontend/src/components/common/Checkbox/index.tsx

This file was deleted.

57 changes: 0 additions & 57 deletions frontend/src/components/common/CheckboxItem/index.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { ChangeEvent } from 'react';

import { Checkbox } from '../../checkboxes';
import { CheckboxItemBaseProps } from '../CheckboxItemBase';
import { CheckboxItemBase } from '../index';

export interface CheckboxItemProps extends CheckboxItemBaseProps {
isDisabled?: boolean;
handleChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
handleKeyDown?: (event: React.KeyboardEvent<HTMLDivElement>) => void;
}

const CheckboxItem = ({ id, label, isChecked, isDisabled = false, handleChange, ...rest }: CheckboxItemProps) => {
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === 'Enter' && handleChange) {
handleChange({
currentTarget: {
id: id,
checked: !isChecked,
} as Partial<HTMLInputElement>,
} as ChangeEvent<HTMLInputElement>);
}
};

return (
<CheckboxItemBase
id={`checkbox-item-${id}`}
isChecked={isChecked}
tabIndex={isDisabled ? -1 : 0}
isDisabled={isDisabled}
label={label}
handleKeyDown={handleKeyDown}
>
<Checkbox
id={id}
isChecked={isChecked}
isDisabled={isDisabled}
tabIndex={-1}
handleChange={handleChange}
{...rest}
/>
</CheckboxItemBase>
);
};

export default CheckboxItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { EssentialPropsWithChildren } from '@/types';

import { CheckboxItemProps } from '../CheckboxItem';

import * as S from './styles';

export interface CheckboxItemBaseProps {
id: string;
label: string;
isChecked: boolean;
name?: string;
tabIndex?: number;
}

interface FinalCheckboxItemBaseProps extends CheckboxItemBaseProps, CheckboxItemProps{};

const CheckboxItemBase = ({
label,
isChecked,
tabIndex = 0,
handleKeyDown,
children,
...rest
}: EssentialPropsWithChildren<FinalCheckboxItemBaseProps>) => {
const isCheckedLabel = `${label}, ${isChecked ? '선택됨' : '선택 안 됨'}`;

return (
<S.CheckboxItem
className="checkbox-item"
tabIndex={tabIndex}
aria-label={isCheckedLabel}
onKeyDown={handleKeyDown}
{...rest}
>
<S.CheckboxLabel>
{children}
{label}
</S.CheckboxLabel>
</S.CheckboxItem>
);
};

export default CheckboxItemBase;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ReadonlyCheckbox } from '../../checkboxes';
import { CheckboxItemBaseProps } from '../CheckboxItemBase';
import { CheckboxItemBase } from '../index';

export interface ReadonlyCheckboxItemProps
extends Omit<CheckboxItemBaseProps, 'tabIndex' | 'isDisabled' | 'handleChange' | 'handleKeyDown'> {}

const ReadonlyCheckboxItem = ({ id, label, isChecked, ...rest }: ReadonlyCheckboxItemProps) => {
return (
<CheckboxItemBase id={id} isChecked={isChecked} tabIndex={-1} label={label}>
<ReadonlyCheckbox id={id} isChecked={isChecked} tabIndex={-1} $isReadonly={true} {...rest} />
</CheckboxItemBase>
);
};

export default ReadonlyCheckboxItem;
3 changes: 3 additions & 0 deletions frontend/src/components/common/checkboxItems/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as CheckboxItem } from './CheckboxItem';
export { default as CheckboxItemBase } from './CheckboxItemBase';
export { default as ReadonlyCheckboxItem } from './ReadonlyCheckboxItem';
22 changes: 22 additions & 0 deletions frontend/src/components/common/checkboxes/Checkbox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ChangeEvent } from 'react';

import { CheckboxBaseProps } from '../CheckboxBase';
import { CheckboxBase } from '../index';

export interface CheckboxProps extends CheckboxBaseProps {
handleChange?: (event: ChangeEvent<HTMLInputElement>, label?: string) => void;
}

export const Checkbox = ({ isDisabled, isChecked, isTabAccessible = true, handleChange, ...rest }: CheckboxProps) => {
return (
<CheckboxBase
isDisabled={isDisabled}
isChecked={isChecked}
tabIndex={isDisabled || isTabAccessible ? 0 : -1}
handleChange={handleChange}
{...rest}
/>
);
};

export default Checkbox;
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import CheckedIcon from '@/assets/checked.svg';
import UncheckedIcon from '@/assets/unchecked.svg';
import UndraggableWrapper from '@/components/common/UndraggableWrapper';

import { CheckboxProps } from '../Checkbox';

import * as S from './styles';

export interface CheckboxStyleProps {
$isReadonly?: boolean;
$style?: React.CSSProperties;
}

export interface CheckboxA11yProps {
isTabAccessible?: boolean; // CheckboxItem을 사용할 때 Checkbox 중복 포커싱 방지용
tabIndex?: number;
}
export interface CheckboxBaseProps extends CheckboxStyleProps, CheckboxA11yProps {
id: string;
isChecked: boolean;
isDisabled?: boolean;
name?: string;
}

interface FinalCheckboxBaseProps extends CheckboxBaseProps, CheckboxProps {}

const CheckboxBase = ({
id,
isChecked,
isDisabled,
tabIndex,
handleChange,
$isReadonly = false,
$style,
...rest
}: FinalCheckboxBaseProps) => {
return (
<UndraggableWrapper>
<S.CheckboxContainer $style={$style} $isReadonly={$isReadonly}>
<S.CheckboxLabel>
<input
id={id}
data-testid={`checkbox-${id}`}
checked={isChecked}
disabled={isDisabled}
onChange={handleChange}
type="checkbox"
tabIndex={-1}
{...rest}
/>
<img
src={isChecked ? CheckedIcon : UncheckedIcon}
tabIndex={tabIndex}
role="checkbox"
aria-checked={isChecked}
alt=""
/>
{$isReadonly && <span className="sr-only">{isChecked ? '선택됨' : '선택 안 됨'}</span>}
</S.CheckboxLabel>
</S.CheckboxContainer>
</UndraggableWrapper>
);
};

export default CheckboxBase;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from '@emotion/styled';

import { CheckboxStyleProps } from './index';
import { CheckboxStyleProps } from '.';

export const CheckboxContainer = styled.div<CheckboxStyleProps>`
width: 2.7rem;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { CheckboxProps } from '../Checkbox';
import { CheckboxBase } from '../index';

interface ReadonlyCheckboxProps extends Omit<CheckboxProps, 'isDisabled' | 'handleChange'> {}

const ReadonlyCheckbox = ({ isChecked, ...rest }: ReadonlyCheckboxProps) => {
return (
<CheckboxBase
isDisabled={true}
isChecked={isChecked}
tabIndex={-1}
aria-readonly={true}
$isReadonly={true}
{...rest}
/>
);
};

export default ReadonlyCheckbox;
3 changes: 3 additions & 0 deletions frontend/src/components/common/checkboxes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as Checkbox } from './Checkbox';
export { default as CheckboxBase } from './CheckboxBase';
export { default as ReadonlyCheckbox } from './ReadonlyCheckbox';
7 changes: 4 additions & 3 deletions frontend/src/components/common/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ export { default as Input } from './Input';
export { default as ReviewDate } from './ReviewDate';
export { default as MultilineTextViewer } from './MultilineTextViewer';
export { default as TopButton } from './TopButton';
export { default as Checkbox } from './Checkbox';
export { default as CheckboxItem } from './CheckboxItem';
export { default as Checkbox } from './checkboxes/Checkbox';
export { default as ReadonlyCheckbox } from './checkboxes/ReadonlyCheckbox';
export { default as CheckboxItem } from './checkboxItems/CheckboxItem';
export { default as ReadonlyCheckboxItem } from './checkboxItems/ReadonlyCheckboxItem';
export { default as EyeButton } from './EyeButton';
export { default as Carousel } from './Carousel';
export { default as Accordion } from './Accordion';
export { default as Dropdown } from './Dropdown';
export { default as Toast } from './Toast';

export { default as OptionSwitch } from './OptionSwitch';
export { default as ReviewEmptySection } from './ReviewEmptySection';
export * from './modals';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';

import { AlertModal } from '@/components';
import Checkbox from '@/components/common/Checkbox';
import Checkbox from '@/components/common/checkboxes/Checkbox';

import { CopyTextButton } from '../index';

Expand Down
Loading
Loading