sellmate-design-system-react 4.1.0 → 4.3.0
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 +41 -6
- package/README.md +19 -3
- package/dist/components/SButton/README.md +2 -0
- package/dist/components/SDrawer/README.md +42 -0
- package/dist/components/SDrawer/SDrawer.d.ts +39 -0
- package/dist/components/SDrawer/index.d.ts +1 -0
- package/dist/components/SGhostButton/README.md +2 -0
- package/dist/components/SGnb/README.md +2 -1
- package/dist/components/SGnb/SGnb.d.ts +7 -1
- package/dist/components/SGnb/gnb.config.d.ts +23 -0
- package/dist/components/SGnb/index.d.ts +1 -1
- package/dist/index.cjs +254 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +253 -98
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +83 -7
- package/dist/llms.txt +43 -8
- package/dist/styles.css +97 -9
- package/dist/theme.css +7 -0
- package/eslint/rules/no-off-scale-spacing.mjs +114 -35
- package/package.json +3 -1
package/dist/llms-full.txt
CHANGED
|
@@ -158,15 +158,16 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
|
|
|
158
158
|
|
|
159
159
|
### 2-2. 간격 (spacing)
|
|
160
160
|
|
|
161
|
-
- **간격 유틸리티는 `sd-` 접두를 붙인다** — `gap-sd-8`, `p-sd-
|
|
161
|
+
- **간격 유틸리티는 `sd-` 접두를 붙인다** — `gap-sd-8`, `p-sd-16`, `mt-sd-12`. 숫자 = px 다.
|
|
162
162
|
접두를 빼면 Tailwind 기본 스케일이 적용된다(`gap-8` = 32px). 접두는 속성 뒤, 숫자 앞에 온다.
|
|
163
163
|
- 스케일: `2 4 6 8 10 12 16 19 20 22 24 28 32 36 40 44 48 56 60 62 80`
|
|
164
|
+
- **스케일에 없는 간격이 필요하면 임의 값(`p-[64px]`)으로 우회하지 않는다.** 가까운 스케일 값으로 맞추거나, 디자인상 그 값이어야 하면 **토큰 추가를 요청한다.** 이미 있는 토큰을 정확히 써야 할 때만 `gap-[var(--토큰명)]` 으로 참조한다.
|
|
164
165
|
- 형제 요소 간격은 margin 대신 부모의 `flex`/`grid` + `gap-sd-*`으로 잡는다.
|
|
165
166
|
- 시맨틱 간격 토큰 (텍스트 덩어리·요소 사이 기본 리듬):
|
|
166
167
|
|
|
167
168
|
| 상황 | 값 |
|
|
168
169
|
| --- | --- |
|
|
169
|
-
| **페이지 콘텐츠 패딩** |
|
|
170
|
+
| **페이지 콘텐츠 패딩** | **16px — `SPage` 가 `--cmp-pageBody-padding` 으로 이미 넣는다.** 직접 주지 않는다 (덮어쓰면 토큰이 바뀌어도 안 따라간다). `SPage` 밖에서 같은 패딩이 필요하면 `p-sd-16` |
|
|
170
171
|
| **섹션 ↔ 섹션** | **`gap-sd-12`** |
|
|
171
172
|
| **페이지 내 블록 ↔ 블록** (헤더·필터·툴바·테이블 사이) | **`gap-sd-12`** |
|
|
172
173
|
| 요소 ↔ 요소 | **기본 `gap-sd-8`** (`--sys-space-stack-gap-element-normal`) · 타이트 `gap-sd-4`(`-tight`) · 여유 `gap-sd-12`(`-relaxed`) / `gap-sd-16`(`-wide`) |
|
|
@@ -346,7 +347,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
|
|
|
346
347
|
- 작은 창이 아니라 **화면 하나가 통째로** 들어간다 — 검색 필터·테이블·페이지네이션이 그대로 있는 목록(`엑셀 파일 관리`), 헤더 카드·탭이 있는 상세(`이동 오더 상세`).
|
|
347
348
|
- 상세를 팝업으로 여는 이유는 **목록을 떠나지 않고 여러 건을 번갈아 보기** 위해서다. 단 상세가 **항상** 팝업인 것은 아니고, 데이터 양이 많을 때 팝업을 쓴다.
|
|
348
349
|
- 구조는 헤더(제목 중앙) + 본문 + 푸터다. **확정할 작업이 있으면 푸터에 `저장`, 조회만이면 `useFooter={false}`** 로 푸터를 없앤다.
|
|
349
|
-
- 본문에는 패딩이 없다 — 콘텐츠가 여백을 담당한다. 팝업 안도 일반 페이지와 같은 규칙(§4)을 따른다: 패딩 `p-sd-
|
|
350
|
+
- 본문에는 패딩이 없다 — 콘텐츠가 여백을 담당한다. 팝업 안도 일반 페이지와 같은 규칙(§4)을 따른다: 패딩 `p-sd-16`(`SPage` 가 아니라 직접 준다), 블록 간격 `gap-sd-12`, 표는 `SKeyValueTable` / `STable`.
|
|
350
351
|
|
|
351
352
|
```tsx
|
|
352
353
|
// 1) 목록에서 별도 창을 연다 — 창 크기 = 콘텐츠 크기
|
|
@@ -362,7 +363,7 @@ function openDetailPopup(orderId: string) {
|
|
|
362
363
|
export default function TransferOrderPopupPage() {
|
|
363
364
|
return (
|
|
364
365
|
<SPopup popupTitle="이동 오더 상세" useFooter={false}>
|
|
365
|
-
<div className="flex flex-col gap-sd-12 p-sd-
|
|
366
|
+
<div className="flex flex-col gap-sd-12 p-sd-16">
|
|
366
367
|
<SSectionHeaderCard>…</SSectionHeaderCard>
|
|
367
368
|
<STabs value={tab} tabs={TABS} onValueChange={setTab} />
|
|
368
369
|
<STable columns={columns} rows={rows} rowKey="id" />
|
|
@@ -498,6 +499,8 @@ const columns: STableColumn[] = [
|
|
|
498
499
|
| 테이블 **행 내부** 인라인 액션 | `xs` |
|
|
499
500
|
| 화면·목록 액션 (툴바, `STableBar`) | `sm` |
|
|
500
501
|
| **모달·위저드 푸터** | `md` |
|
|
502
|
+
| **페이지 하단 실행 버튼** (폼 저장·상세 수정 등) | `md` |
|
|
503
|
+
| 스크롤 시 헤더로 승격된 버튼 | `sm` (최대) |
|
|
501
504
|
|
|
502
505
|
`lg` 는 현재 사용처가 없다. 페이지 골격에서 쓰지 않는다.
|
|
503
506
|
|
|
@@ -618,12 +621,42 @@ export default function AppShell({ children }: { children: React.ReactNode }) {
|
|
|
618
621
|
<SLayout type="box" header="fix">
|
|
619
622
|
{/* type/header/folded 는 SLayout 에만 준다 — SGnb 는 context 에서 읽는다 */}
|
|
620
623
|
<SGnb items={MENU} value={current} onValueChange={navigate} logo={<Logo />} />
|
|
621
|
-
|
|
624
|
+
{/* 콘텐츠 패딩(16px)은 SPage 가 토큰으로 넣는다 — p-sd-* 로 덮어쓰지 않는다 */}
|
|
625
|
+
<SPage background="frame">{children}</SPage>
|
|
622
626
|
</SLayout>
|
|
623
627
|
);
|
|
624
628
|
}
|
|
625
629
|
```
|
|
626
630
|
|
|
631
|
+
**상단바 배치는 `header` 가 정한다.** 요소 순서가 달라지므로 슬롯을 채우기 전에 어느 쪽인지부터 정한다.
|
|
632
|
+
|
|
633
|
+
| `header` | 상단바 배치 | 로고 폭 | `topContent` |
|
|
634
|
+
| --- | --- | --- | --- |
|
|
635
|
+
| `"fix"` (기본) | `[런처 · 로고 … 폴드]` — 상단바가 GNB 컬럼 안에 있고 폴드가 컬럼 오른쪽 끝 | 내용 폭 | **렌더되지 않는다** (놓을 자리가 없다) |
|
|
636
|
+
| `"full"` | `[런처 · 폴드 · 로고 · topContent]` — 상단바가 화면 전폭 | **140px 고정** (런처 없으면 172px) | 로고 오른쪽 남는 폭 전체 |
|
|
637
|
+
|
|
638
|
+
- `topContent` 는 상단바 로고 오른쪽 슬롯이다. 전역 검색·계정 메뉴·알림처럼 **모든 페이지에 공통인 것만** 넣는다. 페이지별 액션은 여기가 아니라 §4-2 의 `STableBar` 로 간다.
|
|
639
|
+
- 슬롯이 남는 폭을 통째로 받으므로 **정렬은 안에서 직접 잡는다** (좌측 정렬 + 우측은 `ml-auto`).
|
|
640
|
+
- `header="full"` 에서 로고 자리는 140px 로 고정된다 — 로고 내용이 바뀌어도 `topContent` 시작점이 흔들리지 않게 하기 위함이다. 로고가 그보다 넓으면 잘리므로 이 폭에 맞춰 준비한다.
|
|
641
|
+
- `onLauncherClick` 을 주지 않으면 런처가 렌더되지 않고, 그 자리(버튼 + 간격)를 로고 슬롯이 이어받아 172px 가 된다. `topContent` 시작점은 런처 유무와 관계없이 같은 자리다.
|
|
642
|
+
|
|
643
|
+
```tsx
|
|
644
|
+
<SLayout type="box" header="full">
|
|
645
|
+
<SGnb
|
|
646
|
+
items={MENU} value={current} onValueChange={navigate}
|
|
647
|
+
logo={<Logo />}
|
|
648
|
+
topContent={
|
|
649
|
+
/* 남는 폭 전체를 받는다 — 왼쪽은 그대로, 오른쪽 끝은 ml-auto */
|
|
650
|
+
<div className="flex w-full items-center gap-sd-8">
|
|
651
|
+
<SInput value={keyword} onValueChange={setKeyword} placeholder="통합 검색" />
|
|
652
|
+
<SButton size="sm" color="neutral" outline label="내 계정" className="ml-auto" onClick={openAccount} />
|
|
653
|
+
</div>
|
|
654
|
+
}
|
|
655
|
+
/>
|
|
656
|
+
<SPage background="frame">{children}</SPage>
|
|
657
|
+
</SLayout>
|
|
658
|
+
```
|
|
659
|
+
|
|
627
660
|
### 4-2. 목록 페이지 (필터 + 테이블)
|
|
628
661
|
|
|
629
662
|
구조: **페이지 헤더(제목 + 가이드 링크) → 필터(`SKeyValueTable`) → `STableBar` → `STable`**
|
|
@@ -882,7 +915,7 @@ export default function ProductDetailPage() {
|
|
|
882
915
|
- [ ] 간격이 전부 `sd-` 접두 스케일 값인가 (`gap-13`·`gap-sd-13` ❌ → `gap-sd-12` ✅)
|
|
883
916
|
- [ ] 본문이 12px(`typo-body-sm-default`)인가 (14px 본문 ❌)
|
|
884
917
|
- [ ] 텍스트 회색 위계를 순차 적용했는가 (기본 → `text-fg-secondary` → `text-fg-tertiary`, 단계 건너뛰기 ❌)
|
|
885
|
-
- [ ]
|
|
918
|
+
- [ ] `SPage` 의 기본 패딩(16px)을 `p-sd-*` 로 덮어쓰지 않았는가, 블록·섹션 간격이 `gap-sd-12` 인가 (`gap-sd-16`/`gap-sd-24` ❌)
|
|
886
919
|
- [ ] 같은 컴포넌트를 나열할 때 §2-2 그룹 간격을 썼는가 (체크박스 가로 `gap-sd-24` 등)
|
|
887
920
|
- [ ] 페이지가 §4의 표준 골격에서 시작했는가
|
|
888
921
|
- [ ] 필터·폼·상세 정보를 `SKeyValueTable` 로 만들었는가 (컨트롤을 `div` 로 나열하지 않았는가)
|
|
@@ -926,6 +959,8 @@ export default function ProductDetailPage() {
|
|
|
926
959
|
|
|
927
960
|
`gap-sd-13` 처럼 스케일 밖 값은 Tailwind v4 에서 **에러 없이 조용히 무시된다**. 반대로 접두를 빠뜨린 `gap-8` 은 Tailwind 기본 스케일이라 **32px 이 적용된다**. 둘 다 "간격이 왜 이러지" 로만 보이므로 반드시 `sd-` 접두 스케일 값을 쓴다. (린트는 기본값에서 앞쪽만 잡는다 — 뒤쪽까지 강제하려면 `requirePrefix: true`)
|
|
928
961
|
|
|
962
|
+
접두 누락은 **자동 수정되지 않는다.** `p-16` 은 지금 64px 로 동작하는 코드라 `p-sd-16`(16px)으로 바꾸면 여백이 달라지기 때문이다. 린트는 "숫자를 px 로 의도했나(`p-sd-16`)" 와 "현재 값을 유지할 건가(스케일에 있으면 그 값)" 를 제안으로 내놓으니 **의도에 맞는 쪽을 골라 적용한다.**
|
|
963
|
+
|
|
929
964
|
린트가 잡지 못하는 것(§3 컴포넌트 선택, §4 페이지 골격, 버튼 배치)은 §5 체크리스트로 직접 확인한다.
|
|
930
965
|
|
|
931
966
|
|
|
@@ -1240,6 +1275,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
|
|
|
1240
1275
|
|
|
1241
1276
|
- [SActionModal](../SActionModal)
|
|
1242
1277
|
- [SConfirmModal](../SConfirmModal)
|
|
1278
|
+
- [SDrawer](../SDrawer)
|
|
1243
1279
|
- [SDropdownButton](../SDropdownButton)
|
|
1244
1280
|
- [SKeyValueTable](../SKeyValueTable)
|
|
1245
1281
|
- [SLoadingModal](../SLoadingModal)
|
|
@@ -1814,6 +1850,44 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
|
|
|
1814
1850
|
|
|
1815
1851
|
---
|
|
1816
1852
|
|
|
1853
|
+
# SDrawer
|
|
1854
|
+
|
|
1855
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
1856
|
+
|
|
1857
|
+
### SDrawer
|
|
1858
|
+
|
|
1859
|
+
#### Props
|
|
1860
|
+
|
|
1861
|
+
| Prop | Type | Default | Description |
|
|
1862
|
+
|------|------|---------|-------------|
|
|
1863
|
+
| `open?` | `boolean` | — | 표시 여부 |
|
|
1864
|
+
| `persistent?` | `boolean` | `false` | true면 backdrop·ESC로 닫히지 않고 흔들림 효과를 준다. |
|
|
1865
|
+
| `title?` | `string` | `''` | 접근성 제목 및 헤더 제목 |
|
|
1866
|
+
| `width?` | `number \| string` | `572` | Drawer 너비. 기본값은 Figma drawer 기준 572px이다. |
|
|
1867
|
+
| `footerLeft?` | `ReactNode` | — | footer 좌측 슬롯 |
|
|
1868
|
+
| `button?` | `SDrawerButton` | — | 우측 기본 액션 버튼 |
|
|
1869
|
+
| `children?` | `ReactNode` | — | |
|
|
1870
|
+
| `className?` | `string` | — | |
|
|
1871
|
+
| `style?` | `CSSProperties` | — | |
|
|
1872
|
+
|
|
1873
|
+
#### Events
|
|
1874
|
+
|
|
1875
|
+
| Event | Type | Description |
|
|
1876
|
+
|-------|------|-------------|
|
|
1877
|
+
| `onOpenChange` | `(open: boolean) => void` | 표시 상태 변경 |
|
|
1878
|
+
| `onClose` | `() => void` | 닫기(X) 버튼 클릭 |
|
|
1879
|
+
|
|
1880
|
+
## Dependencies
|
|
1881
|
+
|
|
1882
|
+
### Depends on
|
|
1883
|
+
|
|
1884
|
+
- [SButton](../SButton)
|
|
1885
|
+
- [SGhostButton](../SGhostButton)
|
|
1886
|
+
|
|
1887
|
+
### Graph
|
|
1888
|
+
|
|
1889
|
+
---
|
|
1890
|
+
|
|
1817
1891
|
# SDropdownButton
|
|
1818
1892
|
|
|
1819
1893
|
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
@@ -2129,6 +2203,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
|
|
|
2129
2203
|
- [SCalendar](../SCalendar)
|
|
2130
2204
|
- [SChip](../SChip)
|
|
2131
2205
|
- [SDateRangePicker](../SDateRangePicker)
|
|
2206
|
+
- [SDrawer](../SDrawer)
|
|
2132
2207
|
- [SFilePicker](../SFilePicker)
|
|
2133
2208
|
- [SGnb](../SGnb)
|
|
2134
2209
|
- [SGuide](../SGuide)
|
|
@@ -2168,7 +2243,8 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
|
|
|
2168
2243
|
| `useRail?` | `boolean` | — | 좌측 레일 사용 여부. 켜면 items 의 첫 depth 가 아이콘+라벨 버튼의 세로 레일로 서고, 선택된 레일 아이템의 children 이 오른쪽 메뉴 패널에 깔린다. 미지정 시 SLayout 의 useRail 을 따른다. children 없는 레일 아이템이 활성이면 메뉴 패널은 렌더되지 않고 레일만 남는다. |
|
|
2169
2244
|
| `value?` | `string` | `''` | 현재 선택된 아이템 value |
|
|
2170
2245
|
| `folded?` | `boolean` | — | 접힘(레일) 상태. 미지정 시 SLayout 의 folded 를 따른다. |
|
|
2171
|
-
| `logo?` | `ReactNode` | — | 상단바 로고 영역 (slot) |
|
|
2246
|
+
| `logo?` | `ReactNode` | — | 상단바 로고 영역 (slot). header="full" 이면 폭이 140px 로 고정된다. |
|
|
2247
|
+
| `topContent?` | `ReactNode` | — | 상단바 로고 오른쪽 슬롯 (검색·액션 등). 로고와 16px 띄고 남는 폭을 모두 차지하므로 안에서 자유롭게 정렬한다. 상단바가 전폭인 header="full" 에서만 렌더된다 (fix 는 상단바가 좁은 GNB 컬럼 안이라 놓을 자리가 없다). |
|
|
2172
2248
|
| `railFooter?` | `ReactNode` | — | 레일 하단 고정 슬롯. 레일 아이템이 많아 넘치면 아이템 목록(ul)만 스크롤되고 이 슬롯은 레일 하단에 붙어 고정된다. useRail 일 때만 렌더된다. |
|
|
2173
2249
|
| `menuFooter?` | `ReactNode` | — | 메뉴 하단 고정 슬롯. 메뉴 아이템이 많아 넘치면 메뉴 목록(ul)만 스크롤되고 이 슬롯은 메뉴 하단에 붙어 고정된다. 메뉴가 렌더될 때만(showMenu) 나타난다. |
|
|
2174
2250
|
| `foldedFooter?` | `ReactNode` | — | 접힘(fix 레일) 하단 고정 슬롯. 접으면 본문이 빠져나가며 rail/menu footer 도 사라지므로, 48px 폴드 레일 바닥에 붙는 별도 슬롯이다. header="fix" 로 접혔을 때만 나타난다. |
|
package/dist/llms.txt
CHANGED
|
@@ -159,15 +159,16 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
|
|
|
159
159
|
|
|
160
160
|
### 2-2. 간격 (spacing)
|
|
161
161
|
|
|
162
|
-
- **간격 유틸리티는 `sd-` 접두를 붙인다** — `gap-sd-8`, `p-sd-
|
|
162
|
+
- **간격 유틸리티는 `sd-` 접두를 붙인다** — `gap-sd-8`, `p-sd-16`, `mt-sd-12`. 숫자 = px 다.
|
|
163
163
|
접두를 빼면 Tailwind 기본 스케일이 적용된다(`gap-8` = 32px). 접두는 속성 뒤, 숫자 앞에 온다.
|
|
164
164
|
- 스케일: `2 4 6 8 10 12 16 19 20 22 24 28 32 36 40 44 48 56 60 62 80`
|
|
165
|
+
- **스케일에 없는 간격이 필요하면 임의 값(`p-[64px]`)으로 우회하지 않는다.** 가까운 스케일 값으로 맞추거나, 디자인상 그 값이어야 하면 **토큰 추가를 요청한다.** 이미 있는 토큰을 정확히 써야 할 때만 `gap-[var(--토큰명)]` 으로 참조한다.
|
|
165
166
|
- 형제 요소 간격은 margin 대신 부모의 `flex`/`grid` + `gap-sd-*`으로 잡는다.
|
|
166
167
|
- 시맨틱 간격 토큰 (텍스트 덩어리·요소 사이 기본 리듬):
|
|
167
168
|
|
|
168
169
|
| 상황 | 값 |
|
|
169
170
|
| --- | --- |
|
|
170
|
-
| **페이지 콘텐츠 패딩** |
|
|
171
|
+
| **페이지 콘텐츠 패딩** | **16px — `SPage` 가 `--cmp-pageBody-padding` 으로 이미 넣는다.** 직접 주지 않는다 (덮어쓰면 토큰이 바뀌어도 안 따라간다). `SPage` 밖에서 같은 패딩이 필요하면 `p-sd-16` |
|
|
171
172
|
| **섹션 ↔ 섹션** | **`gap-sd-12`** |
|
|
172
173
|
| **페이지 내 블록 ↔ 블록** (헤더·필터·툴바·테이블 사이) | **`gap-sd-12`** |
|
|
173
174
|
| 요소 ↔ 요소 | **기본 `gap-sd-8`** (`--sys-space-stack-gap-element-normal`) · 타이트 `gap-sd-4`(`-tight`) · 여유 `gap-sd-12`(`-relaxed`) / `gap-sd-16`(`-wide`) |
|
|
@@ -347,7 +348,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
|
|
|
347
348
|
- 작은 창이 아니라 **화면 하나가 통째로** 들어간다 — 검색 필터·테이블·페이지네이션이 그대로 있는 목록(`엑셀 파일 관리`), 헤더 카드·탭이 있는 상세(`이동 오더 상세`).
|
|
348
349
|
- 상세를 팝업으로 여는 이유는 **목록을 떠나지 않고 여러 건을 번갈아 보기** 위해서다. 단 상세가 **항상** 팝업인 것은 아니고, 데이터 양이 많을 때 팝업을 쓴다.
|
|
349
350
|
- 구조는 헤더(제목 중앙) + 본문 + 푸터다. **확정할 작업이 있으면 푸터에 `저장`, 조회만이면 `useFooter={false}`** 로 푸터를 없앤다.
|
|
350
|
-
- 본문에는 패딩이 없다 — 콘텐츠가 여백을 담당한다. 팝업 안도 일반 페이지와 같은 규칙(§4)을 따른다: 패딩 `p-sd-
|
|
351
|
+
- 본문에는 패딩이 없다 — 콘텐츠가 여백을 담당한다. 팝업 안도 일반 페이지와 같은 규칙(§4)을 따른다: 패딩 `p-sd-16`(`SPage` 가 아니라 직접 준다), 블록 간격 `gap-sd-12`, 표는 `SKeyValueTable` / `STable`.
|
|
351
352
|
|
|
352
353
|
```tsx
|
|
353
354
|
// 1) 목록에서 별도 창을 연다 — 창 크기 = 콘텐츠 크기
|
|
@@ -363,7 +364,7 @@ function openDetailPopup(orderId: string) {
|
|
|
363
364
|
export default function TransferOrderPopupPage() {
|
|
364
365
|
return (
|
|
365
366
|
<SPopup popupTitle="이동 오더 상세" useFooter={false}>
|
|
366
|
-
<div className="flex flex-col gap-sd-12 p-sd-
|
|
367
|
+
<div className="flex flex-col gap-sd-12 p-sd-16">
|
|
367
368
|
<SSectionHeaderCard>…</SSectionHeaderCard>
|
|
368
369
|
<STabs value={tab} tabs={TABS} onValueChange={setTab} />
|
|
369
370
|
<STable columns={columns} rows={rows} rowKey="id" />
|
|
@@ -499,6 +500,8 @@ const columns: STableColumn[] = [
|
|
|
499
500
|
| 테이블 **행 내부** 인라인 액션 | `xs` |
|
|
500
501
|
| 화면·목록 액션 (툴바, `STableBar`) | `sm` |
|
|
501
502
|
| **모달·위저드 푸터** | `md` |
|
|
503
|
+
| **페이지 하단 실행 버튼** (폼 저장·상세 수정 등) | `md` |
|
|
504
|
+
| 스크롤 시 헤더로 승격된 버튼 | `sm` (최대) |
|
|
502
505
|
|
|
503
506
|
`lg` 는 현재 사용처가 없다. 페이지 골격에서 쓰지 않는다.
|
|
504
507
|
|
|
@@ -619,12 +622,42 @@ export default function AppShell({ children }: { children: React.ReactNode }) {
|
|
|
619
622
|
<SLayout type="box" header="fix">
|
|
620
623
|
{/* type/header/folded 는 SLayout 에만 준다 — SGnb 는 context 에서 읽는다 */}
|
|
621
624
|
<SGnb items={MENU} value={current} onValueChange={navigate} logo={<Logo />} />
|
|
622
|
-
|
|
625
|
+
{/* 콘텐츠 패딩(16px)은 SPage 가 토큰으로 넣는다 — p-sd-* 로 덮어쓰지 않는다 */}
|
|
626
|
+
<SPage background="frame">{children}</SPage>
|
|
623
627
|
</SLayout>
|
|
624
628
|
);
|
|
625
629
|
}
|
|
626
630
|
```
|
|
627
631
|
|
|
632
|
+
**상단바 배치는 `header` 가 정한다.** 요소 순서가 달라지므로 슬롯을 채우기 전에 어느 쪽인지부터 정한다.
|
|
633
|
+
|
|
634
|
+
| `header` | 상단바 배치 | 로고 폭 | `topContent` |
|
|
635
|
+
| --- | --- | --- | --- |
|
|
636
|
+
| `"fix"` (기본) | `[런처 · 로고 … 폴드]` — 상단바가 GNB 컬럼 안에 있고 폴드가 컬럼 오른쪽 끝 | 내용 폭 | **렌더되지 않는다** (놓을 자리가 없다) |
|
|
637
|
+
| `"full"` | `[런처 · 폴드 · 로고 · topContent]` — 상단바가 화면 전폭 | **140px 고정** (런처 없으면 172px) | 로고 오른쪽 남는 폭 전체 |
|
|
638
|
+
|
|
639
|
+
- `topContent` 는 상단바 로고 오른쪽 슬롯이다. 전역 검색·계정 메뉴·알림처럼 **모든 페이지에 공통인 것만** 넣는다. 페이지별 액션은 여기가 아니라 §4-2 의 `STableBar` 로 간다.
|
|
640
|
+
- 슬롯이 남는 폭을 통째로 받으므로 **정렬은 안에서 직접 잡는다** (좌측 정렬 + 우측은 `ml-auto`).
|
|
641
|
+
- `header="full"` 에서 로고 자리는 140px 로 고정된다 — 로고 내용이 바뀌어도 `topContent` 시작점이 흔들리지 않게 하기 위함이다. 로고가 그보다 넓으면 잘리므로 이 폭에 맞춰 준비한다.
|
|
642
|
+
- `onLauncherClick` 을 주지 않으면 런처가 렌더되지 않고, 그 자리(버튼 + 간격)를 로고 슬롯이 이어받아 172px 가 된다. `topContent` 시작점은 런처 유무와 관계없이 같은 자리다.
|
|
643
|
+
|
|
644
|
+
```tsx
|
|
645
|
+
<SLayout type="box" header="full">
|
|
646
|
+
<SGnb
|
|
647
|
+
items={MENU} value={current} onValueChange={navigate}
|
|
648
|
+
logo={<Logo />}
|
|
649
|
+
topContent={
|
|
650
|
+
/* 남는 폭 전체를 받는다 — 왼쪽은 그대로, 오른쪽 끝은 ml-auto */
|
|
651
|
+
<div className="flex w-full items-center gap-sd-8">
|
|
652
|
+
<SInput value={keyword} onValueChange={setKeyword} placeholder="통합 검색" />
|
|
653
|
+
<SButton size="sm" color="neutral" outline label="내 계정" className="ml-auto" onClick={openAccount} />
|
|
654
|
+
</div>
|
|
655
|
+
}
|
|
656
|
+
/>
|
|
657
|
+
<SPage background="frame">{children}</SPage>
|
|
658
|
+
</SLayout>
|
|
659
|
+
```
|
|
660
|
+
|
|
628
661
|
### 4-2. 목록 페이지 (필터 + 테이블)
|
|
629
662
|
|
|
630
663
|
구조: **페이지 헤더(제목 + 가이드 링크) → 필터(`SKeyValueTable`) → `STableBar` → `STable`**
|
|
@@ -883,7 +916,7 @@ export default function ProductDetailPage() {
|
|
|
883
916
|
- [ ] 간격이 전부 `sd-` 접두 스케일 값인가 (`gap-13`·`gap-sd-13` ❌ → `gap-sd-12` ✅)
|
|
884
917
|
- [ ] 본문이 12px(`typo-body-sm-default`)인가 (14px 본문 ❌)
|
|
885
918
|
- [ ] 텍스트 회색 위계를 순차 적용했는가 (기본 → `text-fg-secondary` → `text-fg-tertiary`, 단계 건너뛰기 ❌)
|
|
886
|
-
- [ ]
|
|
919
|
+
- [ ] `SPage` 의 기본 패딩(16px)을 `p-sd-*` 로 덮어쓰지 않았는가, 블록·섹션 간격이 `gap-sd-12` 인가 (`gap-sd-16`/`gap-sd-24` ❌)
|
|
887
920
|
- [ ] 같은 컴포넌트를 나열할 때 §2-2 그룹 간격을 썼는가 (체크박스 가로 `gap-sd-24` 등)
|
|
888
921
|
- [ ] 페이지가 §4의 표준 골격에서 시작했는가
|
|
889
922
|
- [ ] 필터·폼·상세 정보를 `SKeyValueTable` 로 만들었는가 (컨트롤을 `div` 로 나열하지 않았는가)
|
|
@@ -927,6 +960,8 @@ export default function ProductDetailPage() {
|
|
|
927
960
|
|
|
928
961
|
`gap-sd-13` 처럼 스케일 밖 값은 Tailwind v4 에서 **에러 없이 조용히 무시된다**. 반대로 접두를 빠뜨린 `gap-8` 은 Tailwind 기본 스케일이라 **32px 이 적용된다**. 둘 다 "간격이 왜 이러지" 로만 보이므로 반드시 `sd-` 접두 스케일 값을 쓴다. (린트는 기본값에서 앞쪽만 잡는다 — 뒤쪽까지 강제하려면 `requirePrefix: true`)
|
|
929
962
|
|
|
963
|
+
접두 누락은 **자동 수정되지 않는다.** `p-16` 은 지금 64px 로 동작하는 코드라 `p-sd-16`(16px)으로 바꾸면 여백이 달라지기 때문이다. 린트는 "숫자를 px 로 의도했나(`p-sd-16`)" 와 "현재 값을 유지할 건가(스케일에 있으면 그 값)" 를 제안으로 내놓으니 **의도에 맞는 쪽을 골라 적용한다.**
|
|
964
|
+
|
|
930
965
|
린트가 잡지 못하는 것(§3 컴포넌트 선택, §4 페이지 골격, 버튼 배치)은 §5 체크리스트로 직접 확인한다.
|
|
931
966
|
|
|
932
967
|
|
|
@@ -1096,7 +1131,7 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
|
|
|
1096
1131
|
--sys-color-link-accent
|
|
1097
1132
|
--sys-color-navigation-gnb-bg-dark
|
|
1098
1133
|
|
|
1099
|
-
## 3. 컴포넌트 인덱스 (
|
|
1134
|
+
## 3. 컴포넌트 인덱스 (62종)
|
|
1100
1135
|
|
|
1101
1136
|
**Props 는 이 문서에 없다.** 쓸 컴포넌트를 정했으면 그 컴포넌트의 README 를 읽는다.
|
|
1102
1137
|
|
|
@@ -1105,4 +1140,4 @@ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터
|
|
|
1105
1140
|
예) SButton 을 쓴다면 `dist/components/SButton/README.md`.
|
|
1106
1141
|
prop 을 추측해서 쓰지 말고 반드시 README 로 확인한다 (분류별 용도는 §1 의 "전체 컴포넌트 인덱스" 참조).
|
|
1107
1142
|
|
|
1108
|
-
SActionModal · SBadge · SBarcodeInput · SButton · SCalendar · SCallout · SCard · SCheckbox · SChip · SChipInput · SCircleProgress · SConfirmModal · SDatePicker · SDateRangePicker · SDivider · SDraggableItem · SDraggableList · SDropdownButton · SExpansionItem · SExpansionList · SField · SFilePicker · SForm · SGhostButton · SGnb · SGuide · SIcon · SInput · SKeyValueTable · SLayout · SLinearProgress · SList · SListItem · SLoadingContainer · SLoadingModal · SModal · SNumberInput · SPage · SPagination · SPopover · SPopup · SPortal · SRadio · SRadioButton · SScrollArea · SSectionHeaderCard · SSelect · SStepper · SSwitch · STable · STableBar · STabs · STag · STextLink · STextarea · STimePicker · STimeRangePicker · SToast · SToggle · STooltip · STree
|
|
1143
|
+
SActionModal · SBadge · SBarcodeInput · SButton · SCalendar · SCallout · SCard · SCheckbox · SChip · SChipInput · SCircleProgress · SConfirmModal · SDatePicker · SDateRangePicker · SDivider · SDraggableItem · SDraggableList · SDrawer · SDropdownButton · SExpansionItem · SExpansionList · SField · SFilePicker · SForm · SGhostButton · SGnb · SGuide · SIcon · SInput · SKeyValueTable · SLayout · SLinearProgress · SList · SListItem · SLoadingContainer · SLoadingModal · SModal · SNumberInput · SPage · SPagination · SPopover · SPopup · SPortal · SRadio · SRadioButton · SScrollArea · SSectionHeaderCard · SSelect · SStepper · SSwitch · STable · STableBar · STabs · STag · STextLink · STextarea · STimePicker · STimeRangePicker · SToast · SToggle · STooltip · STree
|
package/dist/styles.css
CHANGED
|
@@ -377,6 +377,7 @@
|
|
|
377
377
|
--animate-modal-in: modal-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
378
378
|
--animate-modal-out: modal-out 0.2s ease-in;
|
|
379
379
|
--animate-modal-shake: modal-shake 0.3s ease-out;
|
|
380
|
+
--animate-drawer-shake: drawer-shake 0.22s ease-out;
|
|
380
381
|
--animate-floating-in-top: floating-in-top 0.35s ease-out;
|
|
381
382
|
--animate-floating-in-bottom: floating-in-bottom 0.35s ease-out;
|
|
382
383
|
--animate-floating-in-left: floating-in-left 0.35s ease-out;
|
|
@@ -751,6 +752,9 @@
|
|
|
751
752
|
.mt-8 {
|
|
752
753
|
margin-top: calc(var(--spacing) * 8);
|
|
753
754
|
}
|
|
755
|
+
.mt-9 {
|
|
756
|
+
margin-top: calc(var(--spacing) * 9);
|
|
757
|
+
}
|
|
754
758
|
.mt-\[8px\] {
|
|
755
759
|
margin-top: 8px;
|
|
756
760
|
}
|
|
@@ -772,6 +776,9 @@
|
|
|
772
776
|
.mt-sd-32 {
|
|
773
777
|
margin-top: var(--spacing-sd-32);
|
|
774
778
|
}
|
|
779
|
+
.mt-sd-36 {
|
|
780
|
+
margin-top: var(--spacing-sd-36);
|
|
781
|
+
}
|
|
775
782
|
.-mr-px {
|
|
776
783
|
margin-right: -1px;
|
|
777
784
|
}
|
|
@@ -1225,6 +1232,10 @@
|
|
|
1225
1232
|
--tw-translate-x: calc(1 / 2 * 100%);
|
|
1226
1233
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
1227
1234
|
}
|
|
1235
|
+
.translate-x-full {
|
|
1236
|
+
--tw-translate-x: 100%;
|
|
1237
|
+
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
1238
|
+
}
|
|
1228
1239
|
.-translate-y-1\/2 {
|
|
1229
1240
|
--tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
|
|
1230
1241
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
@@ -1247,6 +1258,9 @@
|
|
|
1247
1258
|
.animate-circle-spin {
|
|
1248
1259
|
animation: var(--animate-circle-spin);
|
|
1249
1260
|
}
|
|
1261
|
+
.animate-drawer-shake {
|
|
1262
|
+
animation: var(--animate-drawer-shake);
|
|
1263
|
+
}
|
|
1250
1264
|
.animate-linear-indeterminate {
|
|
1251
1265
|
animation: var(--animate-linear-indeterminate);
|
|
1252
1266
|
}
|
|
@@ -1532,6 +1546,9 @@
|
|
|
1532
1546
|
.gap-\[var\(--cmp-textinput-sm-gap\)\] {
|
|
1533
1547
|
gap: var(--cmp-textinput-sm-gap);
|
|
1534
1548
|
}
|
|
1549
|
+
.gap-\[var\(--토큰명\)\] {
|
|
1550
|
+
gap: var(--토큰명);
|
|
1551
|
+
}
|
|
1535
1552
|
.gap-sd-2 {
|
|
1536
1553
|
gap: var(--spacing-sd-2);
|
|
1537
1554
|
}
|
|
@@ -1824,6 +1841,9 @@
|
|
|
1824
1841
|
.\!border-\[\#93C4FF\] {
|
|
1825
1842
|
border-color: #93C4FF !important;
|
|
1826
1843
|
}
|
|
1844
|
+
.\!border-border-accentLight {
|
|
1845
|
+
border-color: var(--color-border-accentLight) !important;
|
|
1846
|
+
}
|
|
1827
1847
|
.border-\(--cmp-listDraggableItem-border-default\) {
|
|
1828
1848
|
border-color: var(--cmp-listDraggableItem-border-default);
|
|
1829
1849
|
}
|
|
@@ -1884,6 +1904,9 @@
|
|
|
1884
1904
|
.border-\[color\:var\(--cmp-datepicker-border-default\)\] {
|
|
1885
1905
|
border-color: var(--cmp-datepicker-border-default);
|
|
1886
1906
|
}
|
|
1907
|
+
.border-\[color\:var\(--cmp-drawer-body-border\)\] {
|
|
1908
|
+
border-color: var(--cmp-drawer-body-border);
|
|
1909
|
+
}
|
|
1887
1910
|
.border-\[color\:var\(--cmp-listBoxItem-depth1-border-color\)\] {
|
|
1888
1911
|
border-color: var(--cmp-listBoxItem-depth1-border-color);
|
|
1889
1912
|
}
|
|
@@ -2061,6 +2084,9 @@
|
|
|
2061
2084
|
.bg-\[var\(--cmp-datepicker-calendar-time-bg-selected\)\] {
|
|
2062
2085
|
background-color: var(--cmp-datepicker-calendar-time-bg-selected);
|
|
2063
2086
|
}
|
|
2087
|
+
.bg-\[var\(--cmp-drawer-bg\)\] {
|
|
2088
|
+
background-color: var(--cmp-drawer-bg);
|
|
2089
|
+
}
|
|
2064
2090
|
.bg-\[var\(--cmp-listBox-bg\)\] {
|
|
2065
2091
|
background-color: var(--cmp-listBox-bg);
|
|
2066
2092
|
}
|
|
@@ -2079,6 +2105,12 @@
|
|
|
2079
2105
|
.bg-\[var\(--cmp-modal-bg\)\] {
|
|
2080
2106
|
background-color: var(--cmp-modal-bg);
|
|
2081
2107
|
}
|
|
2108
|
+
.bg-\[var\(--cmp-overlay-footer-bg-default\)\] {
|
|
2109
|
+
background-color: var(--cmp-overlay-footer-bg-default);
|
|
2110
|
+
}
|
|
2111
|
+
.bg-\[var\(--cmp-overlay-header-bg\)\] {
|
|
2112
|
+
background-color: var(--cmp-overlay-header-bg);
|
|
2113
|
+
}
|
|
2082
2114
|
.bg-\[var\(--cmp-pagination-item-bg-selected\)\] {
|
|
2083
2115
|
background-color: var(--cmp-pagination-item-bg-selected);
|
|
2084
2116
|
}
|
|
@@ -2199,6 +2231,9 @@
|
|
|
2199
2231
|
.p-16 {
|
|
2200
2232
|
padding: calc(var(--spacing) * 16);
|
|
2201
2233
|
}
|
|
2234
|
+
.p-64 {
|
|
2235
|
+
padding: calc(var(--spacing) * 64);
|
|
2236
|
+
}
|
|
2202
2237
|
.p-\[2px\] {
|
|
2203
2238
|
padding: 2px;
|
|
2204
2239
|
}
|
|
@@ -2214,6 +2249,12 @@
|
|
|
2214
2249
|
.p-\[16px\] {
|
|
2215
2250
|
padding: 16px;
|
|
2216
2251
|
}
|
|
2252
|
+
.p-\[24px\] {
|
|
2253
|
+
padding: 24px;
|
|
2254
|
+
}
|
|
2255
|
+
.p-\[64px\] {
|
|
2256
|
+
padding: 64px;
|
|
2257
|
+
}
|
|
2217
2258
|
.p-\[var\(--cmp-datepicker-calendar-paddingXY\)\] {
|
|
2218
2259
|
padding: var(--cmp-datepicker-calendar-paddingXY);
|
|
2219
2260
|
}
|
|
@@ -2244,6 +2285,9 @@
|
|
|
2244
2285
|
.p-sd-32 {
|
|
2245
2286
|
padding: var(--spacing-sd-32);
|
|
2246
2287
|
}
|
|
2288
|
+
.p-sd-62 {
|
|
2289
|
+
padding: var(--spacing-sd-62);
|
|
2290
|
+
}
|
|
2247
2291
|
.px-\(--cmp-chipInput-md-paddingX\) {
|
|
2248
2292
|
padding-inline: var(--cmp-chipInput-md-paddingX);
|
|
2249
2293
|
}
|
|
@@ -2316,6 +2360,9 @@
|
|
|
2316
2360
|
.px-\[var\(--cmp-overlay-footer-paddingX\)\] {
|
|
2317
2361
|
padding-inline: var(--cmp-overlay-footer-paddingX);
|
|
2318
2362
|
}
|
|
2363
|
+
.px-\[var\(--cmp-overlay-header-paddingX\)\] {
|
|
2364
|
+
padding-inline: var(--cmp-overlay-header-paddingX);
|
|
2365
|
+
}
|
|
2319
2366
|
.px-\[var\(--cmp-pagination-paddingX\)\] {
|
|
2320
2367
|
padding-inline: var(--cmp-pagination-paddingX);
|
|
2321
2368
|
}
|
|
@@ -2988,6 +3035,10 @@
|
|
|
2988
3035
|
--tw-shadow: 5px 0 8px 0 var(--tw-shadow-color, rgba(34,34,34,0.1));
|
|
2989
3036
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
2990
3037
|
}
|
|
3038
|
+
.shadow-\[var\(--shadow-overlay\)\] {
|
|
3039
|
+
--tw-shadow: var(--shadow-overlay);
|
|
3040
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
3041
|
+
}
|
|
2991
3042
|
.shadow-none {
|
|
2992
3043
|
--tw-shadow: 0 0 #0000;
|
|
2993
3044
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -3065,6 +3116,10 @@
|
|
|
3065
3116
|
--tw-duration: 200ms;
|
|
3066
3117
|
transition-duration: 200ms;
|
|
3067
3118
|
}
|
|
3119
|
+
.duration-300 {
|
|
3120
|
+
--tw-duration: 300ms;
|
|
3121
|
+
transition-duration: 300ms;
|
|
3122
|
+
}
|
|
3068
3123
|
.duration-\[400ms\] {
|
|
3069
3124
|
--tw-duration: 400ms;
|
|
3070
3125
|
transition-duration: 400ms;
|
|
@@ -3394,13 +3449,6 @@
|
|
|
3394
3449
|
}
|
|
3395
3450
|
}
|
|
3396
3451
|
}
|
|
3397
|
-
.hover\:border-\[\#AAAAAA\] {
|
|
3398
|
-
&:hover {
|
|
3399
|
-
@media (hover: hover) {
|
|
3400
|
-
border-color: #AAAAAA;
|
|
3401
|
-
}
|
|
3402
|
-
}
|
|
3403
|
-
}
|
|
3404
3452
|
.hover\:border-\[color\:var\(--cmp-checkbox-unchecked-border-hover\)\] {
|
|
3405
3453
|
&:hover {
|
|
3406
3454
|
@media (hover: hover) {
|
|
@@ -3429,6 +3477,13 @@
|
|
|
3429
3477
|
}
|
|
3430
3478
|
}
|
|
3431
3479
|
}
|
|
3480
|
+
.hover\:border-border-strong {
|
|
3481
|
+
&:hover {
|
|
3482
|
+
@media (hover: hover) {
|
|
3483
|
+
border-color: var(--color-border-strong);
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3432
3487
|
.hover\:\!bg-\[var\(--cmp-radioButton-bg-hover\)\] {
|
|
3433
3488
|
&:hover {
|
|
3434
3489
|
@media (hover: hover) {
|
|
@@ -3716,6 +3771,12 @@
|
|
|
3716
3771
|
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
3717
3772
|
}
|
|
3718
3773
|
}
|
|
3774
|
+
.data-\[state\=closed\]\:translate-x-full {
|
|
3775
|
+
&[data-state="closed"] {
|
|
3776
|
+
--tw-translate-x: 100%;
|
|
3777
|
+
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3719
3780
|
.data-\[state\=closed\]\:animate-modal-out {
|
|
3720
3781
|
&[data-state="closed"] {
|
|
3721
3782
|
animation: var(--animate-modal-out);
|
|
@@ -3810,6 +3871,12 @@
|
|
|
3810
3871
|
}
|
|
3811
3872
|
}
|
|
3812
3873
|
}
|
|
3874
|
+
.data-\[state\=open\]\:translate-x-0 {
|
|
3875
|
+
&[data-state="open"] {
|
|
3876
|
+
--tw-translate-x: 0;
|
|
3877
|
+
translate: var(--tw-translate-x) var(--tw-translate-y);
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3813
3880
|
.data-\[state\=open\]\:animate-modal-in {
|
|
3814
3881
|
&[data-state="open"] {
|
|
3815
3882
|
animation: var(--animate-modal-in);
|
|
@@ -3873,6 +3940,16 @@
|
|
|
3873
3940
|
transition-property: none;
|
|
3874
3941
|
}
|
|
3875
3942
|
}
|
|
3943
|
+
.md\:p-4 {
|
|
3944
|
+
@media (width >= 48rem) {
|
|
3945
|
+
padding: calc(var(--spacing) * 4);
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
.md\:p-sd-16 {
|
|
3949
|
+
@media (width >= 48rem) {
|
|
3950
|
+
padding: var(--spacing-sd-16);
|
|
3951
|
+
}
|
|
3952
|
+
}
|
|
3876
3953
|
.md\:px-sd-24 {
|
|
3877
3954
|
@media (width >= 48rem) {
|
|
3878
3955
|
padding-inline: var(--spacing-sd-24);
|
|
@@ -4004,9 +4081,9 @@
|
|
|
4004
4081
|
border-left: 1px solid var(--sys-color-border-default);
|
|
4005
4082
|
}
|
|
4006
4083
|
}
|
|
4007
|
-
.\[\&\:has\(\>button\:hover\)\]\:border
|
|
4084
|
+
.\[\&\:has\(\>button\:hover\)\]\:border-border-strong {
|
|
4008
4085
|
&:has(>button:hover) {
|
|
4009
|
-
border-color:
|
|
4086
|
+
border-color: var(--color-border-strong);
|
|
4010
4087
|
}
|
|
4011
4088
|
}
|
|
4012
4089
|
.\[\&\>\*\:not\(\:last-child\)\]\:border-b {
|
|
@@ -5484,6 +5561,17 @@
|
|
|
5484
5561
|
transform: scale(1.01);
|
|
5485
5562
|
}
|
|
5486
5563
|
}
|
|
5564
|
+
@keyframes drawer-shake {
|
|
5565
|
+
0%, 100% {
|
|
5566
|
+
transform: translateX(0);
|
|
5567
|
+
}
|
|
5568
|
+
40% {
|
|
5569
|
+
transform: translateX(-3px);
|
|
5570
|
+
}
|
|
5571
|
+
70% {
|
|
5572
|
+
transform: translateX(2px);
|
|
5573
|
+
}
|
|
5574
|
+
}
|
|
5487
5575
|
@keyframes floating-in-top {
|
|
5488
5576
|
from {
|
|
5489
5577
|
opacity: 0;
|
package/dist/theme.css
CHANGED
|
@@ -1743,6 +1743,7 @@
|
|
|
1743
1743
|
--animate-modal-in: modal-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
1744
1744
|
--animate-modal-out: modal-out 0.2s ease-in;
|
|
1745
1745
|
--animate-modal-shake: modal-shake 0.3s ease-out;
|
|
1746
|
+
--animate-drawer-shake: drawer-shake 0.22s ease-out;
|
|
1746
1747
|
|
|
1747
1748
|
/* floating(툴팁·팝오버) placement 방향별 슬라이드+페이드 (sd-floating-portal 포팅) */
|
|
1748
1749
|
--animate-floating-in-top: floating-in-top 0.35s ease-out;
|
|
@@ -1783,6 +1784,12 @@
|
|
|
1783
1784
|
50% { transform: scale(0.97); }
|
|
1784
1785
|
75% { transform: scale(1.01); }
|
|
1785
1786
|
}
|
|
1787
|
+
/* persistent Drawer에서 닫기 시도 시 사용하는 낮은 진폭의 흔들림 */
|
|
1788
|
+
@keyframes drawer-shake {
|
|
1789
|
+
0%, 100% { transform: translateX(0); }
|
|
1790
|
+
40% { transform: translateX(-3px); }
|
|
1791
|
+
70% { transform: translateX(2px); }
|
|
1792
|
+
}
|
|
1786
1793
|
/* floating(툴팁·팝오버): placement 방향에서 4px 슬라이드 + 페이드 (sd-floating-slide-* 포팅) */
|
|
1787
1794
|
@keyframes floating-in-top { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
|
|
1788
1795
|
@keyframes floating-in-bottom { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
|