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

중복선택 버튼 컴포넌트 (체크박스) 작성 #27

Merged
merged 10 commits into from
Jul 14, 2024
37 changes: 37 additions & 0 deletions src/app/test/Staging.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,52 @@
import { useEffect } from "react";

import Button from "@/component/Button/Button.tsx";
import { ButtonProvider } from "@/component/Button/ButtonProvider.tsx";
import CheckBox from "@/component/common/CheckBox/CheckBox";
import CheckBoxGroup from "@/component/common/CheckBox/CheckBoxGroup";
import Radio from "@/component/common/RadioButton/Radio";
import RadioButtonGroup from "@/component/common/RadioButton/RadioButtonGroup";
import { useCheckBox } from "@/hooks/useCheckBox";
import { useRadioButton } from "@/hooks/useRadioButton";
import { DefaultLayout } from "@/layout/DefaultLayout.tsx";

export default function Staging() {
const [isRadioChecked, onChange, selectedValue] = useRadioButton();
const [isCheckBoxChecked, toggle, selectedValues] = useCheckBox();

useEffect(() => {
console.log("라디오 버튼 선택 value:", selectedValue);
}, [selectedValue]);

useEffect(() => {
console.log("체크박스 선택 values:", selectedValues);
}, [selectedValues]);

return (
<DefaultLayout>
<Button> 그냥 그저 그런 버튼 </Button>
<Button colorSchema={"gray"}> 그냥 그저 그런 버튼 </Button>
<Button colorSchema={"sky"}> 그냥 그저 그런 버튼 </Button>
<Button colorSchema={"primary"}> 그냥 그저 그런 버튼 </Button>

<br />
<h3>라디오버튼</h3>
<RadioButtonGroup isChecked={isRadioChecked} onChange={onChange} radioName={"프로젝트 주기"}>
<Radio value={"0"}>주 1회</Radio>
<Radio value={"1"}>월 1회</Radio>
<Radio value={"2"}>분기별</Radio>
<Radio value={"3"}>프로젝트 끝난 후</Radio>
</RadioButtonGroup>

<br />
<h3>체크박스</h3>
<CheckBoxGroup isChecked={isCheckBoxChecked} onChange={toggle}>
<CheckBox value={"00"}>주 1회</CheckBox>
<CheckBox value={"10"}>월 1회</CheckBox>
<CheckBox value={"20"}>분기별</CheckBox>
<CheckBox value={"30"}>프로젝트 끝난 후</CheckBox>
</CheckBoxGroup>
Comment on lines +34 to +48
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용방법이 직관적이어서 좋네요!!


<ButtonProvider>
<ButtonProvider.Primary>기본 버튼</ButtonProvider.Primary>
<ButtonProvider.Sky>하늘색 버튼</ButtonProvider.Sky>
Expand Down
46 changes: 46 additions & 0 deletions src/component/common/CheckBox/CheckBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { css } from "@emotion/react";
import { useContext } from "react";

import { CheckBoxContext } from "./CheckBoxGroup";

import ListItemCard from "@/component/common/Card/ListItemCard";

type CheckBoxProps = {
value: string;
children: React.ReactNode;
};

const CheckBox = ({ value, children }: CheckBoxProps) => {
const checkboxContext = useContext(CheckBoxContext);
return (
<ListItemCard variant={checkboxContext?.isChecked(value) ? "theme" : "default"}>
<label
htmlFor={value}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

htmlFor이라는 속성도 있군요!! 하나 또 알아갑니다.

css={css`
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
cursor: pointer;
`}
>
{children}
</label>
<input
type="checkbox"
id={value}
value={value}
onChange={(e) => {
checkboxContext?.onChange && checkboxContext.onChange(e.target.value);
}}
css={css`
display: none;
`}
/>
</ListItemCard>
);
};

export default CheckBox;
29 changes: 29 additions & 0 deletions src/component/common/CheckBox/CheckBoxGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { css } from "@emotion/react";
import { createContext } from "react";

export type CheckBoxContextState = {
isChecked: (value: string) => boolean;
onChange: (value: string) => void;
};

export const CheckBoxContext = createContext<CheckBoxContextState | undefined>(undefined);

type CheckBoxGroupProps = {
children: React.ReactNode;
} & CheckBoxContextState;

const CheckBoxGroup = ({ children, ...props }: CheckBoxGroupProps) => {
return (
<div
css={css`
display: flex;
flex-direction: column;
gap: 1rem;
`}
>
<CheckBoxContext.Provider value={props}>{children}</CheckBoxContext.Provider>
</div>
);
};

export default CheckBoxGroup;
6 changes: 4 additions & 2 deletions src/component/common/RadioButton/Radio.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { css } from "@emotion/react";
import { useContext } from "react";

import { RadioContext } from "./RadioButtonGroup";

import ListItemCard from "@/component/common/Card/ListItemCard";
import { RadioContext } from "@/store/context/RadioContext";

type RadioProps = {
value: string;
Expand All @@ -12,7 +13,7 @@ type RadioProps = {
const Radio = ({ value, children }: RadioProps) => {
const radioContext = useContext(RadioContext);
return (
<ListItemCard variant={radioContext?.selectedValue === value ? "theme" : "default"}>
<ListItemCard variant={radioContext?.isChecked(value) ? "theme" : "default"}>
<label
htmlFor={value}
css={css`
Expand All @@ -22,6 +23,7 @@ const Radio = ({ value, children }: RadioProps) => {
align-items: center;
height: 100%;
width: 100%;
cursor: pointer;
`}
>
{children}
Expand Down
18 changes: 11 additions & 7 deletions src/component/common/RadioButton/RadioButtonGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { css } from "@emotion/react";
import { createContext } from "react";

import { RadioContext } from "@/store/context/RadioContext";
export type RadioContextState = {
radioName: string;
isChecked: (value: string) => boolean;
onChange: (value: string) => void;
};

export const RadioContext = createContext<RadioContextState | undefined>(undefined);

type RadioButtonGroupProps = {
children: React.ReactNode;
selectedValue: string | undefined;
onChange: React.Dispatch<React.SetStateAction<string | undefined>>;
radioName: string;
};
} & RadioContextState;

const RadioButtonGroup = ({ children, ...rest }: RadioButtonGroupProps) => {
const RadioButtonGroup = ({ children, ...props }: RadioButtonGroupProps) => {
return (
<div
css={css`
Expand All @@ -18,7 +22,7 @@ const RadioButtonGroup = ({ children, ...rest }: RadioButtonGroupProps) => {
gap: 1rem;
`}
>
<RadioContext.Provider value={rest}>{children}</RadioContext.Provider>
<RadioContext.Provider value={props}>{children}</RadioContext.Provider>
</div>
);
};
Expand Down
10 changes: 10 additions & 0 deletions src/hooks/useCheckBox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useState } from "react";

export const useCheckBox = () => {
const [checkedStates, setCheckedStates] = useState<Record<string, boolean>>({});
const isChecked = (value: string) => checkedStates[value];
const toggle = (value: string) => setCheckedStates((prev) => ({ ...prev, [value]: !prev[value] }));
const selectedValues = Object.keys(checkedStates).filter((key) => checkedStates[key]);

return [isChecked, toggle, selectedValues] as const;
};
9 changes: 9 additions & 0 deletions src/hooks/useRadioButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useState } from "react";

export const useRadioButton = () => {
const [selectedValue, setSelectedValue] = useState<string>();
const isChecked = (value: string) => selectedValue === value;
const onChange = (value: string) => setSelectedValue(value);

return [isChecked, onChange, selectedValue] as const;
};
2 changes: 1 addition & 1 deletion src/layout/GlobalLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default function GlobalLayout() {

display: flex;
flex-direction: column;
background-color: #f1f3f5;
background-color: #ffffff;
`}
>
<Outlet />
Expand Down
9 changes: 0 additions & 9 deletions src/store/context/RadioContext.ts

This file was deleted.

Loading