sellmate-design-system-react 2.1.1 → 2.2.0

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.
@@ -1 +1 @@
1
- export { STable, type STableProps, type STableColumn, type STablePagination, type STableStickyColumn, type STableHandle, type SRow, } from './STable';
1
+ export { STable, type STableProps, type STableColumn, type STableCellContext, type STablePagination, type STableStickyColumn, type STableHandle, type SRow, } from './STable';
package/dist/index.cjs CHANGED
@@ -4901,7 +4901,8 @@ function SConfirmModal({
4901
4901
  const mainStyle = MAIN_BUTTON_STYLE[mainButtonName ?? DEFAULT_MAIN_BUTTON[type]];
4902
4902
  const tagNode = tagSlot ?? (tagLabel ? /* @__PURE__ */ jsxRuntime.jsx(STag, { shape: tagShape, size: tagSize, color: tagColor, label: tagLabel }) : null);
4903
4903
  const optionNode = optionSlot ?? (slotLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: slotLabel }) : null);
4904
- const hasBody = topMessage.length > 0 || bottomMessage.length > 0 || tagNode != null || optionNode != null;
4904
+ const hasContentBox = tagNode != null || optionNode != null;
4905
+ const hasBody = topMessage.length > 0 || bottomMessage.length > 0 || hasContentBox;
4905
4906
  return /* @__PURE__ */ jsxRuntime.jsx(
4906
4907
  SModalContainer,
4907
4908
  {
@@ -4936,8 +4937,12 @@ function SConfirmModal({
4936
4937
  },
4937
4938
  i
4938
4939
  )) }),
4939
- tagNode != null && // tag 위치 content-box: 흰 박스 + 1px 테두리 + 패딩 + 14/700 (원본 sd-confirm-modal__content-box)
4940
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center gap-[8px] rounded-[8px] border border-solid border-[color:var(--color-grey-30)] bg-white px-[16px] py-[12px] text-[14px] font-bold leading-[22px] w-full", children: tagNode }),
4940
+ hasContentBox && // content-box: 흰 박스 + 1px 테두리 + 패딩 + 14/700 (원본 sd-confirm-modal__content-box)
4941
+ // tag 왼쪽, slotLabel/optionSlot 오른쪽에 gap 8 나란히 놓인다
4942
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-[8px] rounded-[8px] border border-solid border-[color:var(--color-grey-30)] bg-white px-[16px] py-[12px] text-[14px] font-bold leading-[22px] w-full", children: [
4943
+ tagNode,
4944
+ optionNode
4945
+ ] }),
4941
4946
  bottomMessage.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-[2px]", children: bottomMessage.map((m, i) => /* @__PURE__ */ jsxRuntime.jsx(
4942
4947
  "p",
4943
4948
  {
@@ -4945,8 +4950,7 @@ function SConfirmModal({
4945
4950
  dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(m) }
4946
4951
  },
4947
4952
  i
4948
- )) }),
4949
- optionNode != null && optionNode
4953
+ )) })
4950
4954
  ] })
4951
4955
  ] }),
4952
4956
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 gap-[8px]", children: [
@@ -7380,8 +7384,10 @@ var STable = react.forwardRef(function STable2({
7380
7384
  stickyColumn,
7381
7385
  radius = "default",
7382
7386
  noDataLabel = "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
7387
+ noDataSlot,
7383
7388
  isLoading = false,
7384
7389
  dense = false,
7390
+ noHover = false,
7385
7391
  pagination,
7386
7392
  onPageChange,
7387
7393
  useInternalPagination = false,
@@ -7467,7 +7473,10 @@ var STable = react.forwardRef(function STable2({
7467
7473
  );
7468
7474
  const handleScroll = react.useCallback(() => {
7469
7475
  const el = scrollRef.current;
7470
- if (!el) return;
7476
+ if (!el) {
7477
+ setHeaderGutter(0);
7478
+ return;
7479
+ }
7471
7480
  const header = headerScrollRef.current;
7472
7481
  if (header) header.scrollLeft = el.scrollLeft;
7473
7482
  setHeaderGutter(el.offsetWidth - el.clientWidth);
@@ -7599,6 +7608,7 @@ var STable = react.forwardRef(function STable2({
7599
7608
  bodyRows = rows.slice(pageInfo.startIndex, pageInfo.endIndex);
7600
7609
  }
7601
7610
  const isNoData = rowCount === 0 && !isLoading;
7611
+ const showNoDataSlot = isNoData && noDataSlot != null;
7602
7612
  const showPagination = !useVirtualScroll && (pagination != null || useInternalPagination);
7603
7613
  const lastPage = useInternalPagination ? Math.max(1, Math.ceil(rowCount / (innerRowsPerPage || 1))) : pagination?.lastPage ?? Math.max(1, Math.ceil(rowCount / (pagination?.rowsPerPage ?? 10)));
7604
7614
  const displayPage = useInternalPagination ? currentPage : pagination?.page ?? 1;
@@ -7660,6 +7670,12 @@ var STable = react.forwardRef(function STable2({
7660
7670
  isRightEdge && scrolledRight && "shadow-[-5px_0_8px_0_rgba(34,34,34,0.1)]"
7661
7671
  );
7662
7672
  };
7673
+ const bodyScrollClass = cn(
7674
+ "min-h-0 flex-1 overflow-auto border-t border-solid border-[color:var(--cmp-table-border-color)]",
7675
+ SCROLLBAR_CLASS,
7676
+ SCROLLBAR_TRACK_BG_CLASS,
7677
+ SCROLLBAR_TRACK_BORDER_CLASS
7678
+ );
7663
7679
  const colgroup = /* @__PURE__ */ jsxRuntime.jsxs("colgroup", { children: [
7664
7680
  selectable && /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: SELECTABLE_COLUMN_WIDTH } }),
7665
7681
  visibleCols.map((col, i) => /* @__PURE__ */ jsxRuntime.jsx("col", { style: col.autoWidth ? void 0 : { width: columnWidths[i] } }, col.name))
@@ -7781,97 +7797,106 @@ var STable = react.forwardRef(function STable2({
7781
7797
  )
7782
7798
  }
7783
7799
  ),
7784
- /* @__PURE__ */ jsxRuntime.jsx(
7785
- "div",
7786
- {
7787
- ref: scrollRef,
7788
- onScroll: handleScroll,
7789
- className: cn(
7790
- // 헤더 하단 구분선은 body 상단 border로 그린다. body 래퍼는 스크롤바를 포함한
7791
- // 전체 폭을 차지하므로(스크롤바는 border 안쪽) 헤더 거터의 border-right와 미터가
7792
- // 생기지 않아 색·길이가 균일한 한 줄이 된다.
7793
- "min-h-0 flex-1 overflow-auto border-t border-solid border-[color:var(--cmp-table-border-color)]",
7794
- SCROLLBAR_CLASS,
7795
- SCROLLBAR_TRACK_BG_CLASS,
7796
- SCROLLBAR_TRACK_BORDER_CLASS,
7797
- // 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 스크롤 차단
7798
- (isLoading || rowCount === 0) && "overflow-hidden"
7799
- ),
7800
- children: /* @__PURE__ */ jsxRuntime.jsxs(
7801
- "table",
7802
- {
7803
- className: "w-full table-fixed border-separate border-spacing-0 text-left",
7804
- style: { fontSize: 12 },
7805
- children: [
7806
- colgroup,
7807
- /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
7808
- useVirtualScroll && topSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: topSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) }),
7809
- rowCount === 0 ? null : bodyRows.map((row, ri) => {
7810
- const isSel = selectedKeys.has(row[rowKey]);
7811
- const rowBg = "bg-white";
7812
- return /* @__PURE__ */ jsxRuntime.jsxs(
7813
- "tr",
7814
- {
7815
- onClick: () => onRowClick?.(row),
7816
- className: cn(
7817
- "group/table-row hover:bg-[var(--color-grey-05)]",
7818
- onRowClick && "cursor-pointer"
7819
- ),
7820
- style: { height: useVirtualScroll ? effectiveRowHeight : rowH },
7821
- children: [
7822
- selectable && /* @__PURE__ */ jsxRuntime.jsx(
7823
- "td",
7824
- {
7825
- className: cn(
7826
- // 원본 .td--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
7827
- "sticky left-0 z-[2] border-b border-solid border-[color:var(--cmp-table-border-color)] align-middle group-hover/table-row:bg-[var(--color-grey-05)]",
7828
- rowBg,
7829
- stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
7830
- ),
7831
- style: {
7832
- width: SELECTABLE_COLUMN_WIDTH,
7833
- minWidth: SELECTABLE_COLUMN_WIDTH,
7834
- maxWidth: SELECTABLE_COLUMN_WIDTH
7835
- },
7836
- onClick: (e) => e.stopPropagation(),
7837
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SCheckbox, { value: isSel, onValueChange: () => toggleRow(row) }) })
7838
- }
7800
+ showNoDataSlot ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(bodyScrollClass, "pointer-events-auto bg-white"), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full min-h-[60px] w-full items-center justify-center", children: noDataSlot }) }) : (
7801
+ /* 바디: 세로 스크롤은 이 컨테이너에만 생긴다 (헤더 제외) */
7802
+ /* @__PURE__ */ jsxRuntime.jsx(
7803
+ "div",
7804
+ {
7805
+ ref: scrollRef,
7806
+ onScroll: handleScroll,
7807
+ className: cn(
7808
+ bodyScrollClass,
7809
+ // 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 스크롤 차단
7810
+ (isLoading || rowCount === 0) && "overflow-hidden"
7811
+ ),
7812
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
7813
+ "table",
7814
+ {
7815
+ className: "w-full table-fixed border-separate border-spacing-0 text-left",
7816
+ style: { fontSize: 12 },
7817
+ children: [
7818
+ colgroup,
7819
+ /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
7820
+ useVirtualScroll && topSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: topSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) }),
7821
+ rowCount === 0 ? null : bodyRows.map((row, ri) => {
7822
+ const isSel = selectedKeys.has(row[rowKey]);
7823
+ const rowBg = "bg-white";
7824
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7825
+ "tr",
7826
+ {
7827
+ onClick: () => onRowClick?.(row),
7828
+ className: cn(
7829
+ "group/table-row",
7830
+ !noHover && "hover:bg-[var(--color-grey-05)]",
7831
+ onRowClick && "cursor-pointer"
7839
7832
  ),
7840
- visibleCols.map((col, i) => /* @__PURE__ */ jsxRuntime.jsx(
7841
- "td",
7842
- {
7843
- className: cn(
7833
+ style: { height: useVirtualScroll ? effectiveRowHeight : rowH },
7834
+ children: [
7835
+ selectable && /* @__PURE__ */ jsxRuntime.jsx(
7836
+ "td",
7837
+ {
7838
+ className: cn(
7839
+ // 원본 .td--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
7840
+ "sticky left-0 z-[2] border-b border-solid border-[color:var(--cmp-table-border-color)] align-middle",
7841
+ rowBg,
7842
+ !noHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
7843
+ stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
7844
+ ),
7845
+ style: {
7846
+ width: SELECTABLE_COLUMN_WIDTH,
7847
+ minWidth: SELECTABLE_COLUMN_WIDTH,
7848
+ maxWidth: SELECTABLE_COLUMN_WIDTH
7849
+ },
7850
+ onClick: (e) => e.stopPropagation(),
7851
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SCheckbox, { value: isSel, onValueChange: () => toggleRow(row) }) })
7852
+ }
7853
+ ),
7854
+ visibleCols.map((col, i) => {
7855
+ const tdClassName = cn(
7844
7856
  // 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
7845
7857
  // 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
7846
7858
  "overflow-hidden text-ellipsis whitespace-nowrap border-b border-solid border-[color:var(--cmp-table-border-color)] text-[12px] leading-[20px] text-[color:var(--sys-color-fg-primary)]",
7847
7859
  rowBg,
7848
- "group-hover/table-row:bg-[var(--color-grey-05)]",
7860
+ !noHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
7849
7861
  stickyShadowClass(i),
7850
7862
  typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
7851
- ),
7852
- style: {
7863
+ );
7864
+ const tdStyle = {
7853
7865
  paddingLeft: cellPadX,
7854
7866
  paddingRight: cellPadX,
7855
7867
  paddingTop: cellPadY,
7856
7868
  paddingBottom: cellPadY,
7857
7869
  textAlign: col.align ?? "left",
7858
7870
  ...cellStyle(i)
7859
- },
7860
- children: col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row)
7861
- },
7862
- col.name
7863
- ))
7864
- ]
7865
- },
7866
- row[rowKey] ?? ri
7867
- );
7868
- }),
7869
- useVirtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
7870
- ] })
7871
- ]
7872
- }
7873
- )
7874
- }
7871
+ };
7872
+ if (col.renderCell) {
7873
+ const cell = col.renderCell({
7874
+ row,
7875
+ value: cellValue(col, row),
7876
+ column: col,
7877
+ colIndex: i,
7878
+ rowIndex: ri,
7879
+ isSelected: isSel,
7880
+ className: tdClassName,
7881
+ style: tdStyle
7882
+ });
7883
+ if (cell == null || cell === false) return null;
7884
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: cell }, col.name);
7885
+ }
7886
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { className: tdClassName, style: tdStyle, children: col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row) }, col.name);
7887
+ })
7888
+ ]
7889
+ },
7890
+ row[rowKey] ?? ri
7891
+ );
7892
+ }),
7893
+ useVirtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
7894
+ ] })
7895
+ ]
7896
+ }
7897
+ )
7898
+ }
7899
+ )
7875
7900
  ),
7876
7901
  isNoData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7877
7902
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -7881,7 +7906,7 @@ var STable = react.forwardRef(function STable2({
7881
7906
  className: "pointer-events-none absolute left-0 right-0 top-0 z-[31] h-[var(--cmp-table-header-height)] bg-white/60"
7882
7907
  }
7883
7908
  ),
7884
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-0 left-0 right-0 top-[var(--cmp-table-header-height)] z-[30] flex items-center justify-center bg-white/60 text-[12px] text-[color:var(--color-grey-65)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[60px] w-full items-center justify-center", children: noDataLabel }) })
7909
+ !showNoDataSlot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-0 left-0 right-0 top-[var(--cmp-table-header-height)] z-[30] flex items-center justify-center bg-white/60 text-[12px] text-[color:var(--color-grey-65)]", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[60px] w-full items-center justify-center", children: noDataLabel }) })
7885
7910
  ] }),
7886
7911
  isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-30 flex items-center justify-center bg-white/60", children: /* @__PURE__ */ jsxRuntime.jsx(SCircleProgress, { indeterminate: true }) })
7887
7912
  ]