JS Design System v0.6

Loading

로딩 상태를 알립니다. 1초 미만은 표시하지 않고, 영역 로딩은 Skeleton, 짧은 동작은 Spinner, 진행률을 알면 Progress.

1. Default

기본 크기(24px) 스피너입니다.

2. Spinner

sm 16 · md 24 · lg 40. 버튼 안에서는 Button .loading 을 씁니다.

이벤트를 불러오는 중…

3. Skeleton

콘텐츠 형태를 미리 보여줍니다. 목록·카드의 첫 로딩에.

4. Progress

진행률을 알 때. 배포·검사 진행. 완료는 success, 실패는 danger.

정책 배포 중842 / 1,284
전체 검사 완료100%
업데이트 실패38%

Props

HTML 에서는 클래스와 속성으로, React(@jiran/ds-react)에서는 같은 이름의 prop(variant · size …)으로 변형·상태를 지정합니다.

Prop / ClassType · ValuesDefaultDescription
.spinnerspan—role=status aria-label. sm | (md) | lg
.skeletonspan—.title | .text(.short) | .circle | .rect. 컨테이너에 aria-busy
.progressdiv—role=progressbar aria-valuenow. i 의 width 가 진행률
tone.success | .dangeraccent완료 / 실패
.smbooleanfalse높이 4

Usage

React: @jiran/ds-react 패키지를 설치하고 style.css 를 한 번 import 하면 위 React 탭 코드를 그대로 쓸 수 있습니다(React Package). HTML: assets/style.css 를 연결하고(일부만 필요하면 아래 컴포넌트 CSS 복사), 동작이 필요하면 assets/ds.js 를 함께 넣습니다 — 이 페이지의 프리뷰가 그 스크립트로 동작합니다. 색은 전부 토큰(var(--accent) 등)을 참조하므로 --accent-* 만 제품 컬러로 바꾸면 됩니다.

React @jiran/ds-react

npm i @jiran/ds-react

// main.tsx — 앱 진입점에서 한 번
import "@jiran/ds-react/style.css";

// 컴포넌트
import { Spinner, Skeleton, SkeletonRow, Progress } from "@jiran/ds-react";

HTML

<!-- 1) 토큰 + 전체 컴포넌트 스타일 한 번에 연결 -->
<link rel="stylesheet" href="assets/style.css">
<!-- 동작(드롭다운·탭·달력·표 정렬/선택·토스트 등) — 순수 JS 한 파일. React 제품은 불필요 -->
<script src="assets/ds.js" defer></script>

<!-- 2) 또는 아래 "Component CSS" 만 프로젝트 CSS 에 붙이고,
        :root 토큰은 Foundations › Design Token 에서 복사 -->

Component CSS .spinner, .spinner-wrap, .skeleton, .skeleton-row, .progress, .progress-row

/* JS Design System v0.6 · .spinner, .spinner-wrap, .skeleton, .skeleton-row, .progress, .progress-row · 토큰(var(--*))은 assets/style.css :root 참고 */
.spinner{display:inline-block;width:24px;height:24px;border:3px solid var(--border-default);border-top-color:var(--accent);border-radius:50%;animation:spin .8s linear infinite}
.spinner.sm{width:16px;height:16px;border-width:2px}
.spinner.lg{width:40px;height:40px;border-width:4px}
.spinner-wrap{display:inline-flex;flex-direction:column;align-items:center;gap:12px;font-size:12px;color:var(--text-tertiary)}
.skeleton{display:block;height:14px;border-radius:6px;background:linear-gradient(90deg,var(--bg-panel) 25%,var(--bg-subtle) 50%,var(--bg-panel) 75%);background-size:200% 100%;animation:shimmer 1.4s infinite}
.skeleton.title{height:20px;width:40%}
.skeleton.text{width:100%}
.skeleton.text.short{width:70%}
.skeleton.circle{width:40px;height:40px;border-radius:50%;flex:none}
.skeleton.rect{height:120px;border-radius:var(--radius-md)}
.skeleton-row{display:flex;align-items:center;gap:12px;width:100%}
.skeleton-row .lines{flex:1;display:flex;flex-direction:column;gap:8px}
.progress{width:100%;height:8px;border-radius:var(--radius-full);background:var(--fill-strong);overflow:hidden}
.progress i{display:block;height:100%;background:var(--accent-graphic);border-radius:var(--radius-full);transition:width var(--motion-base)}
.progress.sm{height:4px}
.progress.success i{background:var(--success)}
.progress.danger i{background:var(--danger)}
.progress-row{display:flex;flex-direction:column;gap:6px;width:100%;font-size:12px;color:var(--text-secondary)}
.progress-row .row{display:flex;justify-content:space-between}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes shimmer{to{background-position:-200% 0}}