@black-ui/react
TypeScript icon, indicating that this package has built-in type declarations

0.0.26 • Public • Published

header

Vanilla Extract 기반 디자인 시스템으로 성능 저하 없이 멋진 디자인을 구현하세요!

미완성 프로젝트입니다. 개선할 부분이 있다면 언제든지 Issues 남겨주세요!

Table of Contents

기술 설명
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>
      )}
    </>
  );
}

Package Sidebar

Install

npm i @black-ui/react

Weekly Downloads

441

Version

0.0.26

License

MIT

Unpacked Size

21.9 MB

Total Files

527

Last publish

Collaborators

  • hyeon9782