sellmate-design-system-react 9.0.0-beta.40 → 9.0.0-beta.41
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 -20
- package/dist/components/SBarcodeInput/README.md +3 -3
- package/dist/components/SBarcodeInput/SBarcodeInput.d.ts +3 -1
- package/dist/components/SChipInput/README.md +1 -1
- package/dist/components/SChipInput/SChipInput.d.ts +1 -1
- package/dist/components/SConfirmModal/README.md +3 -11
- package/dist/components/SConfirmModal/SConfirmModal.d.ts +16 -8
- package/dist/components/SConfirmModal/index.d.ts +1 -1
- package/dist/components/SDateRangePicker/README.md +2 -2
- package/dist/components/SDateRangePicker/SDateRangePicker.d.ts +4 -4
- package/dist/components/SEditor/EditorBody.d.ts +1 -1
- package/dist/components/SEditor/README.md +4 -4
- package/dist/components/SEditor/SEditor.d.ts +3 -3
- package/dist/components/SField/README.md +2 -2
- package/dist/components/SField/SField.d.ts +8 -2
- package/dist/components/SFilePicker/README.md +3 -3
- package/dist/components/SFilePicker/SFilePicker.d.ts +4 -4
- package/dist/components/SForm/README.md +1 -1
- package/dist/components/SForm/SForm.d.ts +2 -2
- package/dist/components/SGnb/README.md +7 -7
- package/dist/components/SGnb/SGnb.d.ts +9 -9
- package/dist/components/SGnb/gnb.config.d.ts +2 -2
- package/dist/components/SImage/README.md +1 -1
- package/dist/components/SImage/SImage.d.ts +2 -2
- package/dist/components/SInput/README.md +3 -3
- package/dist/components/SInput/SInput.d.ts +3 -3
- package/dist/components/SLayout/README.md +1 -1
- package/dist/components/SLayout/SLayout.d.ts +2 -2
- package/dist/components/SList/README.md +10 -2
- package/dist/components/SList/SList.d.ts +7 -3
- package/dist/components/SList/index.d.ts +1 -1
- package/dist/components/SLoadingModal/README.md +1 -1
- package/dist/components/SLoadingModal/SLoadingModal.d.ts +2 -2
- package/dist/components/SModal/README.md +1 -1
- package/dist/components/SNumberInput/README.md +5 -5
- package/dist/components/SNumberInput/SNumberInput.d.ts +5 -3
- package/dist/components/SPage/README.md +42 -3
- package/dist/components/SPage/SPage.d.ts +16 -1
- package/dist/components/SPage/SPageHeader.d.ts +19 -8
- package/dist/components/SPage/index.d.ts +1 -1
- package/dist/components/SPage/page-column.d.ts +11 -2
- package/dist/components/SPage/page-width.d.ts +23 -0
- package/dist/components/SPage/page.config.d.ts +18 -0
- package/dist/components/SPopup/README.md +8 -2
- package/dist/components/SPopup/SPopup.d.ts +7 -3
- package/dist/components/SPopup/index.d.ts +1 -1
- package/dist/components/SSearchInput/README.md +3 -3
- package/dist/components/SSearchInput/SSearchInput.d.ts +3 -3
- package/dist/components/SSelect/README.md +5 -5
- package/dist/components/SSelect/SSelect.d.ts +14 -6
- package/dist/components/SSplitter/README.md +2 -2
- package/dist/components/SSplitter/SSplitter.d.ts +7 -3
- package/dist/components/SSwitch/README.md +0 -1
- package/dist/components/SSwitch/SSwitch.d.ts +1 -3
- package/dist/components/STable/README.md +8 -9
- package/dist/components/STable/STable.d.ts +9 -11
- package/dist/components/STabs/README.md +1 -1
- package/dist/components/STabs/STabs.d.ts +2 -2
- package/dist/components/STextLink/README.md +1 -1
- package/dist/components/STextLink/STextLink.d.ts +1 -1
- package/dist/components/STextarea/README.md +3 -3
- package/dist/components/STextarea/STextarea.d.ts +3 -3
- package/dist/components/STimePicker/README.md +1 -1
- package/dist/components/STimePicker/STimePicker.d.ts +4 -4
- package/dist/components/STimeRangePicker/README.md +1 -1
- package/dist/components/STimeRangePicker/STimeRangePicker.d.ts +4 -4
- package/dist/components/SToast/README.md +1 -1
- package/dist/components/SToast/SToast.d.ts +2 -2
- package/dist/components/STooltip/README.md +1 -1
- package/dist/components/STooltip/STooltip.d.ts +1 -1
- package/dist/components/STree/README.md +4 -4
- package/dist/components/STree/STree.d.ts +17 -5
- package/dist/index.cjs +295 -237
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +294 -238
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +170 -106
- package/dist/llms.txt +41 -20
- package/dist/styles.css +9 -0
- package/package.json +1 -1
package/dist/llms.txt
CHANGED
|
@@ -721,8 +721,8 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
|
|
|
721
721
|
|
|
722
722
|
- 작은 창이 아니라 **화면 하나가 통째로** 들어간다 — 검색 필터·테이블·페이지네이션이 그대로 있는 목록(`엑셀 파일 관리`), 헤더 카드·탭이 있는 상세(`이동 오더 상세`).
|
|
723
723
|
- 상세를 팝업으로 여는 이유는 **목록을 떠나지 않고 여러 건을 번갈아 보기** 위해서다. 단 상세가 **항상** 팝업인 것은 아니고, 데이터 양이 많을 때 팝업을 쓴다.
|
|
724
|
-
- 구조는 헤더(제목 중앙) + 본문이고 **푸터는 기본으로 없다**. 조회만 하는 팝업은 그대로 두고, **확정할 작업이 있을 때만 `
|
|
725
|
-
- **본문 패딩은 `SPopup` 이 토큰으로 넣는다. 직접 주지 않는다** (`p-sd-*` 로 덮어쓰면 토큰이 바뀌어도 안 따라간다). 표를 가장자리까지 채우는 등 콘텐츠가 여백을 직접 다뤄야 할 때만 `
|
|
724
|
+
- 구조는 헤더(제목 중앙) + 본문이고 **푸터는 기본으로 없다**. 조회만 하는 팝업은 그대로 두고, **확정할 작업이 있을 때만 `showFooter` 로 푸터를 켜서 `submitButton` 에 `저장`** 을 둔다.
|
|
725
|
+
- **본문 패딩은 `SPopup` 이 토큰으로 넣는다. 직접 주지 않는다** (`p-sd-*` 로 덮어쓰면 토큰이 바뀌어도 안 따라간다). 표를 가장자리까지 채우는 등 콘텐츠가 여백을 직접 다뤄야 할 때만 `padding="none"` 으로 끈다.
|
|
726
726
|
- 그 밖에는 팝업 안도 일반 페이지와 같은 규칙(§4)을 따른다: 블록 간격 `gap-sd-12`, 표는 `SKeyValueTable` / `STable`.
|
|
727
727
|
|
|
728
728
|
```tsx
|
|
@@ -1304,7 +1304,7 @@ const columns: STableColumn[] = [
|
|
|
1304
1304
|
- 모델은 항상 **첫 패널**(`SSplitter.Before`) 크기다. 사이드가 기준인 화면이면 사이드를 `Before` 에 둔다.
|
|
1305
1305
|
- 앱 셸의 GNB 폭은 `SGnb` 가 소유한다. `SLayout`/`SGnb` 를 `SSplitter` 로 감싸지 않는다 — **GNB 폭을 끌 수 있게 하려면 `SGnb` 에 `resizable` 을 준다**(§4-1).
|
|
1306
1306
|
|
|
1307
|
-
**Quasar `q-splitter` 에서 옮겨올 때** — `unit` · `limits` · `
|
|
1307
|
+
**Quasar `q-splitter` 에서 옮겨올 때** — `unit` · `limits` · `updateWhileDragging` 는 이름과 뜻이 같고, 나머지는 아래처럼 바뀐다. `updateWhileDragging` 를 주지 않으면 **드래그를 놓는 순간 한 번만** `onValueChange` 가 온다.
|
|
1308
1308
|
|
|
1309
1309
|
| q-splitter | SSplitter |
|
|
1310
1310
|
| --- | --- |
|
|
@@ -1459,12 +1459,12 @@ const [from, setFrom] = useState<string | null>(null);
|
|
|
1459
1459
|
- **항목 하나의 속성을 나열하는 것은 목록이 아니다.** `라벨: 값` 이 세로로 쌓이는 것은 `SKeyValueTable` 이다 (§4-4).
|
|
1460
1460
|
- `SList` 는 레이아웃만 담당한다. depth 별 단일 펼침이 필요하면 `SExpansionList` 다 (§3-7-7).
|
|
1461
1461
|
- **`SList` 의 자식은 `SListItem` 을 권장한다.** 다른 자식도 그대로 렌더되지만, 펼치는 항목은 `SExpansionList` + `SExpansionItem` 이, 끌어서 순서를 바꾸는 항목은 `SDraggableList` + `SDraggableItem` 이 여닫힘·정렬 동작까지 함께 관리하므로 그쪽을 쓴다 (§3-7-7).
|
|
1462
|
-
- **항목 사이 구분선은 리스트가 알아서 그린다.** `SListItem`·`SExpansionItem`·`SDraggableItem` 셋 다 스스로 구분선을 그리지 않는다. `SList`·`SExpansionList`·`SDraggableList` 가 자식 **사이에** 구분선을 넣으므로 아이템에 `border-b` 를 직접 붙이지 않고, 켜는 prop 도 따로 없다. 마지막 항목 아래에는 선이 남지 않는다. 테두리형(`bordered`)은 테두리가 구분 역할을 하므로 리스트가 구분선을 빼고, `
|
|
1462
|
+
- **항목 사이 구분선은 리스트가 알아서 그린다.** `SListItem`·`SExpansionItem`·`SDraggableItem` 셋 다 스스로 구분선을 그리지 않는다. `SList`·`SExpansionList`·`SDraggableList` 가 자식 **사이에** 구분선을 넣으므로 아이템에 `border-b` 를 직접 붙이지 않고, 켜는 prop 도 따로 없다. 마지막 항목 아래에는 선이 남지 않는다. 테두리형(`bordered`)은 테두리가 구분 역할을 하므로 리스트가 구분선을 빼고, `gap` 으로 띄운다 — `gap` 을 준 목록에도 구분선은 들어가지 않는다.
|
|
1463
1463
|
- **`SListItem` 은 기본이 표시 전용이다.** 눌러서 이동·선택하게 하려면 `clickable` 을 준다 — hover·`selected`·`interaction="chevron"` 표현이 전부 여기에 딸려 있어서, `clickable` 없이 `selected` 만 주면 선택 표시가 나오지 않는다. `SExpansionList` 는 자식 아이템을 알아서 클릭 가능하게 만들어 이 함정을 막아 준다 — 선택 상태 자체는 앱이 든다 (§3-7-7).
|
|
1464
1464
|
|
|
1465
1465
|
```tsx
|
|
1466
1466
|
✅ <SList><SListItem title="일반 문의" />…</SList> {/* 줄로 구분되는 목록 — 구분선은 자동 */}
|
|
1467
|
-
✅ <SList
|
|
1467
|
+
✅ <SList gap><SListItem title="일반 문의" bordered />…</SList> {/* 카드처럼 떨어진 목록 */}
|
|
1468
1468
|
✅ <SListItem title="일반 문의" clickable selected onClick={…} /> {/* 눌러서 고르는 목록 */}
|
|
1469
1469
|
❌ <SList><SListItem title="일반 문의" className="border-b" />…</SList> {/* 구분선을 직접 붙이지 않는다 */}
|
|
1470
1470
|
❌ <SList><><SListItem title="일반 문의" /><SListItem title="결제 문의" /></></SList> {/* Fragment 로 묶으면 그 안쪽은 구분되지 않는다 */}
|
|
@@ -1610,6 +1610,7 @@ export default function AppShell({
|
|
|
1610
1610
|
header?: SPageHeaderProps;
|
|
1611
1611
|
scrollEndSpacing?: boolean;
|
|
1612
1612
|
contentHeight?: SPageContentHeight;
|
|
1613
|
+
contentWidth?: SPageContentWidth;
|
|
1613
1614
|
}) {
|
|
1614
1615
|
return (
|
|
1615
1616
|
<SLayout type="box" header="fix">
|
|
@@ -1621,7 +1622,13 @@ export default function AppShell({
|
|
|
1621
1622
|
{/* 콘텐츠 패딩은 SPage 가 토큰으로 넣는다 — p-sd-* 로 덮어쓰지 않는다 */}
|
|
1622
1623
|
{/* 높이 모드는 페이지가 정한다 — 대부분 contentHeight="fill" 이다 (§2-2) */}
|
|
1623
1624
|
{/* 스크롤 끝 여백도 SPage 가 넣는다. 페이지가 실제로 스크롤되는 화면에서만 켠다 */}
|
|
1624
|
-
|
|
1625
|
+
{/* 가로 폭 모드도 페이지가 정한다 — 넓은 창에서 본문을 늘릴지 최소 폭으로 세울지 */}
|
|
1626
|
+
<SPage
|
|
1627
|
+
background="frame"
|
|
1628
|
+
scrollEndSpacing={scrollEndSpacing}
|
|
1629
|
+
contentHeight={contentHeight}
|
|
1630
|
+
contentWidth={contentWidth}
|
|
1631
|
+
>
|
|
1625
1632
|
{children}
|
|
1626
1633
|
</SPage>
|
|
1627
1634
|
</SLayout>
|
|
@@ -1637,7 +1644,7 @@ export default function AppShell({
|
|
|
1637
1644
|
|
|
1638
1645
|
**페이지 헤더 사용 규칙 — 이 앱에서는 값이 아니라 값의 일관성이 규칙이다.**
|
|
1639
1646
|
|
|
1640
|
-
- **`
|
|
1647
|
+
- **`variant` 는 필수이고, 앱 전체에서 하나로 고정한다.** 어떤 페이지는 `"bar"`(높이 고정 + 하단 구분선), 다른 페이지는 `"plain"`(최소 높이) 로 섞어 쓰지 않는다. 프로젝트에서 하나를 고르면(예: 전부 `"bar"`) 모든 페이지 헤더가 그 값을 쓴다. **기본값이 없는 것도 이 규칙 때문이다** — 기본값이 있으면 안 준 페이지만 조용히 다른 모양이 되어 메뉴를 옮길 때마다 제목 줄이 튄다. 셸을 한 번 감싸 쓰면 지정하는 자리는 `AppShell` 한 곳이다. `SLayout` 의 `header`(`"fix" | "full"`)와는 다른 축이다 — 그쪽은 상단바가 GNB 컬럼 안에 있는지 화면 전폭인지를 정한다.
|
|
1641
1648
|
- **`slot`·`onBack` 도 페이지 성격이 실제로 다른 경우가 아니면 있는 대로 통일한다.** "목록 페이지엔 없고 상세·등록 페이지엔 있다"처럼 화면 종류에 따라 갈리는 것은 허용되지만, 같은 종류의 화면끼리는 임의로 넣었다 뺐다 하지 않는다.
|
|
1642
1649
|
- **`slot` 은 `ReactNode` 를 그대로 받지만, 원칙은 `size="sm"` 버튼 위주로만 채운다.** `STextLink`·복잡한 커스텀 마크업을 슬롯에 넣지 않는다 — 그 이상이 필요하면 페이지 헤더가 아니라 §4-2 의 `STableBar` 처럼 본문 쪽 액션 자리를 쓴다.
|
|
1643
1650
|
|
|
@@ -1650,7 +1657,7 @@ const [scrolled, setScrolled] = useState(false);
|
|
|
1650
1657
|
|
|
1651
1658
|
{/* 헤더는 자기 흰 면을 스스로 칠한다 — 감싸는 쪽은 본문이 놓일 면만 정하면 된다 */}
|
|
1652
1659
|
<div className="flex h-full min-h-0 flex-col bg-[var(--sys-color-bg-frame)]">
|
|
1653
|
-
<SPageHeader title="상품 목록" subText="판매 중인 상품을 관리합니다." scrolled={scrolled} />
|
|
1660
|
+
<SPageHeader variant="plain" title="상품 목록" subText="판매 중인 상품을 관리합니다." scrolled={scrolled} />
|
|
1654
1661
|
{/* 스크롤을 앱이 쥐므로 scrolled 도 앱이 넣는다 — 패딩은 SPage 가 없으니 여기서 준다 */}
|
|
1655
1662
|
<div
|
|
1656
1663
|
className="min-h-0 flex-1 overflow-auto p-sd-16"
|
|
@@ -1687,7 +1694,20 @@ import { SModalOutlet } from 'sellmate-design-system-react';
|
|
|
1687
1694
|
|
|
1688
1695
|
**최소 너비는 `SLayout` 이 보장한다 — 앱이 `min-w-*` 를 직접 주지 않는다.** 창이 최소 너비(`SLAYOUT_MIN_WIDTH`, GNB 포함한 전체 기준)보다 좁아지면 GNB·상단바는 제자리에 남고 **`SPage` 안에만 가로 스크롤이 생긴다.** 문서(브라우저 창)에는 가로 스크롤이 생기지 않는다. 그래서 셸을 감싸는 요소에 `min-width` 나 `overflow-x` 를 걸지 않는다 — 걸면 창 전체가 스크롤되어 GNB 가 화면 밖으로 밀린다.
|
|
1689
1696
|
|
|
1690
|
-
|
|
1697
|
+
**창이 최소 너비보다 넓을 때 본문을 어떻게 세울지는 `SPage` 의 `contentWidth` 가 정한다 — 폭을 직접 계산하지 않는다.** 넓은 모니터에서 본문이 끝까지 늘어나 성기어지는 화면이 있으므로 세 가지 중 하나를 고른다.
|
|
1698
|
+
|
|
1699
|
+
| `contentWidth` | 넓은 창에서 | 쓰는 곳 |
|
|
1700
|
+
| --- | --- | --- |
|
|
1701
|
+
| `"full"` (기본) | 남는 폭을 본문이 다 쓴다 | 표·목록처럼 가로를 넓게 쓸수록 정보가 더 들어가는 화면 |
|
|
1702
|
+
| `"fixed"` | 최소 너비일 때의 본문 폭으로 고정, 왼쪽 정렬 (남는 폭은 오른쪽) | 시안 폭 그대로 세우되 왼쪽 기준을 유지할 화면 |
|
|
1703
|
+
| `"fixedCenter"` | 같은 폭으로 고정, 가운데 정렬 (남는 폭은 좌우) | 폼·상세처럼 가로를 넓게 써도 얻을 것이 없는 화면 |
|
|
1704
|
+
|
|
1705
|
+
- **고정 폭에 숫자를 쓰지 않는다.** `max-w-*` 나 `mx-auto` 로 흉내 내면 GNB 폭·접힘이 반영되지 않아 시안과 어긋난다. 고정 폭은 "창이 최소 너비일 때의 본문 폭"이고 `SPage` 가 GNB 상태까지 반영해 계산한다.
|
|
1706
|
+
- **창이 최소 너비보다 좁아지면 세 모드가 모두 같다** — 남는 폭이 없으므로 위 문단대로 `SPage` 안에만 가로 스크롤이 생긴다.
|
|
1707
|
+
- 같은 열의 `SPageHeader` 는 자동으로 같은 폭·정렬을 따른다 — 제목 줄에 별도로 주지 않는다. 헤더의 흰 면·구분선은 늘 전폭이다.
|
|
1708
|
+
- **같은 종류의 화면끼리는 값을 통일한다** (헤더 `fix` 와 같은 이유). 목록 페이지마다 `full`·`fixedCenter` 가 섞이면 메뉴를 옮길 때마다 본문 폭이 튄다.
|
|
1709
|
+
|
|
1710
|
+
**셸의 `SPage` 는 모든 페이지가 공유하므로, 페이지마다 달라지는 것은 페이지가 셸에 알려야 한다.** 위처럼 프레임 컴포넌트가 `contentHeight` · `scrollEndSpacing` · `contentWidth` 를 받아 그대로 넘긴다.
|
|
1691
1711
|
|
|
1692
1712
|
**대부분의 페이지는 `contentHeight="fill"` 이다** — 본문이 창을 꽉 채우고 스크롤은 각 영역 안에서 일어나는 것이 표준이다(§2-2). 블록의 높이가 정해져 있고 그 높이가 창보다 커서 페이지 자체가 스크롤돼야 하는 화면에서만 `contentHeight="auto"`(기본값) + `scrollEndSpacing` 을 켠다.
|
|
1693
1713
|
|
|
@@ -1723,14 +1743,14 @@ import { SModalOutlet } from 'sellmate-design-system-react';
|
|
|
1723
1743
|
</SLayout>
|
|
1724
1744
|
```
|
|
1725
1745
|
|
|
1726
|
-
**메뉴 목록과 함께 스크롤되면 안 되는 것은 `SGnb` 의 위아래 고정 슬롯에 둔다.** 레일과 메뉴에 각각 위(`railTop`·`menuTop`)와 아래(`railFooter`·`menuFooter`) 슬롯이 있다. 아이템이 많아 넘치면 **목록만 스크롤되고 이 슬롯들은 제자리에 남는다** — 메뉴 검색, 워크스페이스 전환, 계정 행처럼 항상 보여야 하는 것이 여기 온다. 레일 슬롯은 `
|
|
1746
|
+
**메뉴 목록과 함께 스크롤되면 안 되는 것은 `SGnb` 의 위아래 고정 슬롯에 둔다.** 레일과 메뉴에 각각 위(`railTop`·`menuTop`)와 아래(`railFooter`·`menuFooter`) 슬롯이 있다. 아이템이 많아 넘치면 **목록만 스크롤되고 이 슬롯들은 제자리에 남는다** — 메뉴 검색, 워크스페이스 전환, 계정 행처럼 항상 보여야 하는 것이 여기 온다. 레일 슬롯은 `showRail` 일 때만, 메뉴 슬롯은 깔 메뉴가 있을 때만 렌더된다.
|
|
1727
1747
|
|
|
1728
1748
|
**접으면 레일·메뉴가 통째로 빠져나가면서 그 슬롯들도 함께 사라진다.** 접힌 상태에서도 남겨야 할 것은 `foldedTop`·`foldedFooter` 로 따로 준다 — `header="fix"` 로 접혔을 때만 나타나며, 폭이 좁은 폴드 레일이므로 아이콘 버튼 하나 정도로 줄인다.
|
|
1729
1749
|
|
|
1730
1750
|
```tsx
|
|
1731
1751
|
{/* 접히면 menuTop·menuFooter 가 함께 빠지므로, 폴드 레일에 남길 것만 foldedTop 으로 따로 준다 */}
|
|
1732
1752
|
<SGnb
|
|
1733
|
-
items={MENU} value={current} onValueChange={navigate}
|
|
1753
|
+
items={MENU} value={current} onValueChange={navigate} showRail
|
|
1734
1754
|
menuTop={<SSearchInput value={keyword} onValueChange={setKeyword} placeholder="메뉴 검색" />}
|
|
1735
1755
|
menuFooter={<AccountRow />}
|
|
1736
1756
|
foldedTop={<SGhostButton icon="search" size="sm" ariaLabel="메뉴 검색" onClick={openSearch} />}
|
|
@@ -1793,7 +1813,7 @@ import { SModalOutlet } from 'sellmate-design-system-react';
|
|
|
1793
1813
|
- **닫힘은 `onTooltipDismiss` 로 받아 `tooltip` 을 비워 둔다.** 같은 값을 계속 넘기는 동안에는 다시 뜨지 않고, **비웠다 다시 넘기면 문구가 같아도 새 안내로 뜬다** — 새 알림마다 같은 안내를 다시 띄우는 화면이 막히지 않는다.
|
|
1794
1814
|
- 재노출 신호는 문구가 **없음 → 있음** 으로 바뀌는 것이다. 한 이벤트 핸들러 안에서 비웠다 곧바로 넣으면 렌더가 한 번으로 묶여 신호가 되지 않는다 — 닫을 때 비우고, 다시 필요할 때 넘긴다.
|
|
1795
1815
|
- 컴포넌트가 아는 범위는 그 자리가 서 있는 동안뿐이다(새로고침하거나 GNB 를 접어 알림이 다른 자리로 옮겨 서면 새로 마운트된다). **그 사용자에게 두 번 다시 보이지 않아야 하면 앱이 닫힘을 저장해 두고 `tooltip` 을 넘기지 않는다.**
|
|
1796
|
-
- **`header="fix"` + `
|
|
1816
|
+
- **`header="fix"` + `showRail` 에서 하위 메뉴가 없는 레일 아이템이 활성이면 메뉴 컬럼째 사라지므로 이 패널도 함께 빠진다.** 항상 보여야 하는 계정·알림이라면 그런 레일 리프를 두지 않는다 — 또는 `header="full"` 로 두면 상단바에 남는다(그런 레일 리프가 있으면 GNB 가 `header` 를 `full` 로 강제한다).
|
|
1797
1817
|
|
|
1798
1818
|
### 4-2. 목록 페이지 (필터 + 테이블)
|
|
1799
1819
|
|
|
@@ -1821,7 +1841,7 @@ import {
|
|
|
1821
1841
|
const filterFields: SKeyValueField[][] = [
|
|
1822
1842
|
[
|
|
1823
1843
|
{ name: 'status', label: '상태', type: 'select',
|
|
1824
|
-
options: { options: STATUS_OPTIONS,
|
|
1844
|
+
options: { options: STATUS_OPTIONS, valueAsPrimitive: true } },
|
|
1825
1845
|
{ name: 'keyword', label: '검색어', type: 'input',
|
|
1826
1846
|
options: { placeholder: '상품명 / 상품코드' } },
|
|
1827
1847
|
],
|
|
@@ -1853,6 +1873,7 @@ export default function ProductListPage() {
|
|
|
1853
1873
|
return (
|
|
1854
1874
|
<AppShell
|
|
1855
1875
|
header={{
|
|
1876
|
+
variant: 'bar',
|
|
1856
1877
|
title: '상품 목록',
|
|
1857
1878
|
// 이 페이지의 주요 액션이 아니라 부가 액션 — slot 은 sm 버튼으로만 채운다
|
|
1858
1879
|
slot: <SButton size="sm" color="neutral" outline label="이용 가이드" onClick={openGuide} />,
|
|
@@ -1895,7 +1916,7 @@ export default function ProductListPage() {
|
|
|
1895
1916
|
selected={selected}
|
|
1896
1917
|
onSelectedChange={setSelected}
|
|
1897
1918
|
pagination={{ currentPage, lastPage }}
|
|
1898
|
-
|
|
1919
|
+
loading={loading}
|
|
1899
1920
|
/>
|
|
1900
1921
|
</div>
|
|
1901
1922
|
</AppShell>
|
|
@@ -1911,7 +1932,7 @@ export default function ProductListPage() {
|
|
|
1911
1932
|
|
|
1912
1933
|
```tsx
|
|
1913
1934
|
// 좁게 시작하고, 사용자가 바꾸는 밀도는 표가 알아서 들고 간다
|
|
1914
|
-
<STable dense
|
|
1935
|
+
<STable dense showRowsPerPageSelect pagination={{ currentPage, lastPage }} />;
|
|
1915
1936
|
|
|
1916
1937
|
// 사용자가 고른 밀도를 다음 방문에도 남기려는 화면만 받아서 저장한다.
|
|
1917
1938
|
// 저장한 값은 시작 밀도로만 돌려준다 — 되돌려 넣지 않는다
|
|
@@ -1920,7 +1941,7 @@ const [initialDense] = useState(() => loadPref('list.dense', true));
|
|
|
1920
1941
|
<STable
|
|
1921
1942
|
dense={initialDense}
|
|
1922
1943
|
onDenseChange={next => savePref('list.dense', next)}
|
|
1923
|
-
|
|
1944
|
+
showRowsPerPageSelect
|
|
1924
1945
|
pagination={{ currentPage, lastPage }}
|
|
1925
1946
|
/>;
|
|
1926
1947
|
```
|
|
@@ -1968,7 +1989,7 @@ const fields: SKeyValueField[][] = [
|
|
|
1968
1989
|
],
|
|
1969
1990
|
[
|
|
1970
1991
|
{ name: 'category', label: '카테고리', required: true, type: 'select',
|
|
1971
|
-
options: { options: CATEGORY_OPTIONS,
|
|
1992
|
+
options: { options: CATEGORY_OPTIONS, valueAsPrimitive: true,
|
|
1972
1993
|
rules: [required('카테고리를 선택해 주세요.')] } },
|
|
1973
1994
|
{ name: 'price', label: '판매가', type: 'number-input' },
|
|
1974
1995
|
],
|
|
@@ -1983,9 +2004,9 @@ export default function ProductCreatePage() {
|
|
|
1983
2004
|
const [values, setValues] = useState<Record<string, unknown>>({});
|
|
1984
2005
|
|
|
1985
2006
|
return (
|
|
1986
|
-
<AppShell header={{ title: '상품 등록', onBack: goBack }}>
|
|
2007
|
+
<AppShell header={{ variant: 'bar', title: '상품 등록', onBack: goBack }}>
|
|
1987
2008
|
<div className="flex flex-col gap-sd-12">
|
|
1988
|
-
<SForm ref={formRef}
|
|
2009
|
+
<SForm ref={formRef} formClassName="flex flex-col gap-sd-12" onSubmit={save}>
|
|
1989
2010
|
<SKeyValueTable
|
|
1990
2011
|
fields={fields}
|
|
1991
2012
|
values={values}
|
|
@@ -2046,7 +2067,7 @@ const priceFields: SKeyValueField[][] = [
|
|
|
2046
2067
|
export default function ProductDetailPage() {
|
|
2047
2068
|
return (
|
|
2048
2069
|
// 목록에서 들어온 상세 페이지 — onBack 으로 뒤로가기를 준다
|
|
2049
|
-
<AppShell header={{
|
|
2070
|
+
<AppShell header={{ variant: 'bar', title: '클래식 셔츠', onBack: goList }}>
|
|
2050
2071
|
<div className="flex flex-col gap-sd-12">
|
|
2051
2072
|
<SSectionHeaderCard title="기본 정보" marker thickness="accent">
|
|
2052
2073
|
<SKeyValueTable fields={basicFields} values={product} />
|
package/dist/styles.css
CHANGED
|
@@ -768,6 +768,9 @@
|
|
|
768
768
|
.mx-\[calc\(12px-var\(--cmp-chipFilter-chip-group\)\)\] {
|
|
769
769
|
margin-inline: calc(12px - var(--cmp-chipFilter-chip-group));
|
|
770
770
|
}
|
|
771
|
+
.mx-auto {
|
|
772
|
+
margin-inline: auto;
|
|
773
|
+
}
|
|
771
774
|
.my-\[4px\] {
|
|
772
775
|
margin-block: 4px;
|
|
773
776
|
}
|
|
@@ -1055,6 +1058,9 @@
|
|
|
1055
1058
|
.h-\[250px\] {
|
|
1056
1059
|
height: 250px;
|
|
1057
1060
|
}
|
|
1061
|
+
.h-\[260px\] {
|
|
1062
|
+
height: 260px;
|
|
1063
|
+
}
|
|
1058
1064
|
.h-\[280px\] {
|
|
1059
1065
|
height: 280px;
|
|
1060
1066
|
}
|
|
@@ -1277,6 +1283,9 @@
|
|
|
1277
1283
|
.w-\[61px\] {
|
|
1278
1284
|
width: 61px;
|
|
1279
1285
|
}
|
|
1286
|
+
.w-\[72px\] {
|
|
1287
|
+
width: 72px;
|
|
1288
|
+
}
|
|
1280
1289
|
.w-\[176px\] {
|
|
1281
1290
|
width: 176px;
|
|
1282
1291
|
}
|