sellmate-design-system-react 9.0.0-beta.59 → 9.0.0-beta.60

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
@@ -1067,20 +1067,38 @@ const columns: STableColumn[] = [
1067
1067
  라벨 [helpText ?] [editable] [navigable] [required *] [sortable 정렬버튼]
1068
1068
  ```
1069
1069
 
1070
- **`editable` 값을 직접 고칠 있는 열, `navigable` 은 눌러서 다른 화면으로 넘어가는 열에 준다.** 둘 다 **표식일 뿐 버튼이 아니다** — 아이콘·크기·색은 컴포넌트가 고정하고 클릭은 받지 않는다.
1070
+ **둘을 가르는 기준은 "무엇을 하느냐"가 아니라 "현재 화면을 떠나느냐"다.**
1071
+
1072
+ | 셀을 눌렀을 때 | 표식 |
1073
+ | --- | --- |
1074
+ | 셀에서 바로 고친다 | `editable` |
1075
+ | 모달·바텀시트를 띄워 고친다 | `editable` |
1076
+ | 새 창·새 팝업을 띄운다, 페이지를 이동한다 | `navigable` |
1077
+ | 모달로 보여주기만 한다 (고치지 않는다) | 둘 다 없음 |
1078
+
1079
+ **모달은 `navigable` 이 아니다.** 현재 화면 위에 겹쳐 뜰 뿐 화면을 떠나는 것이 아니다 — 거기서 값을 고치면 고치는 자리가 셀이든 모달이든 `editable` 이다. 반대로 새 창·새 팝업은 거기서 값을 고치더라도 `navigable` 이다. 화면을 떠나기 때문이다.
1080
+
1081
+ 둘 다 **표식일 뿐 버튼이 아니다** — 아이콘·크기·색은 컴포넌트가 고정하고 클릭은 받지 않는다.
1071
1082
 
1072
1083
  ```tsx
1073
1084
  const columns: STableColumn[] = [
1085
+ // 새 창으로 상세를 연다 → navigable
1074
1086
  { name: 'name', label: '상품명', field: 'name', width: 200,
1075
1087
  navigable: true,
1076
- render: (row: SRow) => <STextLink label={row.name} onClick={() => goDetail(row.id)} /> },
1088
+ render: (row: SRow) => <STextLink label={row.name} onClick={() => openDetailWindow(row.id)} /> },
1089
+ // 셀에서 바로 고친다 → editable
1077
1090
  { name: 'stock', label: '재고', field: 'stock', width: 160, contentType: 'control',
1078
1091
  editable: true, required: true,
1079
1092
  render: (row: SRow) => <SNumberInput value={row.stock} width="100%" /> },
1093
+ // 수정 모달을 띄워 고친다 → 화면을 떠나지 않으므로 navigable 이 아니라 editable
1094
+ { name: 'memo', label: '메모', field: 'memo', width: 200,
1095
+ editable: true,
1096
+ render: (row: SRow) => <STextLink label={row.memo} onClick={() => openMemoModal(row.id)} /> },
1080
1097
  ];
1081
1098
  ```
1082
1099
 
1083
- - **실제로 그렇게 동작하는 열에만 켠다.** 표식만 켜고 셀은 텍스트 그대로 두면, 고칠 수 있다고 해 놓고 고칠 방법이 없고 넘어갈 수 있다고 해 놓고 누를 것이 없다. `editable` 이면 셀에 입력 컨트롤이, `navigable` 이면 셀에 링크·클릭이 있어야 한다.
1100
+ - **실제로 그렇게 동작하는 열에만 켠다.** 표식만 켜고 셀은 텍스트 그대로 두면, 고칠 수 있다고 해 놓고 고칠 방법이 없고 넘어갈 수 있다고 해 놓고 누를 것이 없다. `editable` 이면 셀에 고치는 수단(입력 컨트롤이나 수정 모달을 여는 링크·클릭)이, `navigable` 이면 셀에 새 화면을 여는 링크·클릭이 있어야 한다.
1101
+ - **한 열에 둘 다 켜는 것은 두 동작이 모두 있을 때만이다** — 예를 들어 셀에서 값을 고치면서 라벨을 누르면 새 창으로 상세가 열리는 열. 판단이 서지 않으면 하나만 켠다.
1084
1102
  - **표식으로 동작을 대신하지 않는다.** 고치는 UI 도 넘어가는 동작도 셀(`column.render`) 몫이다.
1085
1103
  - **`renderHeader` 로 헤더를 통째로 교체하면 표식도 `required` 도 그려지지 않는다** — 헤더 전체가 소비 앱 책임이 되므로 순서·크기·색을 손으로 맞추게 된다.
1086
1104
 
@@ -1765,6 +1783,8 @@ const [from, setFrom] = useState<string | null>(null);
1765
1783
 
1766
1784
  선택은 다르다. 앱이 `selectedId` 스칼라 하나를 들면 상호배제가 구조적으로 보장되고, 그 값은 URL·store 로 복원돼야 한다. 리스트가 사본을 들면 그 순간 진실이 둘이 되어 어긋난다.
1767
1785
 
1786
+ 같은 이유로 `STree` 노드의 `disabled` 는 **선택만** 막는다. 체크박스는 잠기고 전체 선택·부모 선택에서 빠지지만, 캐럿·행 클릭·키보드로 접고 펴는 것은 그대로 된다 — 부모가 disabled 라고 자식에 닿는 길까지 막지 않는다.
1787
+
1768
1788
  ```tsx
1769
1789
  const [selectedId, setSelectedId] = useState<string>();
1770
1790
 
@@ -2668,7 +2688,7 @@ export default function TransferOrderPopupPage() {
2668
2688
  - [ ] 일부 행만 고를 수 있는 표라면 `isRowSelectable` 로 잠갔는가 — 체크박스를 밖에서 직접 잠그거나 전체 선택을 손으로 보정하지 않았는가 (§3-4)
2669
2689
  - [ ] 표 본문의 스크롤이 필요하면 `onScroll` · `ref.getScrollElement()` 를 썼는가 — 내부 마크업을 겨냥한 선택자로 스크롤 컨테이너를 찾지 않았는가 (§3-4)
2670
2690
  - [ ] 스크롤 위치를 저장했다 되돌린다면 **행 번호**(`getFirstVisibleRow` → `scrollToRow`)로 했는가, `scrollTop` 픽셀을 저장하지는 않았는가 (§3-4 — 가상 스크롤에서는 좌표계가 실측으로 움직여 다른 행이 나온다)
2671
- - [ ] `editable` · `navigable` 표식을 켠 열이 **셀에서도 실제로 그렇게 동작하는가** (입력 컨트롤 · 링크가 있는가), 표식을 붙인 열의 폭을 함께 넓혔는가 (§3-4)
2691
+ - [ ] `editable` · `navigable` 표식을 켠 열이 **셀에서도 실제로 그렇게 동작하는가** (입력 컨트롤 · 링크가 있는가), **모달로 처리하는 열에 `navigable` 을 켜지는 않았는가** (화면을 떠나지 않으므로 `editable` 이다), 표식을 붙인 열의 폭을 함께 넓혔는가 (§3-4)
2672
2692
  - [ ] 금액·수량 등 양을 나타내는 숫자에 빠짐없이 `toLocaleString()` 을 썼는가 (번호·코드는 제외)
2673
2693
  - [ ] 날짜를 `YYYY-MM-DD` 로 표기했는가 (`toLocaleDateString()` ❌, §1-4)
2674
2694
  - [ ] 필드 폭을 등급(`'xs' | 'sm' | 'md' | 'lg' | 'xl'`)으로 줬는가 — px 직접 지정 ❌ (§4-3)
@@ -75,7 +75,10 @@ interface STableColumnBase {
75
75
  */
76
76
  required?: boolean;
77
77
  /**
78
- * 값을 직접 고칠 있는 열. 라벨 뒤에 `pageEdit` 표식이 붙는다.
78
+ * **지금 화면에 머문 채로** 값을 고치는 열. 라벨 뒤에 `pageEdit` 표식이 붙는다.
79
+ *
80
+ * 셀에서 바로 고치는 것도, 수정 모달·바텀시트를 띄워 고치는 것도 모두 이쪽이다 —
81
+ * 모달은 현재 화면 **위에** 겹쳐 뜰 뿐 화면을 떠나는 것이 아니라서 `navigable` 이 아니다.
79
82
  *
80
83
  * **표식일 뿐 버튼이 아니다** — 실제로 고치는 UI 는 셀(`render`)이 그린다. 표식만 켜 두면
81
84
  * 고칠 수 있다고 해 놓고 고칠 방법이 없는 열이 된다.
@@ -84,9 +87,13 @@ interface STableColumnBase {
84
87
  */
85
88
  editable?: boolean;
86
89
  /**
87
- * 셀을 눌러 다른 화면으로 넘어가는 열. 라벨 뒤에 `pageMove` 표식이 붙는다.
90
+ * 눌러서 **이 화면을 떠나** 다른 화면으로 가는 창·새 팝업으로 띄우거나 페이지를
91
+ * 이동한다. 라벨 뒤에 `pageMove` 표식이 붙는다.
92
+ *
93
+ * 모달로 처리하는 열은 화면을 떠나지 않으므로 여기에 해당하지 않는다. 모달에서 값을 고치면
94
+ * `editable`, 고치지 않고 보여주기만 하면 둘 다 붙이지 않는다.
88
95
  *
89
- * **표식일 뿐 버튼이 아니다** — 넘어가는 것은 셀(`render`)의 링크·클릭이 한다.
96
+ * **표식일 뿐 버튼이 아니다** — 화면을 여는 것은 셀(`render`)의 링크·클릭이 한다.
90
97
  *
91
98
  * `renderHeader` 로 헤더를 통째로 교체하면 그리지 않는다 (헤더 전체가 소비 앱 책임).
92
99
  */
@@ -68,7 +68,7 @@ export interface STreeNode {
68
68
  label: ReactNode;
69
69
  /** 하위 노드 */
70
70
  children?: STreeNode[];
71
- /** 비활성 상태 */
71
+ /** 선택 비활성. 체크박스만 막고 접기·펼치기는 그대로 된다 (전체 선택·부모 선택에서도 제외) */
72
72
  disabled?: boolean;
73
73
  }
74
74
  ```
@@ -7,7 +7,7 @@ export interface STreeNode {
7
7
  label: ReactNode;
8
8
  /** 하위 노드 */
9
9
  children?: STreeNode[];
10
- /** 비활성 상태 */
10
+ /** 선택 비활성. 체크박스만 막고 접기·펼치기는 그대로 된다 (전체 선택·부모 선택에서도 제외) */
11
11
  disabled?: boolean;
12
12
  }
13
13
  export interface STreeItemRenderState {
@@ -2,3 +2,5 @@ import type { STreeNode } from './STree';
2
2
  export declare const treeUsageItems: STreeNode[];
3
3
  export declare const treeUsageDefaultValue: string[];
4
4
  export declare const treeUsageExpandedIds: string[];
5
+ /** 부모가 disabled 여도 자식은 접고 펼 수 있고, 자식 중 정상 노드는 고를 수 있다 */
6
+ export declare const treeDisabledItems: STreeNode[];
package/dist/index.cjs CHANGED
@@ -7084,7 +7084,6 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7084
7084
  onTreeSelect?.(node, event);
7085
7085
  };
7086
7086
  const handleRowClick = (event) => {
7087
- if (node.disabled) return;
7088
7087
  if (hasChildren) onToggle?.(node, event);
7089
7088
  };
7090
7089
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -7101,9 +7100,8 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7101
7100
  "group/tree-item box-border flex w-full items-center gap-(--cmp-tree-item-rowGap) overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left",
7102
7101
  typography.rowHeight,
7103
7102
  border && "border-b border-(--cmp-tree-item-border-default)",
7104
- !node.disabled && "hover:bg-(--cmp-tree-item-bg-hover)",
7105
- node.disabled && "cursor-not-allowed opacity-60",
7106
- !node.disabled && hasChildren && "cursor-pointer",
7103
+ "hover:bg-(--cmp-tree-item-bg-hover)",
7104
+ hasChildren && "cursor-pointer",
7107
7105
  className
7108
7106
  ),
7109
7107
  ...rest,
@@ -7127,10 +7125,8 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7127
7125
  size: "xxs",
7128
7126
  ariaLabel: expanded ? "collapse tree item" : "expand tree item",
7129
7127
  ariaExpanded: expanded,
7130
- disabled: node.disabled,
7131
7128
  onClick: (event) => {
7132
7129
  event.stopPropagation();
7133
- if (node.disabled) return;
7134
7130
  onToggle?.(node, event);
7135
7131
  }
7136
7132
  }
@@ -7163,6 +7159,7 @@ var STreeItemImpl = /* @__PURE__ */ react.forwardRef(function STreeItem({
7163
7159
  className: cn(
7164
7160
  "block min-w-0 flex-1 truncate py-(--cmp-tree-item-paddingY) text-(--cmp-tree-item-text-default)",
7165
7161
  labelTypo,
7162
+ node.disabled && "opacity-60",
7166
7163
  node.disabled ? "cursor-not-allowed" : selectable ? "cursor-pointer" : void 0
7167
7164
  ),
7168
7165
  children: node.label
@@ -7288,13 +7285,13 @@ var STreeImpl = /* @__PURE__ */ react.forwardRef(function STree({
7288
7285
  break;
7289
7286
  }
7290
7287
  case "ArrowRight": {
7291
- if (!hasChildren || row.node.disabled) return;
7288
+ if (!hasChildren) return;
7292
7289
  if (!row.expanded) updateExpanded(row.node);
7293
7290
  else if (visibleRows[index + 1]) focusRow(visibleRows[index + 1].id);
7294
7291
  break;
7295
7292
  }
7296
7293
  case "ArrowLeft": {
7297
- if (hasChildren && row.expanded && !row.node.disabled) updateExpanded(row.node);
7294
+ if (hasChildren && row.expanded) updateExpanded(row.node);
7298
7295
  else if (row.parentId != null) focusRow(row.parentId);
7299
7296
  else return;
7300
7297
  break;
@@ -7312,7 +7309,7 @@ var STreeImpl = /* @__PURE__ */ react.forwardRef(function STree({
7312
7309
  case " ": {
7313
7310
  if (row.id === TREE_ALL_NODE.id) updateAllSelected();
7314
7311
  else if (selectable) updateSelected(row.node);
7315
- else if (hasChildren && !row.node.disabled) updateExpanded(row.node);
7312
+ else if (hasChildren) updateExpanded(row.node);
7316
7313
  else return;
7317
7314
  break;
7318
7315
  }
@@ -16265,7 +16262,7 @@ var STable = /* @__PURE__ */ react.forwardRef(function STable2({
16265
16262
  name: "pageMove",
16266
16263
  size: 12,
16267
16264
  color: "var(--sys-color-link-accent)",
16268
- label: "\uB2E4\uB978 \uD654\uBA74\uC73C\uB85C \uC774\uB3D9",
16265
+ label: "\uC0C8 \uD654\uBA74\uC5D0\uC11C \uC5F4\uAE30",
16269
16266
  className: "shrink-0"
16270
16267
  }
16271
16268
  ),