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

feat(QYOG-162): 셀렉트박스 디자인 시스템 개발 #87

Merged
merged 7 commits into from
Jun 21, 2024
33 changes: 33 additions & 0 deletions src/components/Design/SelectBox/SelectBox.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { StoryObj } from "@storybook/react";
import { SelectBox } from ".";

const meta = {
title: "components/SelectBox",
component: SelectBox,
};

type Story = StoryObj<typeof meta>;

interface OptionInterface {
name: string;
value: string;
}

function setSelectOption(result: OptionInterface) {
return result;
}

export const Primary: Story = {
args: {
options: [
{ name: "1학년", value: "1" },
{ name: "2학년", value: "2" },
],

defaultName: "학년",
isRequired: true,
setSelectOption: setSelectOption,
},
};

export default meta;
67 changes: 67 additions & 0 deletions src/components/Design/SelectBox/SelectBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Created on Sat May 18 2024
*
* Copyright (c) 2024 Your Company
*/

import { useState, useRef, useEffect } from "react";

import * as S from "./emotion";

interface OptionInterface {
name: string;
value: string;
}
interface SelectboxProps {
options: OptionInterface[];
defaultName: string;
isRequired: boolean;
setSelectOption: (result: OptionInterface) => OptionInterface; // setState or object
}

export default function SelectBox({
options,
defaultName = "값을 선택하세요.",
isRequired = false,
setSelectOption,
}: SelectboxProps) {
const [isOpen, setIsOpen] = useState<boolean>(false);
const [selectedName, setSelectedName] = useState(defaultName);
const [selectedIndex, setSelectedIndex] = useState<number>(-1);

function handleOnChangeOption(e: any) {
setSelectedName(e.target.innerHTML);
setSelectedIndex(e.target.id);
}

useEffect(() => {
if (selectedIndex >= 0) setSelectOption(options[selectedIndex]);
}, [selectedIndex]);

return (
<S.SelectBoxWrap
onClick={() => setIsOpen(!isOpen)}
verticalAlign="center"
horizonAlign="center"
>
<S.SelectedDiv verticalAlign="center" horizonAlign="center">
{isRequired ? <S.RequireNotice>*</S.RequireNotice> : <></>}
<label>{selectedName}</label>
<span>⌵</span>
</S.SelectedDiv>
<S.OptionUl isShow={isOpen}>
{options.map((option, idx) => {
return (
<S.OptionListItem
key={idx}
id={String(idx)}
onClick={handleOnChangeOption}
>
{option.name}
</S.OptionListItem>
);
})}
</S.OptionUl>
</S.SelectBoxWrap>
);
}
48 changes: 48 additions & 0 deletions src/components/Design/SelectBox/emotion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Created on Sat June 15 2024
*
* Copyright (c) 2023 Your Company
*/

import { Column, Row } from "@/components/Layouts";
import styled from "@emotion/styled";

export const SelectBoxWrap = styled(Column.div)`
border: 1px solid red;
position: relative;
cursor: pointer;

padding: 10px;
width: 200px;
border-radius: 10px;
`;

export const OptionUl = styled.ul<{ isShow: boolean }>`
max-height: ${(props) => (props.isShow ? "none" : "0")};
position: absolute;
list-style: none;
top: 18px;
left: 0;
overflow: hidden;
padding: 0;
border: 1px solid blue;
border-top: none;
width: 100%;
margin-top: 22px;
`;

export const RequireNotice = styled.span`
color: red;
`;

export const SelectedDiv = styled(Row.div)`
width: 100%;
justify-content: space-between;
`;

export const OptionListItem = styled.li`
background-color: white;
&:hover {
background-color: black;
}
`;
7 changes: 7 additions & 0 deletions src/components/Design/SelectBox/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Created on Fri Feb 16 2024
*
* Copyright (c) 2024 Your Company
*/

export { default as SelectBox } from "./SelectBox";
Loading