@black-ui/react
v0.0.26
Published
A presonalised UI Library.
Downloads
9
Maintainers
Readme
Vanilla Extract 기반 디자인 시스템으로 성능 저하 없이 멋진 디자인을 구현하세요!
미완성 프로젝트입니다. 개선할 부분이 있다면 언제든지 Issues 남겨주세요!
Table of Contents
- 📦 Getting Started
- 🛠️ Stack
- 📒 Storybook
- 🔮 Todo
- 💻 Components
- Hooks
Stack (배경이 궁금하다면)
| 기술 | 설명 | | --------------- | ------------------------------------------- | | TypeScript | JavaScript의 확장 언어 | | React | JavaScript 프레임워크 | | Vite | React 개발을 위한 빌드 도구 | | Vanilla Extract | Zero-runtime Stylesheets in TypeScript. | | Storybook | React 컴포넌트를 테스트하고 문서화하는 도구 | | Jest | JavaScript 테스트 프레임워크 |
Getting Started
Introduction
black-ui는 react + typescript + vanilla-extract 조합으로 개발한 디자인 시스템입니다.
기존의 유명 디자인 시스템들은 emotion 같은 css-in-js 라이브러리로 개발된 라이브러리들이 많았습니다.
하지만 일반적인 css-in-js 라이브러리들은 js가 css로 변환되는 과정이 런타임 단계에서 일어나기 때문에 성능적인 이슈가 발생할 수 있습니다.
black-ui는 이러한 점을 보완하기 위해 vanilla-extract 라는 스타일링 라이브러리를 선택했습니다.
vanilla-extract도 css-in-js 라이브러리 이지만 css 변환 과정이 런타임이 아니라 컴파일 타임 때 일어나기 때문에 성능적인 이점을 가질 수 있습니다.
기존 디자인 시스템보다 빠르고 완벽한 타입 추론을 지원하는 black-ui를 사용해보세요!
Installation
npm i @black-ui/react
Theming
black-ui를 사용하기 위해서는 반드시 최상위 컴포넌트를 ThemePovider 컴포넌트로 감싸야합니다.
기본 테마는 light이지만 defaultMode props로 기본 테마를 변경할 수 있습니다.
<ThemeProvider defaultMode="light">
<App />
</ThemeProvider>
또한 ThemeSwitcher 컴포넌트를 통해 테마를 자유롭게 변경할 수 있습니다.
<ThemeSwitcher></ThemeSwitcher>
Storybook - Docs
Storybook으로 배포한 Black UI 컴포넌트들을 직접 사용해볼 수 있어요!
Todo
- 스타일 가이드 작성하기
- 테스트 코드 보완하기
- SSR 대응하기
- 반응형 디자인 구현
- 웹 접근성 높이기 WCAG
- Headless 컴포넌트 추가
- Context API 최적화
- 번들 사이즈 최적화
- 컴포넌트 단위로 패키지 분할
- Figma 연동
- 공통 로직 분리하기
- 컴포넌트 추가 구현하기
- Carousel
- Calendar
- Date Picker
Components
DataDisplay
Avatar - Source
Import
import { Avatar } from "@black-ui/react";
Usage
export const Example = () => {
return <Avatar src="/images/profile.jpg" alt="Name" size="sm" />;
};
Card - Source
Import
import { Card, CardHeader, CardBody, CardFooter } from "@black-ui/react";
Usage
export const Example = () => {
return (
<Card variant="elevated">
<CardHeader>Header</CardHeader>
<CardBody>Body</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
);
};
List - Source
Import
import { List, ListItem, ListIcon } from "@black-ui/react";
Usage
export const Example = () => {
return (
<List>
<ListItem>
<ListIcon as={<IoMdSettings />} color="green" />
Lorem ipsum dolor sit amet, consectetur adipisicing elit
</ListItem>
<ListItem>
<ListIcon as={<IoMdSettings />} color="green" />
Assumenda, quia temporibus eveniet a libero incidunt suscipit
</ListItem>
<ListItem>
<ListIcon as={<IoMdSettings />} color="green" />
Quidem, ipsam illum quis sed voluptatum quae eum fugit earum
</ListItem>
<ListItem>
<ListIcon as={<IoMdSettings />} color="green" />
Lorem ipsum dolor sit amet, consectetur adipisicing elit
</ListItem>
</List>
);
};
Table - Source
Import
import {
Table,
TableCaption,
TableContainer,
Tbody,
Td,
Tfoot,
Th,
Thead,
Tr,
} from "@black-ui/react";
Usage
export const Example = () => {
return (
<TableContainer>
<Table variant="filled">
<TableCaption>Imperial to metric conversion factors</TableCaption>
<Thead>
<Tr>
<Th>To convert</Th>
<Th>into</Th>
<Th>multiply by</Th>
</Tr>
</Thead>
<Tbody>
<Tr>
<Td>inches</Td>
<Td>millimetres (mm)</Td>
<Td>25.4</Td>
</Tr>
<Tr>
<Td>feet</Td>
<Td>centimetres (cm)</Td>
<Td>30.48</Td>
</Tr>
<Tr>
<Td>yards</Td>
<Td>metres (m)</Td>
<Td>0.91444</Td>
</Tr>
</Tbody>
<Tfoot>
<Tr>
<Th>To convert</Th>
<Th>into</Th>
<Th>multiply by</Th>
</Tr>
</Tfoot>
</Table>
</TableContainer>
);
};
Tag - Source
Import
import { Tag, TagIcon, TagLabel } from "@black-ui/react";
Usage
export const Example = () => {
return (
<>
<Tag>Sample Tag</Tag>
<Tag color="red" variant="solid">
<TagIcon as={<IoMdSettings />} />
<TagLabel>Left Icon</TagLabel>
</Tag>
<Tag color="blue" variant="subtle">
<TagLabel>Right Icon</TagLabel>
<TagIcon as={<IoMdSettings />} />
</Tag>
<Tag>
<TagLabel>Close Tag</TagLabel>
</Tag>
</>
);
};
Disclosure
Accordion - Source
Import
import {
Accordion,
AccordionButton,
AccordionItem,
AccordionPanel,
} from "@black-ui/react";
Usage
export const Example = () => {
return (
<Accordion>
<AccordionItem>
<AccordionButton>First Title</AccordionButton>
<AccordionPanel>First Contents</AccordionPanel>
</AccordionItem>
<AccordionItem>
<AccordionButton>Second Title</AccordionButton>
<AccordionPanel>Second Contents</AccordionPanel>
</AccordionItem>
</Accordion>
);
};
Tabs - Source
Import
import { Tab, TabList, TabPanel, TabPanels, Tabs } from "@black-ui/react";
Usage
export const Example = () => {
return (
<Tabs variant="soft-rounded">
<TabList>
<Tab>First Tab</Tab>
<Tab>Second Tab</Tab>
</TabList>
<TabPanels>
<TabPanel>First Panel</TabPanel>
<TabPanel>Second Panel</TabPanel>
</TabPanels>
</Tabs>
);
};
VisuallyHidden - Source
Import
import { VisuallyHidden, VisuallyHiddenInput } from "@black-ui/react";
Usage
export const Example = () => {
return (
<>
<VisuallyHidden>Hello</VisuallyHidden>
<VisuallyHiddenInput />
</>
);
};
Feedback
Progress - Source
Import
import { Progress } from "@black-ui/react";
Usage
export const Example = () => {
const [value, setValue] = useState(0);
return <Progress value={value} />;
};
Skeleton - Source
Import
import { Skeleton } from "@black-ui/react";
Usage
export const Example = () => {
return (
<Skeleton width="150px" height="150px" radius="15px" background="gray" />
);
};
Spinner - Source
Import
import { Spinner } from "@black-ui/react";
Usage
export const Example = () => {
return <Spinner size="sm" />;
};
Toast - Source
Import
import { ToastProvider, useToast, Button } from "@black-ui/react";
Usage
export const Example = () => {
const { openToast } = useToast();
return (
<ToastProvider>
<Button
onClick={() =>
openToast({
title: "Title",
description: "Description",
status: "success",
})
}
>
Toast
</Button>
</ToastProvider>
);
};
Form
Button - Source
Import
import { Button, IconButton } from "@black-ui/react";
Usage
export const Example = () => {
return (
<>
<Button size="lg" variant="solid" color="black" leftIcon={<IoMdClose />}>
Button
</Button>
<Button size="lg" variant="outline" color="red" rightIcon={<IoMdClose />}>
Button
</Button>
<Button
size="lg"
variant="solid"
color="black"
onClick={() => alert("블랙 클릭")}
leftIcon={<IoMdClose />}
isLoading
spinner={<IoIosArrowDown />}
>
Button
</Button>
<Button
size="lg"
variant="solid"
color="black"
onClick={() => alert("블랙 클릭")}
leftIcon={<IoMdClose />}
isLoading
loadingText="loading..."
spinnerPlacement="right"
>
Button
</Button>
<Button
size="lg"
variant="outline"
color="red"
onClick={() => alert("레드 클릭")}
>
<IoMdClose />
Button
</Button>
<Button
size="lg"
variant="outline"
color="red"
isDisabled
onClick={() => alert("레드 클릭")}
>
Button
</Button>
<IconButton icon={<IoMdStar />} aria-label="Star" isLoading />
</>
);
};
Checkbox - Source
Import
import { Checkbox } from "@black-ui/react";
Usage
export const Example = () => {
return (
<>
<Checkbox color="black" size="xs">
XS Checkbox
</Checkbox>
<Checkbox color="red" size="sm" disabled>
SM Checkbox
</Checkbox>
<Checkbox color="red" size="md" defaultChecked>
MD Checkbox
</Checkbox>
<Checkbox color="red" size="lg" readOnly>
LG Checkbox
</Checkbox>
</>
);
};
FormControl - Source
Import
import {
FormControl,
FormLabel,
FormHelperText,
FormErrorMessage,
Input,
} from "@black-ui/react";
Usage
export const Example = () => {
return (
<FormControl>
<FormLabel>Email</FormLabel>
<Input />
<FormHelperText>
Enter the email you'd like to receive the newsletter on.
</FormHelperText>
<FormErrorMessage>Email is required.</FormErrorMessage>
</FormControl>
);
};
Input - Source
Import
import { Input } from "@black-ui/react";
Usage
export const Example = () => {
return (
<>
<Input placeholder="아이디를 입력해라" size="xs" variant="outline" />
<Input placeholder="아이디를 입력해라" size="xs" variant="filled" />
<Input placeholder="아이디를 입력해라" size="xs" variant="flushed" />
<Input placeholder="아이디를 입력해라" size="xs" variant="unstyled" />
</>
);
};
PinInput - Source
Import
import { PinInput, PinInputField } from "@black-ui/react";
Usage
export const Example = () => {
return (
<PinInput size="lg" mask>
<PinInputField />
<PinInputField />
<PinInputField />
<PinInputField />
</PinInput>
);
};
Radio - Source
Import
import { RadioGroup, Radio } from "@black-ui/react";
Usage
export const Example = () => {
const [radioValue, setRadioValue] = useState("");
const changeRadio = (value: string) => {
setRadioValue(value);
};
return (
<RadioGroup onChange={changeRadio} direction="row">
<Radio color="black" size="xs" value={1}>
XS Radio
</Radio>
<Radio color="black" size="sm" value={2}>
SM Radio
</Radio>
<Radio color="black" size="md" value={3}>
MD Radio
</Radio>
<Radio color="red" size="lg" value={4}>
LG Radio
</Radio>
</RadioGroup>
);
};
CustomSelect - Source
Import
import {
CustomSelect,
CustomSelectTrigger,
CustomSelectContent,
CustomSelectGroup,
CustomSelectLabel,
CustomSelectItem,
} from "@black-ui/react";
Usage
export const Example = () => {
return (
<CustomSelect size="md" variant="outline" label="과일을 선택해주세요.">
<CustomSelectTrigger></CustomSelectTrigger>
<CustomSelectContent>
<CustomSelectGroup>
<CustomSelectLabel>Fruits</CustomSelectLabel>
<CustomSelectItem value="apple">Apple</CustomSelectItem>
<CustomSelectItem value="banana">Banana</CustomSelectItem>
<CustomSelectItem value="blueberry">Blueberry</CustomSelectItem>
</CustomSelectGroup>
</CustomSelectContent>
</CustomSelect>
);
};
Slider - Source
Import
import { Slider } from "@black-ui/react";
Usage
export const Example = () => {
const [value, setValue] = useState(0);
return (
<Slider
color="red"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
};
Switch - Source
Import
import { Switch } from "@black-ui/react";
Usage
export const Example = () => {
const [value, setValue] = useState("");
return (
<Switch
size="xs"
color="red"
value={value}
onChage={(e) => value(e.target.value)}
>
Red
</Switch>
);
};
Textarea - Source
Import
import { Textarea } from "@black-ui/react";
Usage
export const Example = () => {
const [value, setValue] = useState("");
return (
<Textarea
placeholder="Here is a sample placeholder"
size="sm"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
};
Overlay
Drawer - Source
Import
import {
Drawer,
DrawerOverlay,
DrawerContent,
DrawerCloseButton,
DrawerHeader,
DrawerBody,
DrawerFooter,
useDisclosure,
} from "@black-ui/react";
Usage
export const Example = () => {
const {
isOpen: isDrawerOpen,
onOpen: onDrawerOpen,
onClose: onDrawerClose,
} = useDisclosure();
return (
<Drawer isOpen={isDrawerOpen} onClose={onDrawerClose} placement={placement}>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>Header</DrawerHeader>
<DrawerBody>Body</DrawerBody>
<DrawerFooter>Footer</DrawerFooter>
</DrawerContent>
</Drawer>
);
};
Menu - Source
Import
import { Menu, MenuButton, MenuList, MenuItem } from "@black-ui/react";
Usage
export const Example = () => {
return (
<Menu>
<MenuButton>Menu 나와라!</MenuButton>
<MenuList>
<MenuItem
onClick={() => {
alert("다운로드!");
}}
>
Download
</MenuItem>
<MenuItem>Create a Copy</MenuItem>
<MenuItem>Mark as Draft</MenuItem>
<MenuItem>Delete</MenuItem>
<MenuItem>Attend a Workshop</MenuItem>
</MenuList>
</Menu>
);
};
Modal - Source
Import
import {
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
useDisclosure,
} from "@black-ui/react";
Usage
export const Example = () => {
const {
isOpen: isModalOpen,
onOpen: onModalOpen,
onClose: onModalClose,
} = useDisclosure();
return (
<>
<Button onClick={onModalOpen}>Modal 나와라!</Button>
<Modal isOpen={isModalOpen} onClose={onModalClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody>
<div>Modal 입니다!</div>
</ModalBody>
<ModalFooter>
<Button onClick={() => onModalClose()}>취소</Button>
<Button onClick={() => onModalClose()}>확인</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
};
Popover - Source
Import
import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverCloseButton,
Button,
} from "@black-ui/react";
Usage
export const Example = () => {
return (
<Popover>
<PopoverTrigger>
<Button>Popover 나와라!</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverCloseButton />
<div>Popover입니다!!</div>
</PopoverContent>
</Popover>
);
};
Tooltip - Source
Import
import { Tooltip } from "@black-ui/react";
Usage
export const Example = () => {
return (
<Tooltip label="Hover me">
<Button>Tooltip 나와라!</Button>
</Tooltip>
);
};
Other
CloseButton - Source
Import
import { CloseButton } from "@black-ui/react";
Usage
export const Example = () => {
return <CloseButton size="sm" />;
};
Portal - Source
Import
import { Portal } from "@black-ui/react";
Usage
export const Example = () => {
return (
<Portal>
<div>This text is portaled at the end of document.body!</div>
</Portal>
);
};
Theme - Source
Import
import { ThemeProvider, ThemeSwitcher } from "@black-ui/react";
Usage
export const Example = () => {
return (
<ThemeProvider defaultMode="light">
<ThemeSwitcher></ThemeSwitcher>
</ThemeProvider>
);
};
Hooks
useDisclosure - Source
Import
import { useDisclosure } from "@black-ui/react";
Usage
export const Example = () => {
const {
isOpen: isModalOpen,
onOpen: onModalOpen,
onClose: onModalClose,
} = useDisclosure();
return (
<>
<Button onClick={onModalOpen}>Modal 나와라!</Button>
<Modal isOpen={isModalOpen} onClose={onModalClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody>
<div>Modal 입니다!</div>
</ModalBody>
<ModalFooter>
<Button onClick={() => onModalClose()}>취소</Button>
<Button onClick={() => onModalClose()}>확인</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
};
useClipboard - Source
Import
import { useClipboard } from "@black-ui/react";
Usage
export const Example = () => {
const { onCopy, value, setValue, hasCopied } = useClipboard("");
return (
<>
<Input
placeholder={"내용이 복사됩니다."}
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
<Button onClick={onCopy}>{hasCopied ? "Copied!" : "Copy"}</Button>
</>
);
};
useOutsideClick - Source
Import
import { useOutsideClick } from "@black-ui/react";
Usage
function Example() {
const ref = React.useRef();
const [isModalOpen, setIsModalOpen] = React.useState(false);
useOutsideClick({
ref: ref,
handler: () => setIsModalOpen(false),
});
return (
<>
{isModalOpen ? (
<div ref={ref}>
👋 Hey, I'm a modal. Click anywhere outside of me to close.
</div>
) : (
<button onClick={() => setIsModalOpen(true)}>Open Modal</button>
)}
</>
);
}