Skip to content

Commit

Permalink
Merge pull request #27 from depromeet/feature/#11/checkbox
Browse files Browse the repository at this point in the history
중복선택 버튼 컴포넌트 (체크박스) 작성
  • Loading branch information
leeminhee119 authored Jul 14, 2024
2 parents be18ea7 + c356813 commit 217356e
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 19 deletions.
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>

<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}
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.

0 comments on commit 217356e

Please sign in to comment.