sellmate-design-system-react 9.0.0-beta.21 → 9.0.0-beta.22
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 +33 -10
- package/README.md +15 -14
- package/dist/components/SDivider/README.md +1 -0
- package/dist/components/SDivider/SDivider.d.ts +11 -0
- package/dist/components/STable/README.md +2 -3
- package/dist/components/STable/STable.d.ts +12 -12
- package/dist/index.cjs +30 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +30 -25
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +36 -13
- package/dist/llms.txt +33 -10
- package/dist/styles.css +20 -3
- package/eslint/index.mjs +4 -0
- package/eslint/rules/divider-vertical-height.mjs +137 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1153,6 +1153,25 @@ const columns: STableColumn[] = [
|
|
|
1153
1153
|
|
|
1154
1154
|
`SSplitter` 의 구분선은 평소 자리만 잡고 칠해지지 않다가, 경계에 커서를 올리거나 포커스를 주면 그때 드러난다 — 조절 가능한 자리라는 신호다. **항상 보이는 선이 필요하면 `SDivider` 를 쓴다.** 선 색·두께·주변 여백은 토큰이 정하므로 직접 주지 않는다.
|
|
1155
1155
|
|
|
1156
|
+
**세로 구분선의 길이는 `height` prop 으로 준다 — `className` 의 `h-*` 로 주지 않는다.**
|
|
1157
|
+
|
|
1158
|
+
```tsx
|
|
1159
|
+
// 줄 높이를 그대로 채운다 (기본)
|
|
1160
|
+
<div className="flex items-center gap-sd-8">
|
|
1161
|
+
<span>총 주문 3건</span>
|
|
1162
|
+
<SDivider vertical />
|
|
1163
|
+
<span>총 품목 12건</span>
|
|
1164
|
+
</div>
|
|
1165
|
+
|
|
1166
|
+
// 양옆 글자보다 짧은 선이 필요할 때만 길이를 정한다
|
|
1167
|
+
<SDivider vertical height={20} />
|
|
1168
|
+
|
|
1169
|
+
// 하지 말 것 — 선이 줄 맨 위에 붙는다
|
|
1170
|
+
<SDivider vertical className="h-sd-20" />
|
|
1171
|
+
```
|
|
1172
|
+
|
|
1173
|
+
길이를 주지 않으면 `align-self: stretch` 로 부모 줄 높이를 채우는데, `stretch` 는 높이가 `auto` 일 때만 늘린다. `className` 으로 높이를 정하면 `stretch` 가 조용히 무효가 되어 선이 위로 솟는다. `height` 는 길이와 교차축 가운데 정렬을 함께 적용하므로 이 함정이 없다 — 위·아래 정렬이 필요하면 `className="self-start"` 처럼 명시한다. (`sellmate/divider-vertical-height` 규칙이 잡는다.)
|
|
1174
|
+
|
|
1156
1175
|
```tsx
|
|
1157
1176
|
<SSplitter defaultValue={30} limits={[20, 60]}>
|
|
1158
1177
|
<SSplitter.Before>내비게이션</SSplitter.Before>
|
|
@@ -1661,24 +1680,28 @@ export default function ProductListPage() {
|
|
|
1661
1680
|
|
|
1662
1681
|
행 높이를 줄이는 것은 `dense` 다. 세로 여백만 줄고 좌우 패딩은 그대로라, 값이 잘리지 않으면서 한 화면에 들어가는 행 수가 늘어난다.
|
|
1663
1682
|
|
|
1664
|
-
**어느 쪽이 편한지는 화면이 아니라 사용자가 안다.** 그래서
|
|
1683
|
+
**어느 쪽이 편한지는 화면이 아니라 사용자가 안다.** 그래서 `dense` 는 밀도를 고정하는 스위치가 아니라 **시작 밀도이자 밀도 토글의 스위치**다 — 켜면 하단 바 우측(rows per page 셀렉트 왼쪽)에 `좁게 보기` · `넓게 보기` 링크가 붙는다. 켜고 끄는 별도 prop 은 없다.
|
|
1665
1684
|
|
|
1666
1685
|
```tsx
|
|
1667
|
-
// 사용자가
|
|
1668
|
-
|
|
1686
|
+
// 좁게 시작하고, 사용자가 바꾸는 밀도는 표가 알아서 들고 간다
|
|
1687
|
+
<STable dense useRowsPerPageSelect pagination={{ currentPage, lastPage }} />;
|
|
1688
|
+
|
|
1689
|
+
// 사용자가 고른 밀도를 다음 방문에도 남기려는 화면만 받아서 저장한다.
|
|
1690
|
+
// 저장한 값은 시작 밀도로만 돌려준다 — 되돌려 넣지 않는다
|
|
1691
|
+
const [initialDense] = useState(() => loadPref('list.dense', true));
|
|
1669
1692
|
|
|
1670
1693
|
<STable
|
|
1671
|
-
dense={
|
|
1672
|
-
onDenseChange={next =>
|
|
1673
|
-
useDensityToggle
|
|
1694
|
+
dense={initialDense}
|
|
1695
|
+
onDenseChange={next => savePref('list.dense', next)}
|
|
1674
1696
|
useRowsPerPageSelect
|
|
1675
1697
|
pagination={{ currentPage, lastPage }}
|
|
1676
1698
|
/>;
|
|
1677
1699
|
```
|
|
1678
1700
|
|
|
1679
|
-
-
|
|
1680
|
-
-
|
|
1681
|
-
-
|
|
1701
|
+
- **누른 뒤의 밀도는 `STable` 이 내부 상태로 들고 간다.** `onDenseChange` 없이도 토글은 동작한다. 저장이 필요한 화면만 받아서 저장하면 된다.
|
|
1702
|
+
- **`dense` 에 `onDenseChange` 값을 되돌려 넣지 않는다.** 토글을 붙일지는 이 prop 이 정하므로, 넓게 본 순간 `dense` 가 `false` 가 되면 토글이 사라져 다시 좁힐 길이 없다. prop 값을 바꿔 넘기는 것은 외부 버튼 등으로 밀도를 **되돌릴 때**만 쓴다 — 내부 밀도가 그 값으로 맞춰진다.
|
|
1703
|
+
- **`dense` 면 페이지네이션이 없어도 토글이 나온다** — 하단 바를 토글만 담아 그린다. `dense` 가 아니면 토글도 없다.
|
|
1704
|
+
- 라벨과 아이콘은 현재 상태가 아니라 **누르면 되는 상태**를 가리킨다. 좁게 보고 있으면 `넓게 보기` 다.
|
|
1682
1705
|
|
|
1683
1706
|
### 4-3. 폼 페이지 (등록/수정)
|
|
1684
1707
|
|
|
@@ -1894,7 +1917,7 @@ export default function ProductDetailPage() {
|
|
|
1894
1917
|
- [ ] 필터·폼·상세 정보를 `SKeyValueTable` 로 만들었는가 (컨트롤을 `div` 로 나열하지 않았는가). 필터를 `SChipFilter` 로 했다면 §3-7-11 의 판정을 거쳤는가
|
|
1895
1918
|
- [ ] 섹션 구분에 `SSectionHeaderCard` 를 썼는가 (직접 만든 카드가 아니라)
|
|
1896
1919
|
- [ ] 목록의 주요 액션이 `STableBar` 의 `rightActions` 에 있는가 (페이지 제목 줄이 아니라)
|
|
1897
|
-
- [ ] 목록 페이지 표에 `
|
|
1920
|
+
- [ ] 목록 페이지 표에 `dense` 로 밀도 토글을 띄웠는가, 그 값을 `onDenseChange` 결과로 되돌려 넣지는 않았는가 (§4-2 — 되돌려 넣으면 넓게 본 순간 토글이 사라진다)
|
|
1898
1921
|
- [ ] 상태 표시에 `STag size="sm"` 을 썼는가
|
|
1899
1922
|
- [ ] 테이블에서 양을 나타내는 컬럼(금액·수량·개수 등)이 전부 `align: 'right'` 인가
|
|
1900
1923
|
- [ ] 번호·코드·전화번호·일자 컬럼에 `align: 'center'` 를 **명시**했는가 (생략하면 좌측이 된다)
|
package/README.md
CHANGED
|
@@ -178,17 +178,18 @@ export default [
|
|
|
178
178
|
|
|
179
179
|
**`error` 는 "지키지 않으면 깨지는 것" 에만 씁니다.** 앱 화면을 Tailwind 로 자유롭게 만드는 것은 정상이고, 디자인 시스템이 그 자유까지 막지 않습니다. 나머지는 권고(`warn`)입니다.
|
|
180
180
|
|
|
181
|
-
| 규칙
|
|
182
|
-
|
|
|
183
|
-
| `sellmate/no-off-scale-spacing`
|
|
184
|
-
| `sellmate/no-raw-html-control`
|
|
185
|
-
| `sellmate/
|
|
186
|
-
| `sellmate/
|
|
187
|
-
| `sellmate/
|
|
188
|
-
| `sellmate/
|
|
189
|
-
| `sellmate/
|
|
190
|
-
| `sellmate/
|
|
191
|
-
| `sellmate/
|
|
181
|
+
| 규칙 | 기본 | 검출 대상 |
|
|
182
|
+
| ---------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
183
|
+
| `sellmate/no-off-scale-spacing` | **error** | 스케일 밖 디자인 시스템 간격 (`gap-sd-13`) — Tailwind v4 에서 **조용히 무시되어** 스타일이 사라진다 |
|
|
184
|
+
| `sellmate/no-raw-html-control` | **error** | 대응 컴포넌트가 있는 생 HTML (`<button>` `<input>` `<select>` `<textarea>` `<table>` `<form>` `<dialog>` `<hr>` `<details>` `<progress>`), `alert()`/`confirm()` — 디자인 시스템을 통째로 우회하는 경우 |
|
|
185
|
+
| `sellmate/divider-vertical-height` | **error** | 세로 `SDivider` 의 높이를 `className="h-*"` 로 준 경우 — `align-self: stretch` 가 무효가 되어 선이 줄 맨 위에 붙는다. `height` prop 으로 준다(**`--fix` 로 치환**) |
|
|
186
|
+
| `sellmate/prefer-typo-preset` | warn | `text-14 font-bold` 같은 낱개 조합 → `typo-*` 프리셋 |
|
|
187
|
+
| `sellmate/component-group-gap` | warn | 같은 컴포넌트를 나열할 때의 그룹 간격 — 배열 방향에 따라 값이 다르다(체크박스 가로 24 / 세로 8) |
|
|
188
|
+
| `sellmate/table-numeric-align` | warn | 수량 컬럼(금액·수량 등)에 `align: 'right'` 누락 — **`--fix` 로 자동 교정** |
|
|
189
|
+
| `sellmate/require-locale-number` | warn | 수량 컬럼의 `toLocaleString()` 누락 — 세 자리 콤마 |
|
|
190
|
+
| `sellmate/field-width-grade` | warn | 필드 폭이 `maxLength`(스키마 상한)와 어긋남 — 등급 미지정 · 등급 밖 폭 · 상한 대비 과부족 · 등급 px 직접 지정(**`--fix` 로 등급 이름 치환**) |
|
|
191
|
+
| `sellmate/table-column-width` | warn | 컬럼 폭 미지정(기본 120px 이 조용히 들어감) · px 아닌 폭(`%` `clamp()`) · 값을 그리는 열의 `autoWidth` 오용 |
|
|
192
|
+
| `sellmate/no-arbitrary-class` | **off** | 토큰이 있는 속성(색·타이포·간격·모서리)의 임의 값 — `text-[14px]`, `bg-[#eee]`. 앱 고유 화면에는 정당한 사용이 많아 기본값은 끕니다 |
|
|
192
193
|
|
|
193
194
|
`className` 뿐 아니라 `cn()`/`clsx()` 인자, 템플릿 리터럴, 객체 키 안까지 검사합니다.
|
|
194
195
|
|
|
@@ -286,9 +287,9 @@ export default [
|
|
|
286
287
|
한글은 전각이라 영숫자의 약 두 배를 먹으므로 **두 기준 사이에는 아무것도 보고하지 않습니다** —
|
|
287
288
|
영숫자로 채워도 넘칠 때만 "좁다", 한글로 채워도 남을 때만 "넓다" 로 판정합니다.
|
|
288
289
|
|
|
289
|
-
| 등급 | `SInput` (sm)
|
|
290
|
-
| ---- |
|
|
291
|
-
| `xs` | —
|
|
290
|
+
| 등급 | `SInput` (sm) | `SInput` (md) | `SNumberInput` (sm) | `SNumberInput` (sm, `useButton`) |
|
|
291
|
+
| ---- | ------------------- | ------------------- | ------------------- | -------------------------------- |
|
|
292
|
+
| `xs` | — | — | 영숫자 8 | 영숫자 2 |
|
|
292
293
|
| `sm` | 영숫자 14 / 한글 7 | 영숫자 11 / 한글 6 | 영숫자 14 | 영숫자 8 |
|
|
293
294
|
| `md` | 영숫자 20 / 한글 11 | 영숫자 16 / 한글 9 | 영숫자 20 | 영숫자 14 |
|
|
294
295
|
| `lg` | 영숫자 32 / 한글 17 | 영숫자 26 / 한글 14 | 영숫자 32 | 영숫자 26 |
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
| Prop | Type | Default | Description |
|
|
10
10
|
|------|------|---------|-------------|
|
|
11
11
|
| `vertical?` | `boolean` | `false` | true면 수직 분할선, false면 수평 분할선 |
|
|
12
|
+
| `height?` | `number \| string` | — | 수직 분할선의 길이. 숫자는 px, 문자열은 CSS 값(토큰 var 참조 등)으로 쓴다. 주지 않으면 `align-self: stretch` 로 부모 줄 높이를 그대로 채운다. 값을 주면 그 높이로 고정하고 교차축 가운데(`self-center`)에 맞춘다 — `align-self: stretch` 는 높이가 auto 일 때만 늘리므로, 높이를 정하는 순간 정렬을 함께 정해야 한다. 그래서 높이는 `className="h-*"` 가 아니라 이 prop 으로 준다. 수평 분할선에는 적용되지 않는다 (두께는 1px 로 고정). |
|
|
12
13
|
|
|
13
14
|
## Dependencies
|
|
14
15
|
|
|
@@ -2,6 +2,17 @@ import { type HTMLAttributes } from 'react';
|
|
|
2
2
|
export interface SDividerProps extends HTMLAttributes<HTMLHRElement> {
|
|
3
3
|
/** true면 수직 분할선, false면 수평 분할선 */
|
|
4
4
|
vertical?: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* 수직 분할선의 길이. 숫자는 px, 문자열은 CSS 값(토큰 var 참조 등)으로 쓴다.
|
|
7
|
+
*
|
|
8
|
+
* 주지 않으면 `align-self: stretch` 로 부모 줄 높이를 그대로 채운다. 값을 주면
|
|
9
|
+
* 그 높이로 고정하고 교차축 가운데(`self-center`)에 맞춘다 — `align-self: stretch`
|
|
10
|
+
* 는 높이가 auto 일 때만 늘리므로, 높이를 정하는 순간 정렬을 함께 정해야 한다.
|
|
11
|
+
* 그래서 높이는 `className="h-*"` 가 아니라 이 prop 으로 준다.
|
|
12
|
+
*
|
|
13
|
+
* 수평 분할선에는 적용되지 않는다 (두께는 1px 로 고정).
|
|
14
|
+
*/
|
|
15
|
+
height?: number | string;
|
|
5
16
|
}
|
|
6
17
|
/** SDivider — sd-divider 포팅. 색상은 `--sys-color-divider-default`. */
|
|
7
18
|
export declare const SDivider: import("react").ForwardRefExoticComponent<SDividerProps & import("react").RefAttributes<HTMLHRElement>>;
|
|
@@ -24,12 +24,11 @@
|
|
|
24
24
|
| `noDataLabel?` | `string` | `'데이터가 없습니다.'` | |
|
|
25
25
|
| `noDataSlot?` | `ReactNode` | — | 데이터가 없을 때 body 영역 전체를 대체하는 슬롯. 지정하면 `noDataLabel` 대신 이 콘텐츠가 헤더 아래 영역을 채우며, 버튼 등 인터랙션도 동작한다. |
|
|
26
26
|
| `isLoading?` | `boolean` | `false` | |
|
|
27
|
-
| `dense?` | `boolean` | `false` | 행 높이를 좁게 (세로 여백만 줄인다 — 좌우 패딩은 그대로) |
|
|
27
|
+
| `dense?` | `boolean` | `false` | 행 높이를 좁게 (세로 여백만 줄인다 — 좌우 패딩은 그대로). **시작 밀도이자 밀도 토글의 스위치다.** 켜면 하단 바 우측에 `좁게 보기` · `넓게 보기` 토글이 붙는다 — 페이지네이션이 없으면 이 바를 토글만 담아 그린다. 누른 뒤의 밀도는 테이블이 내부 상태로 들고 가므로 `onDenseChange` 를 받지 않아도 토글은 동작하고, 넓게 본 뒤에도 토글은 그대로 남는다(붙일지는 이 prop 이 정한다). 이 prop 값이 바뀌면 내부 밀도도 그 값으로 맞춰진다. |
|
|
28
28
|
| `noHover?` | `boolean` | `false` | true면 행에 마우스를 올려도 hover 배경(grey_05)을 표시하지 않는다 |
|
|
29
29
|
| `pagination?` | `STablePagination` | — | 페이지네이션 (있으면 하단 표시) |
|
|
30
30
|
| `useInternalPagination?` | `boolean` | `false` | 테이블 내부에서 페이지네이션을 직접 관리 (rows를 내부 슬라이싱) |
|
|
31
31
|
| `useRowsPerPageSelect?` | `boolean` | `false` | 페이지당 행 수 셀렉트 표시 |
|
|
32
|
-
| `useDensityToggle?` | `boolean` | `false` | 페이지네이션 바에 밀도 토글(`좁게 보기` · `넓게 보기`) 표시. **페이지네이션이 있을 때만 나타난다** — 토글이 사는 곳이 그 바이기 때문이다. `onDenseChange` 와 함께 준다. 밀도는 컴포넌트가 갖지 않으므로, 핸들러 없이 켜면 눌러도 아무 일도 일어나지 않는다. |
|
|
33
32
|
| `rowsPerPageOption?` | `SSelectOption[]` | `DEFAULT_ROWS_PER_PAGE_OPTION` | |
|
|
34
33
|
| `useVirtualScroll?` | `boolean` | `false` | 가상 스크롤 |
|
|
35
34
|
| `rowHeight?` | `number` | — | |
|
|
@@ -45,7 +44,7 @@
|
|
|
45
44
|
|-------|------|-------------|
|
|
46
45
|
| `onSelectedChange` | `(rows: SRow[]) => void` | |
|
|
47
46
|
| `onSortChange` | `(sort: STableSort \| null) => void` | 정렬 헤더 클릭 (`asc → desc → 해제` 3단). 해제되면 `null` 이 온다. 다중 정렬은 1차 안에서 지원하지 않는다. |
|
|
48
|
-
| `onDenseChange` | `(dense: boolean) => void` | 밀도 변경 (
|
|
47
|
+
| `onDenseChange` | `(dense: boolean) => void` | 밀도 변경 (하단 바의 밀도 토글을 눌렀을 때). 표시는 테이블이 알아서 바꾸므로 받지 않아도 되고, 사용자가 고른 밀도를 다음 방문까지 기억해 두려는(로컬 저장 등) 페이지만 받으면 된다. |
|
|
49
48
|
| `onPageChange` | `(page: number) => void` | |
|
|
50
49
|
| `onRowsPerPageChange` | `(perPage: number) => void` | |
|
|
51
50
|
| `onVirtualUpdate` | `(range: { from: number; to: number }) => void` | |
|
|
@@ -218,12 +218,20 @@ export interface STableProps {
|
|
|
218
218
|
*/
|
|
219
219
|
noDataSlot?: ReactNode;
|
|
220
220
|
isLoading?: boolean;
|
|
221
|
-
/**
|
|
221
|
+
/**
|
|
222
|
+
* 행 높이를 좁게 (세로 여백만 줄인다 — 좌우 패딩은 그대로).
|
|
223
|
+
*
|
|
224
|
+
* **시작 밀도이자 밀도 토글의 스위치다.** 켜면 하단 바 우측에 `좁게 보기` · `넓게 보기` 토글이
|
|
225
|
+
* 붙는다 — 페이지네이션이 없으면 이 바를 토글만 담아 그린다.
|
|
226
|
+
*
|
|
227
|
+
* 누른 뒤의 밀도는 테이블이 내부 상태로 들고 가므로 `onDenseChange` 를 받지 않아도 토글은
|
|
228
|
+
* 동작하고, 넓게 본 뒤에도 토글은 그대로 남는다(붙일지는 이 prop 이 정한다). 이 prop 값이
|
|
229
|
+
* 바뀌면 내부 밀도도 그 값으로 맞춰진다.
|
|
230
|
+
*/
|
|
222
231
|
dense?: boolean;
|
|
223
232
|
/**
|
|
224
|
-
* 밀도 변경 (
|
|
225
|
-
*
|
|
226
|
-
* 기억해 두는 것(로컬 저장 등)도 페이지 몫이다.
|
|
233
|
+
* 밀도 변경 (하단 바의 밀도 토글을 눌렀을 때). 표시는 테이블이 알아서 바꾸므로 받지 않아도 되고,
|
|
234
|
+
* 사용자가 고른 밀도를 다음 방문까지 기억해 두려는(로컬 저장 등) 페이지만 받으면 된다.
|
|
227
235
|
*/
|
|
228
236
|
onDenseChange?: (dense: boolean) => void;
|
|
229
237
|
/** true면 행에 마우스를 올려도 hover 배경(grey_05)을 표시하지 않는다 */
|
|
@@ -235,14 +243,6 @@ export interface STableProps {
|
|
|
235
243
|
useInternalPagination?: boolean;
|
|
236
244
|
/** 페이지당 행 수 셀렉트 표시 */
|
|
237
245
|
useRowsPerPageSelect?: boolean;
|
|
238
|
-
/**
|
|
239
|
-
* 페이지네이션 바에 밀도 토글(`좁게 보기` · `넓게 보기`) 표시.
|
|
240
|
-
*
|
|
241
|
-
* **페이지네이션이 있을 때만 나타난다** — 토글이 사는 곳이 그 바이기 때문이다.
|
|
242
|
-
* `onDenseChange` 와 함께 준다. 밀도는 컴포넌트가 갖지 않으므로, 핸들러 없이 켜면 눌러도
|
|
243
|
-
* 아무 일도 일어나지 않는다.
|
|
244
|
-
*/
|
|
245
|
-
useDensityToggle?: boolean;
|
|
246
246
|
rowsPerPageOption?: SSelectOption[];
|
|
247
247
|
onRowsPerPageChange?: (perPage: number) => void;
|
|
248
248
|
/** 가상 스크롤 */
|
package/dist/index.cjs
CHANGED
|
@@ -3972,7 +3972,8 @@ var SDraggableItemImpl = /* @__PURE__ */ react.forwardRef(function SDraggableIte
|
|
|
3972
3972
|
] });
|
|
3973
3973
|
});
|
|
3974
3974
|
var SDraggableItem2 = /* @__PURE__ */ withDisplayName(SDraggableItemImpl, "SDraggableItem");
|
|
3975
|
-
var SDivider = /* @__PURE__ */ react.forwardRef(function SDivider2({ vertical = false, className, style, ...rest }, ref) {
|
|
3975
|
+
var SDivider = /* @__PURE__ */ react.forwardRef(function SDivider2({ vertical = false, height, className, style, ...rest }, ref) {
|
|
3976
|
+
const fixedHeight = vertical && height !== void 0;
|
|
3976
3977
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3977
3978
|
"hr",
|
|
3978
3979
|
{
|
|
@@ -3980,10 +3981,14 @@ var SDivider = /* @__PURE__ */ react.forwardRef(function SDivider2({ vertical =
|
|
|
3980
3981
|
"aria-orientation": vertical ? "vertical" : "horizontal",
|
|
3981
3982
|
className: cn(
|
|
3982
3983
|
"shrink-0 border-0",
|
|
3983
|
-
vertical ? "inline-block
|
|
3984
|
+
vertical ? cn("inline-block w-px", fixedHeight ? "self-center" : "h-auto self-stretch") : "block h-px w-full",
|
|
3984
3985
|
className
|
|
3985
3986
|
),
|
|
3986
|
-
style: {
|
|
3987
|
+
style: {
|
|
3988
|
+
backgroundColor: "var(--sys-color-divider-default, #E1E1E1)",
|
|
3989
|
+
...fixedHeight ? { height: typeof height === "number" ? `${height}px` : height } : null,
|
|
3990
|
+
...style
|
|
3991
|
+
},
|
|
3987
3992
|
...rest
|
|
3988
3993
|
}
|
|
3989
3994
|
);
|
|
@@ -11341,7 +11346,6 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
11341
11346
|
onPageChange,
|
|
11342
11347
|
useInternalPagination = false,
|
|
11343
11348
|
useRowsPerPageSelect = false,
|
|
11344
|
-
useDensityToggle = false,
|
|
11345
11349
|
rowsPerPageOption = DEFAULT_ROWS_PER_PAGE_OPTION,
|
|
11346
11350
|
onRowsPerPageChange,
|
|
11347
11351
|
useVirtualScroll = false,
|
|
@@ -11357,10 +11361,18 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
11357
11361
|
}, ref) {
|
|
11358
11362
|
const autoId = react.useId();
|
|
11359
11363
|
const resolvedTableId = tableId ?? autoId;
|
|
11364
|
+
const [innerDense, setInnerDense] = react.useState(dense);
|
|
11365
|
+
react.useEffect(() => {
|
|
11366
|
+
setInnerDense(dense);
|
|
11367
|
+
}, [dense]);
|
|
11368
|
+
const changeDense = (next) => {
|
|
11369
|
+
setInnerDense(next);
|
|
11370
|
+
onDenseChange?.(next);
|
|
11371
|
+
};
|
|
11360
11372
|
const visibleCols = react.useMemo(() => columns.filter((c) => c.visible !== false), [columns]);
|
|
11361
11373
|
const stickyLeft = stickyColumn?.left ?? 0;
|
|
11362
11374
|
const stickyRight = stickyColumn?.right ?? 0;
|
|
11363
|
-
const effectiveRowHeight = rowHeight ?? (
|
|
11375
|
+
const effectiveRowHeight = rowHeight ?? (innerDense ? DENSE_ROW_HEIGHT : DEFAULT_ROW_HEIGHT);
|
|
11364
11376
|
const colSignature = react.useMemo(
|
|
11365
11377
|
() => visibleCols.map((c) => `${c.name}:${c.width ?? ""}:${c.autoWidth ? 1 : 0}`).join("|"),
|
|
11366
11378
|
[visibleCols]
|
|
@@ -11590,9 +11602,9 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
11590
11602
|
else onSelectedChange?.([...selected, row]);
|
|
11591
11603
|
};
|
|
11592
11604
|
const radiusClass = radius === "full" ? "rounded-none" : radius === "useTop" ? "rounded-b-[var(--cmp-table-radius)] rounded-t-none" : "rounded-[var(--cmp-table-radius)]";
|
|
11593
|
-
const cellPadY =
|
|
11605
|
+
const cellPadY = innerDense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-body-paddingY-default)";
|
|
11594
11606
|
const cellPadXOf = (col) => col.contentType === "control" ? "var(--cmp-table-body-paddingX-default)" : "var(--cmp-table-body-paddingX-wide)";
|
|
11595
|
-
const rowH =
|
|
11607
|
+
const rowH = innerDense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-body-default-height)";
|
|
11596
11608
|
const totalColSpan = visibleCols.length + (selectable ? 1 : 0);
|
|
11597
11609
|
const stickyInfo = (i) => {
|
|
11598
11610
|
const isLeft = i < stickyLeft;
|
|
@@ -11944,10 +11956,11 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
11944
11956
|
]
|
|
11945
11957
|
}
|
|
11946
11958
|
),
|
|
11947
|
-
showPagination && // 원본 sd-table__pagination: 테이블 하단에 이어붙는 회색 바(높이 48px, margin-top:-1px로 테두리 겹침).
|
|
11959
|
+
(showPagination || dense) && // 원본 sd-table__pagination: 테이블 하단에 이어붙는 회색 바(높이 48px, margin-top:-1px로 테두리 겹침).
|
|
11948
11960
|
// SPagination은 전체 폭 기준 중앙, rows-per-page SSelect는 우측에 absolute 배치해 중앙 정렬을 유지한다.
|
|
11949
11961
|
// 루트 높이가 확정된 경우(테이블이 남은 영역을 채우는 배치) 페이지네이션 바가
|
|
11950
11962
|
// 눌리지 않도록 shrink-0으로 48px를 보장한다.
|
|
11963
|
+
// 페이지네이션이 없어도 dense 면 이 바를 그린다 — 밀도 토글이 사는 곳이 여기다.
|
|
11951
11964
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11952
11965
|
"div",
|
|
11953
11966
|
{
|
|
@@ -11957,22 +11970,20 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
|
|
|
11957
11970
|
bordered && "-mt-px border border-solid border-[color:var(--cmp-table-border-color)]"
|
|
11958
11971
|
),
|
|
11959
11972
|
children: [
|
|
11960
|
-
/* @__PURE__ */ jsxRuntime.jsx(SPagination, { currentPage: displayPage, lastPage, onPageChange: changePage }),
|
|
11961
|
-
(
|
|
11962
|
-
|
|
11963
|
-
// row·rowDense 는 세로 막대라 90도 돌려 가로 행으로 쓴다.
|
|
11964
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11973
|
+
showPagination && /* @__PURE__ */ jsxRuntime.jsx(SPagination, { currentPage: displayPage, lastPage, onPageChange: changePage }),
|
|
11974
|
+
(dense || useRowsPerPageSelect) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-[10px] top-1/2 flex -translate-y-1/2 items-center gap-[12px]", children: [
|
|
11975
|
+
dense && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11965
11976
|
STextLink,
|
|
11966
11977
|
{
|
|
11967
11978
|
size: "sm",
|
|
11968
|
-
icon:
|
|
11979
|
+
icon: innerDense ? "row" : "rowDense",
|
|
11969
11980
|
iconRotate: 90,
|
|
11970
11981
|
iconColor: "var(--sys-color-fg-quaternary)",
|
|
11971
|
-
label:
|
|
11972
|
-
onClick: () =>
|
|
11982
|
+
label: innerDense ? "\uB113\uAC8C \uBCF4\uAE30" : "\uC881\uAC8C \uBCF4\uAE30",
|
|
11983
|
+
onClick: () => changeDense(!innerDense)
|
|
11973
11984
|
}
|
|
11974
11985
|
),
|
|
11975
|
-
|
|
11986
|
+
dense && useRowsPerPageSelect && /* @__PURE__ */ jsxRuntime.jsx(SDivider, { vertical: true, className: "my-[6px]" }),
|
|
11976
11987
|
useRowsPerPageSelect && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11977
11988
|
SSelect2,
|
|
11978
11989
|
{
|
|
@@ -12035,7 +12046,7 @@ var STableBar = /* @__PURE__ */ react.forwardRef(function STableBar2({ total, se
|
|
|
12035
12046
|
SDivider,
|
|
12036
12047
|
{
|
|
12037
12048
|
vertical: true,
|
|
12038
|
-
|
|
12049
|
+
height: "var(--cmp-table-bar-divider-height)",
|
|
12039
12050
|
style: { backgroundColor: "var(--cmp-table-border-color)" }
|
|
12040
12051
|
}
|
|
12041
12052
|
),
|
|
@@ -12960,13 +12971,7 @@ function SCalendar({
|
|
|
12960
12971
|
}
|
|
12961
12972
|
)
|
|
12962
12973
|
] }),
|
|
12963
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12964
|
-
SDivider,
|
|
12965
|
-
{
|
|
12966
|
-
vertical: true,
|
|
12967
|
-
className: "h-[var(--cmp-datepicker-calendar-header-divider-height)] self-center"
|
|
12968
|
-
}
|
|
12969
|
-
),
|
|
12974
|
+
/* @__PURE__ */ jsxRuntime.jsx(SDivider, { vertical: true, height: "var(--cmp-datepicker-calendar-header-divider-height)" }),
|
|
12970
12975
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-[var(--cmp-datepicker-calendar-gap)]", children: [
|
|
12971
12976
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12972
12977
|
SGhostButton,
|