sellmate-design-system-react 9.0.0-beta.104 → 9.0.0-beta.107

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
@@ -576,6 +576,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
576
576
  | 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 — 폼 값으로 드롭다운에서 고르는 것이면 `SSelect` `type="tree"` |
577
577
  | 계층을 이루는 행들을 여러 열로 보여준다 (카테고리 > 상품 > 옵션) | `STreeTable` | §3-7-7 — 한 줄에 라벨 하나면 `STree` |
578
578
  | 표의 행마다 그 건의 상세를 펼쳐 보여준다 (한 행 = 한 건) | `STable` `renderExpansion` | §3-7-7 — 행끼리 계층이면 `STreeTable` |
579
+ | 표의 같은 열 입력(수량·로트번호 등)을 키보드만으로 아래·위 행으로 넘기며 연속 입력한다 | `STable` 컬럼 `gridNav` | §3-4 — Enter 는 아래, Shift+Enter 는 위 |
579
580
  | 사용자가 순서를 드래그로 바꾸게 한다 | `SDraggableList` + `SDraggableItem` | §3-7-6 |
580
581
  | 날짜별 일정을 한 달치 격자로 펼쳐 보여준다 | `SCalendarBoard` | §3-7-4 |
581
582
  | 항목끼리 크기를 눈으로 견주게 한다 (채널별 매출·상품별 판매량) | `SBarChart` | 정확한 값을 읽어야 하면 `STable` — 그래프는 "어느 쪽이 큰가" 를 답하지 "얼마인가" 를 답하지 않는다 |
@@ -1133,6 +1134,24 @@ const columns: STableColumn[] = [
1133
1134
  ];
1134
1135
  ```
1135
1136
 
1137
+ #### 셀 안 입력을 Enter 로 아래 행으로 넘기기
1138
+
1139
+ 수량·로트번호처럼 **행마다 같은 열에 입력이 반복되는 표**에서 키보드만으로 연속 입력하려면 그 컬럼에 `gridNav` 를 준다. Tab 은 가로(같은 행의 다음 필드), `SNumberInput` 의 ↑↓ 는 값 증감이라 수직 이동 수단이 따로 필요하다.
1140
+
1141
+ - **Enter 는 아래 행, Shift+Enter 는 위 행의 같은 열 입력으로 포커스를 옮긴다.** 직접 `onKeyDown` 이나 `data-*` 표식을 달지 않는다 — 한글 조합 중 Enter·열린 콤보박스·textarea 줄바꿈·비활성 행 처리가 `STable` 에 이미 들어 있다.
1142
+ - **`gridNav` 를 준 열의 입력만 Enter 를 가로챈다.** 주지 않은 열과 표 밖 필드의 Enter 는 그대로다 — `SForm` 안에서 Enter 로 제출된다. 이동을 켠 입력은 마지막 행에서도 제출되지 않는다.
1143
+ - **셀렉트·날짜 선택·체크박스, 그리고 자기 Enter 동작이 있는 입력(`SSearchInput` 처럼 Enter 로 검색·확정하는 것)의 열에는 주지 않는다.** Enter 가 이미 자기 뜻을 가진다.
1144
+ - **`gridNav` 를 준 열의 셀에는 입력이 하나여야 한다.** 한 셀에 입력이 둘이면(수량 + 단위 입력 등) 이동은 위·아래 행의 **첫 번째 입력**으로만 간다. 둘째 입력은 Enter 로 닿지 않으므로 Tab 으로 간다.
1145
+ - 이동 대상은 글자·숫자 입력(`SInput`·`SNumberInput`)뿐이다. 체크박스·라디오·비활성(`disabled`·`aria-disabled`)·읽기 전용 입력은 건너뛴다.
1146
+ - **화면에 그려진 행 사이만 이동한다.** `virtualScroll` 로 그려지지 않은 행으로는 넘어가지 않는다. 끝 행에서 Enter 를 눌러도 행이 추가되거나 다음 페이지로 넘어가지 않는다.
1147
+ - `renderCell` 로 `<td>` 를 직접 그리는 열에는 `gridNav` 가 적용되지 않는다. 그 열은 `render` 로 그린다.
1148
+
1149
+ ```tsx
1150
+ { name: 'qty', label: '입고 수량', field: 'qty', width: 100, minWidth: 100, align: 'right',
1151
+ contentType: 'control', gridNav: true,
1152
+ render: (row: SRow) => <SNumberInput value={row.qty} onValueChange={v => setQty(row, v)} /> },
1153
+ ```
1154
+
1136
1155
  #### 정렬 가능한 컬럼
1137
1156
 
1138
1157
  **정렬 상태는 `STable` 이 갖지 않는다.** 컬럼에 `sortable: true` 를 주고, 페이지가 `sort` · `onSortChange` 로 상태를 들고 있는다.
@@ -2536,6 +2555,13 @@ import { SLocaleProvider, SModalOutlet } from 'sellmate-design-system-react';
2536
2555
 
2537
2556
  **접으면 레일·메뉴가 통째로 빠져나가면서 그 슬롯들도 함께 사라진다.** 접힌 상태에서도 남겨야 할 것은 `foldedTop`·`foldedFooter` 로 따로 준다 — `header="fix"` 로 접혔을 때만 나타나며, 폭이 좁은 폴드 레일이므로 아이콘 버튼 하나 정도로 줄인다.
2538
2557
 
2558
+ **접힌 GNB 를 호버로 잠깐 펼치는 동작은 컴포넌트가 한다 — 앱이 따로 만들지 않는다.** 접힌 채 화면 왼쪽 가장자리(`header` 와 무관하게 `fix`·`full` 모두)에 마우스를 가져가면 페이지를 밀지 않고 그 위에 겹쳐 펼쳐지고, GNB 를 벗어나면 다시 접힌다. 키보드 포커스가 펼쳐진 GNB 안에 있으면 접히지 않는다. 이 동작을 켜고 끄는 prop 은 없다.
2559
+
2560
+ - **`folded` 는 그대로이고 `onFoldedChange` 도 오지 않는다.** 호버로 펼친 것은 보이는 모양뿐이라 앱의 접힘 상태·페이지 폭에 영향이 없다. 펼친 채로 두려면 폴드 버튼으로 편다 — 그때 `folded` 가 바뀐다.
2561
+ - **접힌 화면의 왼쪽 가장자리에는 호버 영역(투명 띠)이 깔린다.** 그 자리에 클릭해야 하는 것(페이지 왼쪽 끝에 붙인 버튼 등)을 두지 않는다. 띠의 폭은 컴포넌트가 정하므로 숫자를 직접 주지 않는다.
2562
+ - **펼쳐지는 동안 `foldedTop`·`foldedFooter` 와 접힌 레일의 `system` 은 펼친 모양(`menuTop`·`menuFooter`·메뉴 컬럼 바닥)으로 바뀐다.** 접힌 레일에서 열어 둔 계정·알림 패널은 그때 닫힌다(§4-1 `system`).
2563
+ - **터치에는 hover 가 없어 동작하지 않는다.** 터치 화면에서도 접힌 GNB 를 펴야 하면 폴드 버튼으로 연다.
2564
+
2539
2565
  ```tsx
2540
2566
  {/* 접히면 menuTop·menuFooter 가 함께 빠지므로, 폴드 레일에 남길 것만 foldedTop 으로 따로 준다 */}
2541
2567
  <SGnb
@@ -201,6 +201,9 @@ export interface SGnbProps extends Omit<HTMLAttributes<HTMLDivElement>, 'color'>
201
201
  * 접힘/펼침은 GNB_FOLD_MS 동안의 슬라이드다 — 레일·메뉴가 함께 왼쪽으로 빠져나가고 펼치면 오른쪽에서 들어온다.
202
202
  * 페이지 쪽 폭은 fix 면 이 컴포넌트의 폭 전환이, full 이면 SLayout 의 메뉴 열 전환이 같은 길이로 맞춘다.
203
203
  *
204
+ * 접힌 채 화면 왼쪽 가장자리(투명 띠)에 마우스를 가져가면 페이지를 밀지 않고 위에 겹쳐 펼쳐지고,
205
+ * GNB 를 벗어나면(키보드 포커스가 안에 있으면 유지) 다시 접힌다. `folded` 는 바뀌지 않는다.
206
+ *
204
207
  * SLayout 안에서 쓰면 type·header·folded 를 context 에서 읽어 앱이 중복으로 넘길 필요가 없고,
205
208
  * 자기 치수(컬럼 폭·상단바 높이·전환 길이)를 registerNav 로 되올려 프레임이 그 값으로 그리드를 깐다.
206
209
  *
@@ -118,6 +118,30 @@ export declare const GNB_FOLD_MS = 200;
118
118
  * 폴드와 같은 값을 써서 두 모션이 한 언어로 읽히게 한다.
119
119
  */
120
120
  export declare const GNB_EXPAND_MS = 200;
121
+ /**
122
+ * 접힌 GNB 의 호버 오버레이(peek) — 접힌 채 화면 왼쪽 가장자리에 마우스를 가져가면 GNB 가
123
+ * 페이지를 밀지 않고 위에 겹쳐 펼쳐진다. 전용 토큰이 없어 상수로 둔다.
124
+ * - 진입 지연: 가장자리를 스치기만 한 경우에 펼쳐지지 않게 한다.
125
+ * - 이탈 지연: 경계를 살짝 벗어났다 돌아오는 동안 깜빡이며 접히지 않게 한다.
126
+ * - 가장자리 폭: 여는 호버 영역인 화면 왼쪽 투명 띠의 폭. header="full" 은 접으면 메뉴가 화면 밖으로 나가
127
+ * 잡을 자리가 없고, header="fix" 는 접힌 레일 전체를 영역으로 삼으면 레일의 버튼으로 가는 길에 스치기만 해도
128
+ * 펼쳐져 누르려던 버튼이 바뀌므로 둘 다 띠로 연다.
129
+ */
130
+ export declare const GNB_PEEK_ENTER_DELAY_MS = 120;
131
+ export declare const GNB_PEEK_LEAVE_DELAY_MS = 250;
132
+ export declare const GNB_PEEK_EDGE_WIDTH = 12;
133
+ /**
134
+ * 호버 오버레이가 뜨는 z-index. 두 쪽 사이에 끼어야 한다.
135
+ * - 위로 못 넘는 것: 페이지 안의 로컬 값(SPageHeader·sticky 헤더 등 한 자리~30 대) — 오버레이가 그 아래로 가라앉으면 안 된다.
136
+ * - 아래로 못 내려가는 것: 전역 포털 레이어(`Z_INDEX.baseFloating`=50) — GNB 안에서 뜬 계정 목록·런처·라벨 칩이
137
+ * 오버레이에 가려지면 안 된다.
138
+ */
139
+ export declare const GNB_PEEK_Z_INDEX = 40;
140
+ /**
141
+ * 호버 오버레이의 그림자. 시안 값이 공용 그림자 토큰(--shadow-*)에 없어 상수로 둔다.
142
+ * 오버레이는 왼쪽 가장자리에 붙어 사방으로 고르게 퍼지는 그림자를 쓴다(오프셋 없음).
143
+ */
144
+ export declare const GNB_PEEK_SHADOW = "0px 0px 64px 0px rgba(34,34,34,0.12), 0px 0px 24px 0px rgba(34,34,34,0.08)";
121
145
  /**
122
146
  * 메뉴 고정 폭. 두 header 모두 메뉴는 이 폭으로 좌측에 붙는다(토큰 없음 → 상수).
123
147
  * header="full" 에서 SLayout 이 "메뉴 오른쪽 = 페이지" 영역을 잡을 때도 이 값을 쓴다.
@@ -87,6 +87,11 @@ export type SSelectChangeValue = any;
87
87
  export interface SSelectOption {
88
88
  value: string | number;
89
89
  label: string;
90
+ /**
91
+ * 주면 `label` 을 STag 로 그린다 — 목록 행과 단일 선택 트리거에 적용. 칩·multi 의 쉼표 트리거는 글자로 둔다.
92
+ * 태그는 글자만 받으므로 HTML 라벨과 함께 주면 태그를 걷어낸 글자로 그려진다.
93
+ */
94
+ tag?: SSelectOptionTag;
90
95
  disabled?: boolean;
91
96
  children?: SSelectOption[];
92
97
  }
@@ -106,6 +111,16 @@ export type SSelectType =
106
111
  export type SSelectValueDisplay = 'text' | 'chip';
107
112
  ```
108
113
 
114
+ ### SSelectOptionTag
115
+
116
+ ```ts
117
+ /**
118
+ * 옵션 라벨을 STag 로 그릴 때 넘기는 값. 글자는 옵션의 `label` 이고, 크기는 SSelect 의 `size` 가
119
+ * 정한다(`md` 면 `sm`, 그 외 `xs`) — 그래서 `size`·`label` 은 받지 않는다. 나머지(`color`·`deep`·`shape`·`icon`…)는 STag 와 같다.
120
+ */
121
+ export type SSelectOptionTag = Omit<STagProps, 'size' | 'label'>;
122
+ ```
123
+
109
124
  ## Dependencies
110
125
 
111
126
  ### Used by
@@ -122,6 +137,7 @@ export type SSelectValueDisplay = 'text' | 'chip';
122
137
  - [SIcon](../SIcon)
123
138
  - [SPortal](../SPortal)
124
139
  - [SSearchInput](../SSearchInput)
140
+ - [STag](../STag)
125
141
 
126
142
  ### Graph
127
143
 
@@ -134,6 +150,7 @@ graph TD;
134
150
  SSelect --> SIcon
135
151
  SSelect --> SPortal
136
152
  SSelect --> SSearchInput
153
+ SSelect --> STag
137
154
  SKeyValueTable --> SSelect
138
155
  STable --> SSelect
139
156
  style SSelect fill:#f9f,stroke:#333,stroke-width:4px
@@ -6,7 +6,7 @@ import { type SColor } from '../../lib/color';
6
6
  import { type STooltipProps } from '../STooltip';
7
7
  import { type SSelectOption, type SSelectType, type SSelectValueDisplay } from './select.config';
8
8
  import { type SFieldWidth } from '../../lib/field-width';
9
- export type { SSelectOption, SSelectType, SSelectValueDisplay } from './select.config';
9
+ export type { SSelectOption, SSelectOptionTag, SSelectType, SSelectValueDisplay, } from './select.config';
10
10
  export interface SSelectHandle {
11
11
  /** 트리거(combobox)에 포커스 (sdFocus) */
12
12
  focus: () => void;
@@ -1,6 +1,17 @@
1
+ import { type STagProps } from '../STag';
2
+ /**
3
+ * 옵션 라벨을 STag 로 그릴 때 넘기는 값. 글자는 옵션의 `label` 이고, 크기는 SSelect 의 `size` 가
4
+ * 정한다(`md` 면 `sm`, 그 외 `xs`) — 그래서 `size`·`label` 은 받지 않는다. 나머지(`color`·`deep`·`shape`·`icon`…)는 STag 와 같다.
5
+ */
6
+ export type SSelectOptionTag = Omit<STagProps, 'size' | 'label'>;
1
7
  export interface SSelectOption {
2
8
  value: string | number;
3
9
  label: string;
10
+ /**
11
+ * 주면 `label` 을 STag 로 그린다 — 목록 행과 단일 선택 트리거에 적용. 칩·multi 의 쉼표 트리거는 글자로 둔다.
12
+ * 태그는 글자만 받으므로 HTML 라벨과 함께 주면 태그를 걷어낸 글자로 그려진다.
13
+ */
14
+ tag?: SSelectOptionTag;
4
15
  disabled?: boolean;
5
16
  children?: SSelectOption[];
6
17
  }
@@ -10,6 +21,7 @@ export type SSelectValueDisplay = 'text' | 'chip';
10
21
  export interface FlatOption {
11
22
  value: string;
12
23
  label: string;
24
+ tag?: SSelectOptionTag;
13
25
  disabled: boolean;
14
26
  depth: number;
15
27
  /** children 을 가진 그룹 노드 — 그 자체가 값이 되는 것은 `tree` 타입뿐이다 */
@@ -132,6 +132,20 @@ interface STableColumnBase<TRow extends SRow = SRow> {
132
132
  * 임의의 `render` 결과라 컴포넌트가 알 수 없다. 그래서 열 단위로 받는다.
133
133
  */
134
134
  contentType?: 'text' | 'control';
135
+ /**
136
+ * 이 열의 입력(`SInput`·`SNumberInput`)에서 **Enter 로 아래 행, Shift+Enter 로 위 행**의 같은
137
+ * 입력으로 포커스를 옮긴다. 수량·로트번호처럼 행마다 같은 열에 입력이 반복되는 표에서 키보드만으로
138
+ * 연속 입력할 때 켠다. Tab 은 같은 행의 다음 필드로, ↑↓ 는 숫자 입력의 증감으로 그대로 남는다.
139
+ *
140
+ * - **이동을 켠 열의 입력만 Enter 를 가로챈다.** 그 열의 입력은 마지막 행에서도 폼을 제출하지 않고,
141
+ * 켜지 않은 열·표 밖 필드의 Enter 는 기존대로 제출된다.
142
+ * - **셀에는 입력이 하나여야 한다.** 둘이면 위·아래 행의 첫 번째 입력으로만 이동한다.
143
+ * - **셀렉트·날짜 선택·체크박스, 자기 Enter 동작이 있는 입력(`SSearchInput`)의 열에는 켜지 않는다.**
144
+ * - 비활성·읽기 전용 입력은 건너뛰고, 한글 조합 중 Enter 는 이동하지 않는다.
145
+ * - 화면에 그려진 행 사이만 이동한다 — `virtualScroll` 에서 그려지지 않은 행으로는 넘어가지 않는다.
146
+ * - `renderCell` 로 `<td>` 를 직접 그리는 열은 표식을 달 수 없어 대상이 아니다. `render` 를 쓴다.
147
+ */
148
+ gridNav?: boolean;
135
149
  /** 셀 커스텀 렌더 (React 확장) — `<td>` 안쪽 내용만 교체한다 */
136
150
  render?: (row: TRow, value: STableCellValue<TRow>) => ReactNode;
137
151
  /**
@@ -79,6 +79,7 @@ export const TAG_COLORS = [
79
79
  - [SLauncherListBox](../SLauncherListBox)
80
80
  - [SNumberInput](../SNumberInput)
81
81
  - [SRadioCard](../SRadioCard)
82
+ - [SSelect](../SSelect)
82
83
  - [SSystemActionButton](../SSystemActionButton)
83
84
  - [STabs](../STabs)
84
85
  - [STextLink](../STextLink)
@@ -102,6 +103,7 @@ graph TD;
102
103
  SLauncherListBox --> STag
103
104
  SNumberInput --> STag
104
105
  SRadioCard --> STag
106
+ SSelect --> STag
105
107
  SSystemActionButton --> STag
106
108
  STabs --> STag
107
109
  STextLink --> STag