sellmate-design-system-react 9.0.0-beta.80 → 9.0.0-beta.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -42,7 +42,7 @@
42
42
  | **버튼·링크** | `SButton` `SGhostButton` `SMeatballButton`(⋯ 로 '더 보기' 메뉴를 여는 아이콘 버튼) `SDropdownButton` `STextLink` `SSwitch` `SToggle` |
43
43
  | **입력 (폼)** | `SForm` `SField` `SInput` `SChatInput`(대화 입력창) `SSearchInput` `SNumberInput` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SChip` `SChipInput` `SBarcodeInput` `SFilePicker` |
44
44
  | **날짜·시간** | `SCalendar` `SCalendarBoard`(한 달치 일정 판) `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` |
45
- | **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(입력창 위, 아직 보내지 않은 첨부 한 칸) `SChatFile`(대화 흐름에 선, 보낸 파일 한 칸) `SChatSystemMessage`(대화 흐름 가운데 서는 시스템 안내) `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SListItem` `SExpansionList` `SDraggableList` `SDraggableItem` `STree` |
45
+ | **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(입력창 위, 아직 보내지 않은 첨부 한 칸) `SChatFile`(대화 흐름에 선, 보낸 파일 한 칸) `SChatSystemMessage`(대화 흐름 가운데 서는 시스템 안내) `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SListItem` `SExpansionList` `SDraggableList` `SDraggableItem` `STree` `STimeline`(날짜로 묶인 시간순 기록 — 작업 로그·메모 이력) |
46
46
  | **레이아웃** | `SLayout` `SGnb` `SGnbSystem` `SSystemActionButton`(GNB system 패널에 한 줄씩 쌓는 액션 행 — 버튼 고르기는 §3-5) `SAccountListBox`(계정 행을 눌러 뜨는 계정 패널) `SLauncherListBox`(런처 버튼을 눌러 뜨는 서비스 목록) `SPage` `SPageHeader`(페이지 제목 영역 — `SLayout` 안에서 `SPage` 앞에 둔다) `SSectionHeaderCard` `SCard` `SLoginCard`(통합 계정 로그인 화면의 카드) `SDivider` `SSplitter` `SScrollArea` `SExpansionItem` |
47
47
  | **내비게이션** | `STabs` `SPagination` `SStepper` |
48
48
  | **차트** | `SBarChart`(막대 그래프 — 항목끼리 크기를 견준다. `stacked` 로 항목 안의 구성까지) `SLineChart`(꺾은선 그래프 — 순서가 있는 항목의 추이를 본다. `area` 로 크기까지, `stacked` 로 구성까지) `SPieChart`(원그래프 — 한 시점의 전체를 몇 개의 몫으로 나눈다) `SDonutChart`(도넛 그래프 — 가운데가 빈 원그래프. 구멍에 글자를 두지 않는다) |
@@ -167,7 +167,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
167
167
  | 층 | 무엇인가 | 컴포넌트 |
168
168
  | --- | --- | --- |
169
169
  | **셸** | 앱 전체 뼈대. 페이지가 바뀌어도 남는다 | `SLayout` `SGnb` `SGnbSystem`(GNB 맨 아래 판 · 전폭 상단바 오른쪽 끝) `SPage` `SPageHeader`(`SLayout` 안에서 `SPage` 앞에 둔다) |
170
- | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `SCallout` `SContextAlert` `SBarChart` `SLineChart` `SPieChart` `SDonutChart` `STabs` `SStepper` `SPagination` `SDivider` |
170
+ | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `STimeline` `SCallout` `SContextAlert` `SBarChart` `SLineChart` `SPieChart` `SDonutChart` `STabs` `SStepper` `SPagination` `SDivider` |
171
171
  | **요소** | 블록 **안에** 놓이는 컨트롤. 혼자 페이지에 서지 않는다 | `SButton` `SGhostButton` `SMeatballButton` `SDropdownButton` `SSystemActionButton` `SField` `SInput` `SSearchInput` `SNumberInput` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SSwitch` `SToggle` `SChipInput` `SBarcodeInput` `SFilePicker` `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` `SCalendar` `SListItem` `SExpansionItem` `SDraggableItem` `SChatAttachedFile` `SChatFile` `SImage` `SLinearProgress` `SCircleProgress` `SSkeleton` |
172
172
  | **인라인** | 텍스트 흐름·셀·라벨 안에 섞인다. 혼자 블록이 되지 않는다 | `STag` `SBadge` `SIcon` `SLogo` `STextLink` `SChip` |
173
173
  | **레이어** | 문서 흐름 **밖**에 떠서 그려진다. 어느 층에서 띄우든 레이아웃에 영향이 없다 | `SModal` `SActionModal` `SConfirmModal` `SPopup` `SDrawer` `SPopover` `STooltip` `SPortal` `SAccountListBox`(계정 행에 붙어 뜬다 — 직접 띄우지 않는다) `SLauncherListBox`(런처 버튼에 붙어 뜬다 — 직접 띄우지 않는다) `SToast` `SLoadingModal` `SLoadingContainer` `SGuide` |
@@ -563,6 +563,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
563
563
  | 여러 건을 여러 열로 보여주고 열끼리 비교하게 한다 | `STable` | §3-7-6 |
564
564
  | 항목 하나의 속성들을 `라벨: 값` 으로 보여준다 | `SKeyValueTable` | §4-4 |
565
565
  | 한 줄로 읽히는 항목을 세로로 나열한다 | `SList` + `SListItem` | §3-7-6 |
566
+ | 시각이 붙은 기록을 날짜별로 묶어 시간순으로 보여준다 (작업 로그·메모 이력) | `STimeline` | §3-7-6 |
566
567
  | 대화의 메시지 한 건을 보여준다 | `SChatMessage` | |
567
568
  | 대화 중간에 시스템이 알리는 사실을 끼운다 (상담사 배정·대화 종료 등) | `SChatSystemMessage` | 사람이 보낸 말이면 `SChatMessage` |
568
569
  | 나열한 항목을 펼쳐 하위 내용을 보여준다 | `SExpansionList` + `SExpansionItem` | §3-7-7 |
@@ -1417,6 +1418,7 @@ tableRef.current.scrollToRow(row); // 복원
1417
1418
  | **`default`**(기본) | `#888888` | **대부분** — 닫기, 복사, 드래그, 펼치기, 행 삭제 |
1418
1419
  | `action` | `#025497` | 진입·추가처럼 **의미 있는 조작** — 편집 모드 진입, 항목 추가, 행 수정 |
1419
1420
  | `subAction` | `#5CB0F3` | `action` 다음 계층 — `action`·`default` 사이의 중의적 의미 + 부분 강조 |
1421
+ | `complete` | `#00973C` | **완료**를 나타내는 조작 — 완료 처리(`check`) 등 |
1420
1422
  | `danger` | `#E30000` | **되돌릴 수 없는 삭제** |
1421
1423
  | `inverse` | `#FFFFFF` | 어두운 배경 위 (GNB 접기 등) |
1422
1424
 
@@ -1898,15 +1900,17 @@ const [from, setFrom] = useState<string | null>(null);
1898
1900
 
1899
1901
  직접 쓰는 경우는 하나뿐이다 — **디자인 시스템에 없는 컨트롤**에 다른 필드와 똑같은 라벨·필수·에러 모양을 붙일 때.
1900
1902
 
1901
- #### 3-7-6. 여러 건을 나열하는 셋 — STable vs SList vs SDraggableList
1903
+ #### 3-7-6. 여러 건을 나열하는 넷 — STable vs SList vs SDraggableList vs STimeline
1902
1904
 
1903
1905
  | 판별 | 사용 |
1904
1906
  | --- | --- |
1905
1907
  | 열이 둘 이상이고 **열끼리 값을 비교**한다 (정렬·합계·자릿수 맞춤) | `STable` |
1906
1908
  | 한 항목이 **한 줄로 읽힌다** (제목 + 보조 텍스트) | `SList` + `SListItem` |
1907
1909
  | **순서 자체가 데이터**라 사용자가 끌어서 바꾼다 | `SDraggableList` + `SDraggableItem` |
1910
+ | 항목마다 **시각**이 있고 날짜 머리글로 묶여 위에서 아래로 흐른다 (작업 로그·메모 이력) | `STimeline` |
1908
1911
 
1909
1912
  - **항목 하나의 속성을 나열하는 것은 목록이 아니다.** `라벨: 값` 이 세로로 쌓이는 것은 `SKeyValueTable` 이다 (§4-4).
1913
+ - **`STimeline` 의 레일(점·선)과 머리글·시각 열은 컴포넌트가 그린다.** `groups` 에 데이터만 넘기고, 점·선을 `border-l` 이나 절대 위치 `span` 으로 직접 그리지 않는다 — 선이 묶음 경계와 마지막 줄에서 끊기는 규칙을 컴포넌트가 계산한다. 작성자·편집 버튼 같은 업무 내용은 각 항목의 `content` 에 넣는다. 빈 상태 안내도 `emptyText` 로 넘기고, 불러오는 중에는 `emptyText={null}` 로 빈 안내를 숨긴다.
1910
1914
  - `SList` 는 레이아웃만 담당한다. depth 별 단일 펼침이 필요하면 `SExpansionList` 다 (§3-7-7).
1911
1915
  - **`SList` 의 자식은 `SListItem` 을 권장한다.** 다른 자식도 그대로 렌더되지만, 펼치는 항목은 `SExpansionList` + `SExpansionItem` 이, 끌어서 순서를 바꾸는 항목은 `SDraggableList` + `SDraggableItem` 이 여닫힘·정렬 동작까지 함께 관리하므로 그쪽을 쓴다 (§3-7-7).
1912
1916
  - **항목 사이 구분선은 리스트가 알아서 그린다.** `SListItem`·`SExpansionItem`·`SDraggableItem` 셋 다 스스로 구분선을 그리지 않는다. `SList`·`SExpansionList`·`SDraggableList` 가 자식 **사이에** 구분선을 넣으므로 아이템에 `border-b` 를 직접 붙이지 않고, 켜는 prop 도 따로 없다. 마지막 항목 아래에는 선이 남지 않는다. 테두리형(`bordered`)은 테두리가 구분 역할을 하므로 리스트가 구분선을 빼고, `gap` 으로 띄운다 — `gap` 을 준 목록에도 구분선은 들어가지 않는다.
@@ -1919,6 +1923,8 @@ const [from, setFrom] = useState<string | null>(null);
1919
1923
  ❌ <SList><SListItem title="일반 문의" className="border-b" />…</SList> {/* 구분선을 직접 붙이지 않는다 */}
1920
1924
  ❌ <SList><><SListItem title="일반 문의" /><SListItem title="결제 문의" /></></SList> {/* Fragment 로 묶으면 그 안쪽은 구분되지 않는다 */}
1921
1925
  ❌ <SListItem title="일반 문의" selected /> {/* clickable 없으면 선택 표시가 안 나온다 */}
1926
+ ✅ <STimeline groups={[{ heading: '2026-10-07', entries: [{ key: id, time: '14:32', content: <Memo … /> }] }]} />
1927
+ ❌ <div className="grid grid-cols-[52px_8px_1fr]"><span className="rounded-full …" />…</div> {/* 타임라인 레일을 직접 그리지 않는다 */}
1922
1928
  ```
1923
1929
 
1924
1930
  ##### 행 안에 컨트롤을 둘 때
@@ -2169,6 +2175,7 @@ const [selectedId, setSelectedId] = useState<string>();
2169
2175
  - **실제 레이아웃을 그대로 따라 그린다.** 폼 컨트롤 자리는 `type="input"`·`"button"`·`"checkbox"` 처럼 DS 모양을 쓴다. 해당 컴포넌트 기본 size 의 크기·모서리를 토큰으로 넣으므로 **높이·radius 를 직접 주지 않는다** — 직접 주면 데이터가 왔을 때 레이아웃이 튄다. checkbox·radio·switch 는 크기를 바꾸지 않는다.
2170
2176
  - **텍스트 줄은 `type="text"` 를 실제 텍스트와 같은 typo 클래스 안에 둔다.** 줄 높이를 부모 line-height 에서 받으므로 typo 밖에 두면 높이가 어긋난다. `text` 에 `height` 를 주지 않는다 — 높이가 필요하면 `rect` 다.
2171
2177
  - **원은 `size` 하나로 준다.** `width`·`height` 를 따로 주면 타원이 된다.
2178
+ - **색은 바탕 밝기로 `mode` 만 고른다.** 흰 면·회색 면 위는 기본(`light`), 어두운 면 위는 `mode="dark"`. 색·투명도·모서리는 `--cmp-skeleton-*` 토큰으로 이미 들어가므로 `background`·`opacity`·`rounded-*` 를 직접 주지 않는다.
2172
2179
  - **넓은 영역에는 `pulse` 를 쓰지 않는다.** 블록 전체가 줄었다 커져 레이아웃이 흔들려 보인다. 기본 `wave` 를 쓰고, 한 화면에 아주 많으면 `none`.
2173
2180
  - **로딩 중이라는 사실은 감싸는 영역에 `aria-busy` 로 알린다.** `SSkeleton` 자체는 장식이라 보조기기에 숨겨져 있다.
2174
2181
 
@@ -2181,6 +2188,7 @@ const [selectedId, setSelectedId] = useState<string>();
2181
2188
 
2182
2189
  ❌ <SSkeleton type="input" height={40} /> {/* 실제 SInput 과 높이가 달라 데이터가 오면 튄다 */}
2183
2190
  ❌ <SSkeleton type="text" height={24} /> {/* text 는 세로 절반만 칠한다 — rect 를 쓴다 */}
2191
+ ❌ <SSkeleton className="bg-grey-20" /> {/* 색은 토큰이 넣는다 — 어두운 면이면 mode="dark" */}
2184
2192
  ```
2185
2193
 
2186
2194
  ---
@@ -3350,14 +3358,17 @@ export default function SalesDashboardPage() {
3350
3358
  <SCard key={s.label} bordered className="flex flex-col gap-sd-4 p-sd-16">
3351
3359
  <span className="typo-body-sm-default text-fg-secondary">{s.label}</span>
3352
3360
  {/* 카드 안의 메인 수치는 typo-heading-xl — 제목에는 쓰지 않는다 (§2-1) */}
3353
- <span className="typo-heading-xl">
3361
+ <span className="typo-heading-xl text-right">
3354
3362
  {s.value.toLocaleString()}
3355
3363
  {s.unit}
3356
3364
  </span>
3357
- {/* 증감은 숫자 앞 부호와 색으로 함께 말한다 — 색만으로 뜻을 싣지 않는다 */}
3358
- <span className="typo-body-sm-default text-fg-tertiary">
3365
+ {/* 증감은 숫자 앞 부호와 색으로 함께 말한다 — 색만으로 뜻을 싣지 않는다.
3366
+ 문장 안 강조라 굵기는 typo-body-sm-medium 프리셋으로 준다 (§2-1) */}
3367
+ <span className="typo-body-sm-default text-right text-fg-tertiary">
3359
3368
  전기간 대비{' '}
3360
- <span className={s.change >= 0 ? 'text-fg-success' : 'text-fg-danger'}>
3369
+ <span
3370
+ className={`typo-body-sm-medium ${s.change >= 0 ? 'text-fg-success' : 'text-fg-danger'}`}
3371
+ >
3361
3372
  {s.change >= 0 ? '+' : ''}
3362
3373
  {s.change.toLocaleString()}%
3363
3374
  </span>
@@ -3368,16 +3379,20 @@ export default function SalesDashboardPage() {
3368
3379
 
3369
3380
  {/* 차트는 섹션 카드에 담는다. 차트 이름은 카드의 title 이 맡으므로 차트의 title 은 주지 않는다 —
3370
3381
  둘 다 주면 제목이 두 줄이 된다. 단위(unit)는 차트가 오른쪽 위에 적는다.
3371
- 한 페이지에 섹션 카드가 여럿이라 marker 를 켠다 (§4-5) */}
3382
+ 한 페이지 안의 카드 헤더(titleSize·배경)는 전부 같게 간다 (§4-5) */}
3372
3383
  {/* 날짜순 흐름이라 선 — 순서가 있는 항목의 추이 (§3-0 B). 항목(날짜)이 많아 한 줄을 다 쓴다 */}
3373
- <SSectionHeaderCard title="일별 매출" marker>
3384
+ <SSectionHeaderCard
3385
+ title="일별 매출"
3386
+ titleSize="sm"
3387
+ headerClassName="bg-bg-neutralBright!"
3388
+ padding="none"
3389
+ >
3374
3390
  <SLineChart
3375
3391
  categories={daily.categories}
3376
3392
  series={[{ name: '매출', data: daily.data }]}
3377
3393
  unit="원"
3378
3394
  area
3379
3395
  showLegend={false}
3380
- height={280}
3381
3396
  formatValue={won}
3382
3397
  // 차트는 "어느 쪽이 큰가" 까지만 답한다 — 정확한 값은 그날의 주문 목록에서 본다
3383
3398
  onPointClick={p => navigate(`/orders?date=${daily.dates[p.categoryIndex]}`)}
@@ -3386,26 +3401,36 @@ export default function SalesDashboardPage() {
3386
3401
 
3387
3402
  <div className="grid grid-cols-2 gap-sd-12">
3388
3403
  {/* 합계는 도넛 구멍이 아니라 카드 subtitle 에 적는다 (§3-0 B) */}
3389
- <SSectionHeaderCard title="판매처별 비중" marker subtitle={`합계 ${won(channelTotal)}`}>
3404
+ <SSectionHeaderCard
3405
+ title="판매처별 비중"
3406
+ titleSize="sm"
3407
+ subtitle={`합계 ${won(channelTotal)}`}
3408
+ padding="none"
3409
+ headerClassName="bg-bg-neutralBright!"
3410
+ >
3390
3411
  <SDonutChart
3391
3412
  data={channelShare}
3392
3413
  legendPosition="bottom"
3393
3414
  formatValue={won}
3394
3415
  // 그림은 폭만큼의 정사각형이다 — 칸을 다 채우면 옆 카드보다 훨씬 길어지므로
3395
3416
  // 화면 고유 치수로 폭을 묶는다 (§1-2)
3396
- className="mx-auto max-w-[280px]"
3417
+ className="mx-auto max-w-[310px]"
3397
3418
  />
3398
3419
  </SSectionHeaderCard>
3399
3420
 
3400
3421
  {/* 항목끼리 크기를 견주므로 막대. 상품명이 길어 가로 막대로 눕힌다 */}
3401
- <SSectionHeaderCard title="상품별 판매량 TOP 5" marker>
3422
+ <SSectionHeaderCard
3423
+ title="상품별 판매량 TOP 5"
3424
+ titleSize="sm"
3425
+ padding="none"
3426
+ headerClassName="bg-bg-neutralBright!"
3427
+ >
3402
3428
  <SBarChart
3403
3429
  categories={topProducts.categories}
3404
3430
  series={[{ name: '판매량', data: topProducts.data }]}
3405
3431
  unit="개"
3406
3432
  direction="horizontal"
3407
3433
  showLegend={false}
3408
- height={320}
3409
3434
  formatValue={v => `${v.toLocaleString()}개`}
3410
3435
  />
3411
3436
  </SSectionHeaderCard>
@@ -38,7 +38,8 @@ export type SGhostButtonSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg';
38
38
  ### SGhostButtonIntent
39
39
 
40
40
  ```ts
41
- export type SGhostButtonIntent = 'default' | 'danger' | 'action' | 'subAction' | 'inverse';
41
+ export type SGhostButtonIntent =
42
+ 'default' | 'danger' | 'action' | 'subAction' | 'complete' | 'inverse';
42
43
  ```
43
44
 
44
45
  ## Dependencies
@@ -1,7 +1,7 @@
1
1
  import { type CSSProperties, type MouseEvent } from 'react';
2
2
  import { type SIconName } from '../SIcon';
3
3
  export type SGhostButtonSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg';
4
- export type SGhostButtonIntent = 'default' | 'danger' | 'action' | 'subAction' | 'inverse';
4
+ export type SGhostButtonIntent = 'default' | 'danger' | 'action' | 'subAction' | 'complete' | 'inverse';
5
5
  export interface SGhostButtonProps {
6
6
  /** 표시할 아이콘명 (필수) */
7
7
  icon: SIconName;
@@ -12,6 +12,7 @@
12
12
  | `value?` | `string \| number \| null` | — | 현재 선택 값 |
13
13
  | `size?` | `SRadioButtonSize` | `'sm'` | 크기 |
14
14
  | `disabled?` | `boolean` | `false` | 전체 비활성 |
15
+ | `readOnly?` | `boolean` | `false` | 읽기 전용. 선택 값을 보여주기만 하고 바꿀 수 없다. 모든 버튼이 readOnly 배경, 선택된 버튼만 readOnly 테두리로 구분하며 글자는 기본색이다. 포커스·툴팁은 유지된다. `disabled`(그룹·옵션)가 함께 오면 disabled 가 우선한다. |
15
16
  | `name?` | `string` | — | input name 속성 |
16
17
  | `showTooltip?` | `boolean` | `false` | 옵션 호버 시 툴팁 노출. 문구는 옵션별 `tooltip` 으로 주며, 문구가 없는 옵션은 툴팁을 띄우지 않는다. 툴팁 타입은 `accent` 고정이다. |
17
18
  | `className?` | `string` | — | |
@@ -16,6 +16,12 @@ export interface SRadioButtonProps {
16
16
  size?: SRadioButtonSize;
17
17
  /** 전체 비활성 */
18
18
  disabled?: boolean;
19
+ /**
20
+ * 읽기 전용. 선택 값을 보여주기만 하고 바꿀 수 없다.
21
+ * 모든 버튼이 readOnly 배경, 선택된 버튼만 readOnly 테두리로 구분하며 글자는 기본색이다.
22
+ * 포커스·툴팁은 유지된다. `disabled`(그룹·옵션)가 함께 오면 disabled 가 우선한다.
23
+ */
24
+ readOnly?: boolean;
19
25
  /** input name 속성 */
20
26
  name?: string;
21
27
  /**
@@ -30,6 +36,6 @@ export interface SRadioButtonProps {
30
36
  }
31
37
  /**
32
38
  * SRadioButton — sd-radio-button 포팅. 세그먼트형 라디오(버튼 그룹).
33
- * default(흰 배경/회색, hover 파란 채움) · select(흰 배경/파란 테두리·글자) · disabled.
39
+ * default(흰 배경/회색, hover 파란 채움) · select(흰 배경/파란 테두리·글자) · disabled · readOnly.
34
40
  */
35
- export declare function SRadioButton({ options, value, size, disabled, name, showTooltip, onValueChange, className, style, }: SRadioButtonProps): import("react").JSX.Element;
41
+ export declare function SRadioButton({ options, value, size, disabled, readOnly, name, showTooltip, onValueChange, className, style, }: SRadioButtonProps): import("react").JSX.Element;
@@ -9,10 +9,10 @@
9
9
  | Prop | Type | Default | Description |
10
10
  |------|------|---------|-------------|
11
11
  | `type?` | `SSkeletonType` | `'rect'` | 자리표시 모양 - `rect`: 사각형. 폭은 부모를, 높이는 한 줄 높이를 따른다 — 이미지·카드 영역은 `height` 를 준다 - `circle`: 원형(아바타 등) - `text`: 텍스트 한 줄. 부모 타이포의 line-height 를 따르고 세로로 절반만 칠한다 - `button`·`input`·`tag`·`checkbox`·`radio`·`switch`: 해당 컴포넌트 기본 size 의 크기·모서리 |
12
+ | `mode?` | `SSkeletonMode` | `'light'` | 놓이는 바탕의 밝기 - `light`: 흰 면·회색 면 위. 바탕보다 짙은 반투명 회색 - `dark`: 어두운 면 위. 바탕보다 밝은 반투명 회색 |
12
13
  | `animation?` | `SSkeletonAnimation` | `'wave'` | 로딩 애니메이션 - `wave`: 하이라이트 띠가 왼쪽에서 오른쪽으로 지나간다 - `pulse`: 크기가 숨쉬듯 줄었다 커진다. 블록 전체가 움직이므로 아바타처럼 작은 모양에만 쓴다 - `fade`: 투명도가 숨쉬듯 바뀐다 - `none`: 애니메이션 없음 OS 의 동작 줄이기 설정이 켜져 있으면 어떤 값이든 멈춘다. |
13
14
  | `animationSpeed?` | `number` | `1500` | 애니메이션 한 주기 (ms) |
14
15
  | `square?` | `boolean` | `false` | 모서리를 각지게 |
15
- | `bordered?` | `boolean` | `false` | 테두리 |
16
16
  | `size?` | `string \| number` | — | 가로·세로를 한 번에 지정. `width`·`height` 가 있으면 그쪽이 우선한다. 숫자는 px |
17
17
  | `width?` | `string \| number` | — | 폭. 숫자는 px |
18
18
  | `height?` | `string \| number` | — | 높이. 숫자는 px |
@@ -25,6 +25,12 @@
25
25
  export type SSkeletonType = (typeof SKELETON_TYPES)[number];
26
26
  ```
27
27
 
28
+ ### SSkeletonMode
29
+
30
+ ```ts
31
+ export type SSkeletonMode = (typeof SKELETON_MODES)[number];
32
+ ```
33
+
28
34
  ### SSkeletonAnimation
29
35
 
30
36
  ```ts
@@ -47,6 +53,12 @@ export const SKELETON_TYPES = [
47
53
  ] as const;
48
54
  ```
49
55
 
56
+ ### SKELETON_MODES
57
+
58
+ ```ts
59
+ export const SKELETON_MODES = ['light', 'dark'] as const;
60
+ ```
61
+
50
62
  ### SKELETON_ANIMATIONS
51
63
 
52
64
  ```ts
@@ -1,5 +1,5 @@
1
1
  import { type HTMLAttributes } from 'react';
2
- import { type SSkeletonAnimation, type SSkeletonType } from './skeleton.config';
2
+ import { type SSkeletonAnimation, type SSkeletonMode, type SSkeletonType } from './skeleton.config';
3
3
  export interface SSkeletonProps extends HTMLAttributes<HTMLDivElement> {
4
4
  /**
5
5
  * 자리표시 모양
@@ -9,6 +9,12 @@ export interface SSkeletonProps extends HTMLAttributes<HTMLDivElement> {
9
9
  * - `button`·`input`·`tag`·`checkbox`·`radio`·`switch`: 해당 컴포넌트 기본 size 의 크기·모서리
10
10
  */
11
11
  type?: SSkeletonType;
12
+ /**
13
+ * 놓이는 바탕의 밝기
14
+ * - `light`: 흰 면·회색 면 위. 바탕보다 짙은 반투명 회색
15
+ * - `dark`: 어두운 면 위. 바탕보다 밝은 반투명 회색
16
+ */
17
+ mode?: SSkeletonMode;
12
18
  /**
13
19
  * 로딩 애니메이션
14
20
  * - `wave`: 하이라이트 띠가 왼쪽에서 오른쪽으로 지나간다
@@ -23,8 +29,6 @@ export interface SSkeletonProps extends HTMLAttributes<HTMLDivElement> {
23
29
  animationSpeed?: number;
24
30
  /** 모서리를 각지게 */
25
31
  square?: boolean;
26
- /** 테두리 */
27
- bordered?: boolean;
28
32
  /** 가로·세로를 한 번에 지정. `width`·`height` 가 있으면 그쪽이 우선한다. 숫자는 px */
29
33
  size?: string | number;
30
34
  /** 폭. 숫자는 px */
@@ -1,2 +1,2 @@
1
1
  export { SSkeleton, type SSkeletonProps } from './SSkeleton';
2
- export { SKELETON_TYPES, SKELETON_ANIMATIONS, SKELETON_TYPE_CONFIG, type SSkeletonType, type SSkeletonAnimation, } from './skeleton.config';
2
+ export { SKELETON_TYPES, SKELETON_ANIMATIONS, SKELETON_MODES, SKELETON_TYPE_CONFIG, type SSkeletonType, type SSkeletonAnimation, type SSkeletonMode, } from './skeleton.config';
@@ -2,6 +2,8 @@ export declare const SKELETON_TYPES: readonly ["rect", "circle", "text", "button
2
2
  export type SSkeletonType = (typeof SKELETON_TYPES)[number];
3
3
  export declare const SKELETON_ANIMATIONS: readonly ["wave", "pulse", "fade", "none"];
4
4
  export type SSkeletonAnimation = (typeof SKELETON_ANIMATIONS)[number];
5
+ export declare const SKELETON_MODES: readonly ["light", "dark"];
6
+ export type SSkeletonMode = (typeof SKELETON_MODES)[number];
5
7
  /**
6
8
  * type 별 기본 크기·모서리. 값이 없는 축은 내용(공백 한 글자)과 부모 폭을 따른다.
7
9
  * DS 모양(button·input…)은 해당 컴포넌트의 **기본 size** 토큰을 그대로 가리켜
@@ -12,11 +14,11 @@ export declare const SKELETON_TYPE_CONFIG: Record<SSkeletonType, {
12
14
  height?: string;
13
15
  radius: string;
14
16
  }>;
15
- export declare const SKELETON_COLORS: {
16
- /** Quasar rgba(0,0,0,.12) ≈ 흰 바탕 위 #E1E1E1 */
17
+ /**
18
+ * mode 별 색. 배경색을 반투명(`cmp-skeleton-opacity`)으로 깔아 흰 면·회색 면 어디서든 바탕보다 한 단계 짙게(dark 는 밝게) 보인다.
19
+ * 밝은 면(light)에는 어두운 색(`bg-dark`)을, 어두운 면(dark)에는 밝은 색(`bg-light`)을 쓴다 — Quasar 의 검정·흰색 반투명과 같은 축.
20
+ */
21
+ export declare const SKELETON_COLORS: Record<SSkeletonMode, {
17
22
  bg: string;
18
- /** Quasar rgba(0,0,0,.05) 테두리 — 배경보다 한 단계 짙게 */
19
- border: string;
20
- /** Quasar rgba(255,255,255,.5) 하이라이트 띠 */
21
23
  wave: string;
22
- };
24
+ }>;
@@ -0,0 +1,41 @@
1
+ # STimeline
2
+
3
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
4
+
5
+ ### STimeline
6
+
7
+ #### Props
8
+
9
+ | Prop | Type | Default | Description |
10
+ |------|------|---------|-------------|
11
+ | `groups` | `STimelineGroup[]` | — | 머리글로 묶은 항목 목록. 순서 그대로 그린다 |
12
+ | `emptyText?` | `ReactNode` | `'내역이 없습니다.'` | 항목이 하나도 없을 때 가운데 띄우는 안내. 불러오는 중에는 `null` 을 넘겨 빈 안내가 먼저 깜빡이지 않게 한다. |
13
+
14
+ ## Types
15
+
16
+ ### STimelineGroup
17
+
18
+ ```ts
19
+ export interface STimelineGroup {
20
+ /** React key. 생략하면 순서로 대신한다 */
21
+ key?: Key;
22
+ /** 묶음 머리글 (예: 날짜) */
23
+ heading: ReactNode;
24
+ /** 머리글 아래 항목. 비어 있으면 머리글째 그리지 않는다 */
25
+ entries: STimelineEntry[];
26
+ }
27
+ ```
28
+
29
+ ### STimelineEntry
30
+
31
+ ```ts
32
+ export interface STimelineEntry {
33
+ /** React key — 묶음 안에서 유일해야 한다 */
34
+ key: Key;
35
+ /** 레일 왼쪽 열에 오른쪽 정렬로 서는 시각 (예: `14:32`) */
36
+ time?: ReactNode;
37
+ /** 레일 오른쪽 본문. 타이포·색은 감싸는 쪽을 따른다 — 업무 내용은 소비 앱이 그린다 */
38
+ content: ReactNode;
39
+ }
40
+ ```
41
+
@@ -0,0 +1,27 @@
1
+ import { type HTMLAttributes, type Key, type ReactNode } from 'react';
2
+ export interface STimelineEntry {
3
+ /** React key — 묶음 안에서 유일해야 한다 */
4
+ key: Key;
5
+ /** 레일 왼쪽 열에 오른쪽 정렬로 서는 시각 (예: `14:32`) */
6
+ time?: ReactNode;
7
+ /** 레일 오른쪽 본문. 타이포·색은 감싸는 쪽을 따른다 — 업무 내용은 소비 앱이 그린다 */
8
+ content: ReactNode;
9
+ }
10
+ export interface STimelineGroup {
11
+ /** React key. 생략하면 순서로 대신한다 */
12
+ key?: Key;
13
+ /** 묶음 머리글 (예: 날짜) */
14
+ heading: ReactNode;
15
+ /** 머리글 아래 항목. 비어 있으면 머리글째 그리지 않는다 */
16
+ entries: STimelineEntry[];
17
+ }
18
+ export interface STimelineProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
19
+ /** 머리글로 묶은 항목 목록. 순서 그대로 그린다 */
20
+ groups: STimelineGroup[];
21
+ /**
22
+ * 항목이 하나도 없을 때 가운데 띄우는 안내.
23
+ * 불러오는 중에는 `null` 을 넘겨 빈 안내가 먼저 깜빡이지 않게 한다.
24
+ */
25
+ emptyText?: ReactNode;
26
+ }
27
+ export declare const STimeline: import("react").ForwardRefExoticComponent<STimelineProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ export { STimeline, type STimelineEntry, type STimelineGroup, type STimelineProps, } from './STimeline';