Shared UI

packages/ui 문서 모음집

공통 토큰과 컴포넌트를 문서처럼 탐색할 수 있게 정리한 화면입니다. 좌측 카테고리로 문서 이동, 우측 목차로 Button 세부 설명 이동이 가능합니다.

foundation: 2components: 3button api: documented

소개

황총무 내부 공통 컴포넌트를 분리해서 다른 프로젝트에서도 재사용할 수 있도록 만든 UI 패키지입니다.

포함 범위

  • 디자인 토큰과 테마
  • 공용 Provider와 글로벌 스타일
  • 재사용 가능한 기본 컴포넌트

문서 구조

  • 좌측: 소개, 파운데이션, 컴포넌트 이동
  • 가운데: 실제 예제와 코드
  • 우측: Button 세부 목차 바로가기

사용방법

패키지를 import 하고, 앱 루트에 Provider를 연결한 뒤 컴포넌트를 사용합니다.

Import

import { Button, Input, Typography } from "@hwangchongmu/ui"

Provider

import { UiProvider } from "@hwangchongmu/ui"

Foundation / Colors

`uiTheme.colors` 기준의 색상 토큰입니다.

white

#ffffff

black

#000000

gray50

oklch(0.985 0 0)

gray100

oklch(0.97 0 0)

gray200

oklch(0.922 0 0)

gray300

oklch(0.87 0 0)

gray400

oklch(0.708 0 0)

gray500

oklch(0.556 0 0)

gray600

oklch(0.439 0 0)

gray700

oklch(0.371 0 0)

gray800

oklch(0.269 0 0)

gray900

oklch(0.205 0 0)

gray950

oklch(0.145 0 0)

blue50

oklch(0.97 0.014 254.604)

blue100

oklch(0.932 0.032 255.585)

blue200

oklch(0.882 0.059 254.128)

blue500

oklch(0.623 0.214 259.815)

blue600

oklch(0.546 0.245 262.881)

blue700

oklch(0.488 0.243 264.376)

indigo50

oklch(0.962 0.018 272.314)

indigo100

oklch(0.93 0.034 272.788)

indigo500

oklch(0.585 0.233 277.117)

indigo600

oklch(0.511 0.262 276.966)

yellow50

oklch(0.987 0.026 102.212)

yellow100

oklch(0.973 0.071 103.193)

yellow200

oklch(0.945 0.129 101.54)

yellow400

oklch(0.852 0.199 91.936)

yellow500

oklch(0.795 0.184 86.047)

yellow600

oklch(0.681 0.162 75.834)

green50

oklch(0.982 0.018 155.826)

green100

oklch(0.962 0.044 156.743)

green200

oklch(0.925 0.084 155.995)

green500

oklch(0.723 0.219 149.579)

green600

oklch(0.627 0.194 149.214)

teal50

oklch(0.984 0.014 180.72)

teal100

oklch(0.953 0.051 180.801)

teal200

oklch(0.91 0.096 180.426)

teal500

oklch(0.704 0.14 182.503)

teal600

oklch(0.6 0.118 184.704)

rose50

oklch(0.969 0.015 12.422)

rose100

oklch(0.941 0.03 12.58)

rose200

oklch(0.892 0.058 10.001)

rose500

oklch(0.645 0.246 16.439)

rose600

oklch(0.586 0.253 17.585)

amber50

oklch(0.987 0.022 95.277)

amber100

oklch(0.962 0.059 95.617)

amber200

oklch(0.924 0.12 95.746)

amber500

oklch(0.769 0.188 70.08)

amber600

oklch(0.666 0.179 58.318)

orange50

oklch(0.98 0.016 73.684)

orange100

oklch(0.954 0.038 75.164)

orange200

oklch(0.901 0.076 70.697)

orange500

oklch(0.705 0.213 47.604)

orange600

oklch(0.646 0.222 41.116)

Foundation / Typography

기본 텍스트 스케일입니다.

h1 preview text

h2 preview text

h3 preview text

h4 preview text

body1 preview text

body2 preview text

caption preview text

label preview text

Component / Button

`Button` 컴포넌트는 color, variant, display, size, loading을 조합해서 다양한 액션 버튼을 만들 수 있습니다.

사용 예제

가장 기본적인 text + icon 조합입니다.

React Code

import { Button } from "@hwangchongmu/ui";
import FileDownloadOutlinedIcon from "@mui/icons-material/FileDownloadOutlined";

export function Example() {
  return (
    <Button
      color="primary"
      variant="fill"
      size="large"
      leftIcon={<FileDownloadOutlinedIcon />}
    >
      저장하기
    </Button>
  );
}

크기 조정하기

`size` 속성으로 버튼의 높이와 패딩을 변경합니다.

1
2
3
4

스타일

`color`와 `variant` 조합으로 버튼 톤을 조절합니다.

1

primary

2

danger

3

light

4

dark

형태

`display` 속성으로 버튼의 배치 방식을 제어합니다.

inline

block

full

아이콘

좌측 아이콘, 우측 아이콘, 아이콘 전용 버튼까지 지원합니다.

left icon

right icon

icon only

로딩과 비활성화

`loading`이면 스피너를 표시하고, 상호작용을 동시에 막습니다.

loading

disabled

접근성

아이콘만 있거나 설명이 부족한 버튼은 추가 속성이 필요합니다.

  • 아이콘 전용 버튼은 `aria-label`을 함께 제공합니다.
  • as="a"를 쓰면 링크 태그로 렌더링됩니다.
  • `loading` 상태는 사용자가 중복 클릭하지 못하게 막아줍니다.

인터페이스

문서에 적힌 규칙이 실제 버튼 타입과 동일합니다.

type ButtonAs = "button" | "a";
type ButtonColor = "primary" | "danger" | "light" | "dark";
type ButtonVariant = "fill" | "weak";
type ButtonDisplay = "inline" | "block" | "full";
type ButtonSize = "small" | "medium" | "large" | "xlarge";

interface ButtonProps {
  as?: ButtonAs;
  color?: ButtonColor;
  variant?: ButtonVariant;
  display?: ButtonDisplay;
  size?: ButtonSize;
  loading?: boolean;
  disabled?: boolean;
  type?: "button" | "submit" | "reset";
  htmlStyle?: React.CSSProperties;
  onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
  leftIcon?: React.ReactNode;
  rightIcon?: React.ReactNode;
}

Component / Input

라벨, 우측 보조 문구, 오류 상태를 가진 기본 입력 필드입니다.

Component / Typography

타이포 스케일과 색상 토큰을 연결하는 기본 텍스트 컴포넌트입니다.

h1 preview text

h2 preview text

h3 preview text

h4 preview text

body1 preview text

body2 preview text

caption preview text

label preview text

프로젝트 공통 컴포넌트

황총무 앱 곳곳에서 재사용되는 `components/common/` 컴포넌트들입니다. UI 패키지(@hwangchongmu/ui)와 달리 프로젝트 의존성이 있어 패키지로 분리하지 않은 컴포넌트입니다.

PageIntro

아이콘 + 타이틀 + 설명으로 구성된 페이지 상단 헤더. `StHighlight`로 본문 강조도 가능합니다.

🐰

황총무의 약속잡기

모임 일정을 빠르게 모아주는 도구

React Code

import PageIntro, { StHighlight } from "@/components/common/PageIntro";

export function Example() {
  return (
    <PageIntro
      icon="🐰"
      title="황총무의 약속잡기"
      description={
        <>
          모임 일정을 <StHighlight $color="blue">빠르게</StHighlight> 모아주는 도구
        </>
      }
    />
  );
}

CreateButton

폼 하단의 메인 액션용 100% 너비 버튼. `bgColor` 지정 시 컬러 톤 + 그림자, 미지정 시 기본 다크 톤. `isLoading` 처리 내장.

React Code

import CreateButton from "@/components/common/CreateButton";

export function Example() {
  return (
    <>
      <CreateButton onClick={handleCreate}>약속 만들기</CreateButton>
      <CreateButton bgColor="#3B82F6" isLoading loadingText="저장 중...">
        저장하기
      </CreateButton>
    </>
  );
}

useModal (ModalProvider)

앱 루트 `ModalProvider`로 감싸두고, `useModal()`이 돌려주는 `openAlert` / `openConfirm`을 Promise처럼 await 해서 사용합니다.

React Code

import { useModal } from "@/components/common/ModalProvider";

export function Example() {
  const { openAlert, openConfirm } = useModal();

  async function handleDelete() {
    const ok = await openConfirm("정말 삭제할까요?");
    if (!ok) return;
    await deleteItem();
    await openAlert("삭제되었습니다.");
  }

  return <button onClick={handleDelete}>삭제</button>;
}

Switch

controlled 토글. `aria-checked` / `role="switch"`가 들어가 있어 접근성 OK.

현재 상태: 켜짐

React Code

import Switch from "@/components/common/Switch";

export function Example() {
  const [on, setOn] = useState(false);
  return <Switch checked={on} onChange={setOn} label="알림 켜기" />;
}

TagInput

Enter로 추가, Backspace로 마지막 태그 삭제, IME 조합 중 입력 무시.

참석자
승현
지유

React Code

import TagInput from "@/components/common/TagInput";

export function Example() {
  const [tags, setTags] = useState<string[]>([]);
  return (
    <TagInput
      label="참석자"
      placeholder="이름 입력 후 Enter"
      tags={tags}
      onChange={setTags}
    />
  );
}

ColorPickerPanel

프리셋 칩 + native color picker. 색상 카테고리(라벨, 카드 등) 지정 UI에 사용.

직접 선택:

선택된 색상: #3B82F6

React Code

import ColorPickerPanel from "@/components/common/ColorPickerPanel";

const PRESETS = ["#3B82F6", "#10B981", "#F59E0B", "#EF4444", "#6366F1"];

export function Example() {
  const [color, setColor] = useState(PRESETS[0]);
  return (
    <ColorPickerPanel
      colors={PRESETS}
      selectedColor={color}
      onSelect={setColor}
    />
  );
}

ShareButton

현재 페이지 URL을 클립보드에 복사하고 2초 툴팁을 띄우는 동그란 아이콘 버튼.

React Code

import ShareButton from "@/components/common/ShareButton";

export function Example() {
  return <ShareButton iconSize={20} />;
}