sellmate-design-system-react 9.0.0-beta.13 → 9.0.0-beta.15

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
@@ -854,6 +854,24 @@ const columns: STableColumn[] = [
854
854
 
855
855
  `0` 은 값이 있는 것이므로 하이픈으로 바꾸지 않는다 — `0원` 그대로 표시한다.
856
856
 
857
+ #### 라벨만으로 뜻이 안 통하는 컬럼은 `helpText`
858
+
859
+ 헤더 라벨은 컬럼 폭 안에 들어가야 해서 짧아진다. **산출 기준·단위·상태 값의 뜻처럼 라벨에 담기지 않는 설명은 `column.helpText` 로 준다** — 라벨 뒤에 도움말 아이콘이 붙고 hover 하면 툴팁이 뜬다. 배열의 각 항목이 한 줄이다. `SKeyValueTable` 의 `field.helpText`, `SSectionHeaderCard` 의 `helpText` 와 같은 것이다.
860
+
861
+ ```tsx
862
+ const columns: STableColumn[] = [
863
+ { name: 'orderCount', label: '주문 수', field: 'orderCount', width: '120px', align: 'right',
864
+ helpText: ['취소·반품을 제외한 확정 주문 수입니다.'],
865
+ format: (v: number) => `${Number(v).toLocaleString()}건` },
866
+ { name: 'status', label: '상태', field: 'status', width: '100px', align: 'center',
867
+ helpText: ['활성: 최근 30일 내 주문 있음', '보관됨: 거래 종료'] },
868
+ ];
869
+ ```
870
+
871
+ - **`renderHeader` 로 헤더를 직접 만들어 `STooltip` 을 붙이지 않는다.** `renderHeader` 는 헤더 전체를 교체하므로 `helpText` 가 무시되고, 아이콘·크기·색·간격을 손으로 맞추게 된다.
872
+ - **모든 컬럼에 달지 않는다.** 라벨로 뜻이 통하는 컬럼(`주문번호`·`상품명`)까지 붙이면 헤더가 아이콘으로 뒤덮여 정작 설명이 필요한 컬럼이 묻힌다.
873
+ - 긴 문장을 넣는 자리가 아니다. 한 줄에 한 가지 사실만 담고, 그 이상은 페이지 상단 안내(`SCallout`)로 뺀다.
874
+
857
875
  ### 3-5. 버튼류
858
876
 
859
877
  | 상황 | 사용 |
@@ -3,5 +3,5 @@ export interface SCardProps extends HTMLAttributes<HTMLDivElement> {
3
3
  /** 테두리 표시 여부 */
4
4
  bordered?: boolean;
5
5
  }
6
- /** SCard — sd-card 포팅. 라운드 8px, 흰 배경, 옵션 테두리. */
6
+ /** SCard — sd-card 포팅. 라운드 8px, 흰 배경, 옵션 테두리. 콘텐츠는 라운드 경계에서 잘린다. */
7
7
  export declare const SCard: import("react").ForwardRefExoticComponent<SCardProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -162,3 +162,8 @@ export declare function findGnbRailValue(items: SGnbMenuItem[], value: string):
162
162
  export declare function findGnbSiblingValues(items: SGnbMenuItem[], value: string): string[];
163
163
  /** value 로 선택된 아이템의 조상 value 목록(자기 자신 제외)을 반환 → 자동 펼침용 */
164
164
  export declare function findGnbAncestors(items: SGnbMenuItem[], value: string): string[];
165
+ /**
166
+ * value 를 가진 아이템 아래의 **하위 가지**(children 을 가진 자손) value 목록을 반환.
167
+ * 부모를 펼칠 때 그 아래 가지도 전부 함께 펼치는 용도 — 리프는 펼침 대상이 아니라 제외한다.
168
+ */
169
+ export declare function findGnbDescendantBranchValues(items: SGnbMenuItem[], value: string): string[];
@@ -83,6 +83,13 @@ export interface STableColumn {
83
83
  icon?: SIconName;
84
84
  /** 헤더 아이콘 색상. 팔레트 키(`grey_65`, `red_95` …) 또는 임의 CSS 색상 */
85
85
  iconColor?: SColor;
86
+ /**
87
+ * 헤더 라벨 뒤 도움말 툴팁 (각 항목이 한 줄). `SKeyValueTable` 의 `field.helpText` 와 같은 역할 —
88
+ * 라벨만으로 뜻이 통하지 않는 컬럼의 산출 기준·단위를 설명한다.
89
+ *
90
+ * `renderHeader` 로 헤더를 통째로 교체하면 그리지 않는다 (헤더 전체가 소비 앱 책임).
91
+ */
92
+ helpText?: string[];
86
93
  /**
87
94
  * 셀에 무엇이 들어가는지. 좌우 여백이 여기서 갈린다 — 기본은 `text`(넓게).
88
95
  *
@@ -172,6 +179,7 @@ export interface STableCellContext {
172
179
  - [SIcon](../SIcon)
173
180
  - [SPagination](../SPagination)
174
181
  - [SSelect](../SSelect)
182
+ - [STooltip](../STooltip)
175
183
 
176
184
  ### Graph
177
185
 
@@ -182,5 +190,6 @@ graph TD;
182
190
  STable --> SIcon
183
191
  STable --> SPagination
184
192
  STable --> SSelect
193
+ STable --> STooltip
185
194
  style STable fill:#f9f,stroke:#333,stroke-width:4px
186
195
  ```
@@ -38,6 +38,13 @@ export interface STableColumn {
38
38
  icon?: SIconName;
39
39
  /** 헤더 아이콘 색상. 팔레트 키(`grey_65`, `red_95` …) 또는 임의 CSS 색상 */
40
40
  iconColor?: SColor;
41
+ /**
42
+ * 헤더 라벨 뒤 도움말 툴팁 (각 항목이 한 줄). `SKeyValueTable` 의 `field.helpText` 와 같은 역할 —
43
+ * 라벨만으로 뜻이 통하지 않는 컬럼의 산출 기준·단위를 설명한다.
44
+ *
45
+ * `renderHeader` 로 헤더를 통째로 교체하면 그리지 않는다 (헤더 전체가 소비 앱 책임).
46
+ */
47
+ helpText?: string[];
41
48
  /**
42
49
  * 셀에 무엇이 들어가는지. 좌우 여백이 여기서 갈린다 — 기본은 `text`(넓게).
43
50
  *
@@ -69,6 +69,7 @@ export type STooltipType = 'default' | 'danger' | 'warning' | 'accent';
69
69
  - [SKeyValueTable](../SKeyValueTable)
70
70
  - [SSectionHeaderCard](../SSectionHeaderCard)
71
71
  - [SStepper](../SStepper)
72
+ - [STable](../STable)
72
73
 
73
74
  ### Depends on
74
75
 
@@ -86,5 +87,6 @@ graph TD;
86
87
  SKeyValueTable --> STooltip
87
88
  SSectionHeaderCard --> STooltip
88
89
  SStepper --> STooltip
90
+ STable --> STooltip
89
91
  style STooltip fill:#f9f,stroke:#333,stroke-width:4px
90
92
  ```
package/dist/index.cjs CHANGED
@@ -3373,7 +3373,11 @@ var SCard = /* @__PURE__ */ react.forwardRef(function SCard2({ bordered = false,
3373
3373
  "div",
3374
3374
  {
3375
3375
  ref,
3376
- className: cn("h-fit rounded-[8px] bg-white", bordered && "border border-grey-30", className),
3376
+ className: cn(
3377
+ "h-fit overflow-hidden rounded-[8px] bg-white",
3378
+ bordered && "border border-grey-30",
3379
+ className
3380
+ ),
3377
3381
  ...rest,
3378
3382
  children
3379
3383
  }
@@ -8329,6 +8333,29 @@ function findGnbAncestors(items, value) {
8329
8333
  };
8330
8334
  return walk(items, []) ?? [];
8331
8335
  }
8336
+ function findGnbDescendantBranchValues(items, value) {
8337
+ const find = (list) => {
8338
+ for (const item of list) {
8339
+ if (item.value === value) return item;
8340
+ if (item.children) {
8341
+ const found = find(item.children);
8342
+ if (found) return found;
8343
+ }
8344
+ }
8345
+ return void 0;
8346
+ };
8347
+ const collect = (list, acc) => {
8348
+ for (const item of list) {
8349
+ if (item.children && item.children.length > 0) {
8350
+ acc.push(item.value);
8351
+ collect(item.children, acc);
8352
+ }
8353
+ }
8354
+ return acc;
8355
+ };
8356
+ const target = find(items);
8357
+ return target?.children ? collect(target.children, []) : [];
8358
+ }
8332
8359
  var LABEL_TIP_HIDE_DELAY_MS = 100;
8333
8360
  var DEPTH_PADDING_LEFT = (M, depth) => depth === 1 ? M.depth1PaddingLeft : depth === 2 ? M.depth2PaddingLeft : M.depth3PaddingLeft;
8334
8361
  var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
@@ -8369,8 +8396,12 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
8369
8396
  const H = GNB_HEADER[header];
8370
8397
  const M = GNB_MENU[type];
8371
8398
  const C = GNB_COLORS[color];
8399
+ const branchWithDescendants = (key) => [
8400
+ key,
8401
+ ...findGnbDescendantBranchValues(items, key)
8402
+ ];
8372
8403
  const [expandedKeys, setExpandedKeys] = react.useState(
8373
- () => new Set(findGnbAncestors(items, value))
8404
+ () => new Set(findGnbAncestors(items, value).flatMap(branchWithDescendants))
8374
8405
  );
8375
8406
  const [hoveredKey, setHoveredKey] = react.useState(null);
8376
8407
  const [labelTip, setLabelTip] = react.useState(null);
@@ -8417,12 +8448,15 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
8417
8448
  () => findGnbRailValue(items, value) ?? items[0]?.value
8418
8449
  );
8419
8450
  react.useEffect(() => {
8420
- const ancestors = findGnbAncestors(items, value);
8421
- if (ancestors.length === 0) return;
8451
+ const keys = findGnbAncestors(items, value).flatMap((ancestor) => [
8452
+ ancestor,
8453
+ ...findGnbDescendantBranchValues(items, ancestor)
8454
+ ]);
8455
+ if (keys.length === 0) return;
8422
8456
  setExpandedKeys((prev) => {
8423
- if (ancestors.every((a) => prev.has(a))) return prev;
8457
+ if (keys.every((key) => prev.has(key))) return prev;
8424
8458
  const next = new Set(prev);
8425
- ancestors.forEach((a) => next.add(a));
8459
+ keys.forEach((key) => next.add(key));
8426
8460
  return next;
8427
8461
  });
8428
8462
  }, [items, value]);
@@ -8439,10 +8473,12 @@ var SGnb = /* @__PURE__ */ react.forwardRef(function SGnb2({
8439
8473
  setExpandedKeys((prev) => {
8440
8474
  const next = new Set(prev);
8441
8475
  if (next.has(key)) {
8442
- next.delete(key);
8476
+ branchWithDescendants(key).forEach((descendant) => next.delete(descendant));
8443
8477
  } else {
8444
- findGnbSiblingValues(items, key).forEach((sibling) => next.delete(sibling));
8445
- next.add(key);
8478
+ findGnbSiblingValues(items, key).forEach(
8479
+ (sibling) => branchWithDescendants(sibling).forEach((descendant) => next.delete(descendant))
8480
+ );
8481
+ branchWithDescendants(key).forEach((descendant) => next.add(descendant));
8446
8482
  }
8447
8483
  return next;
8448
8484
  });
@@ -11430,7 +11466,21 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
11430
11466
  ),
11431
11467
  children: col.renderHeader ? col.renderHeader(col, i) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11432
11468
  col.icon && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: col.icon, size: 16, color: col.iconColor }),
11433
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: col.label })
11469
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: col.label }),
11470
+ col.helpText && col.helpText.length > 0 && // 라벨이 좁아져 truncate 되더라도 아이콘까지 함께 줄어들면 안 되므로
11471
+ // shrink-0 래퍼로 감싼다 (STooltip 의 className 은 본문 쪽으로 간다).
11472
+ // 아이콘·크기·색은 SKeyValueTable 헤더 도움말과 동일하게 맞춘다.
11473
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
11474
+ STooltip2,
11475
+ {
11476
+ trigger: "hover",
11477
+ icon: "helpOutline",
11478
+ iconSize: 12,
11479
+ color: "var(--sys-color-fg-success)",
11480
+ placement: "top",
11481
+ message: col.helpText
11482
+ }
11483
+ ) })
11434
11484
  ] })
11435
11485
  }
11436
11486
  ),