sellmate-design-system-react 2.1.2 → 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
@@ -7384,8 +7384,10 @@ var STable = react.forwardRef(function STable2({
7384
7384
  stickyColumn,
7385
7385
  radius = "default",
7386
7386
  noDataLabel = "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
7387
+ noDataSlot,
7387
7388
  isLoading = false,
7388
7389
  dense = false,
7390
+ noHover = false,
7389
7391
  pagination,
7390
7392
  onPageChange,
7391
7393
  useInternalPagination = false,
@@ -7471,7 +7473,10 @@ var STable = react.forwardRef(function STable2({
7471
7473
  );
7472
7474
  const handleScroll = react.useCallback(() => {
7473
7475
  const el = scrollRef.current;
7474
- if (!el) return;
7476
+ if (!el) {
7477
+ setHeaderGutter(0);
7478
+ return;
7479
+ }
7475
7480
  const header = headerScrollRef.current;
7476
7481
  if (header) header.scrollLeft = el.scrollLeft;
7477
7482
  setHeaderGutter(el.offsetWidth - el.clientWidth);
@@ -7603,6 +7608,7 @@ var STable = react.forwardRef(function STable2({
7603
7608
  bodyRows = rows.slice(pageInfo.startIndex, pageInfo.endIndex);
7604
7609
  }
7605
7610
  const isNoData = rowCount === 0 && !isLoading;
7611
+ const showNoDataSlot = isNoData && noDataSlot != null;
7606
7612
  const showPagination = !useVirtualScroll && (pagination != null || useInternalPagination);
7607
7613
  const lastPage = useInternalPagination ? Math.max(1, Math.ceil(rowCount / (innerRowsPerPage || 1))) : pagination?.lastPage ?? Math.max(1, Math.ceil(rowCount / (pagination?.rowsPerPage ?? 10)));
7608
7614
  const displayPage = useInternalPagination ? currentPage : pagination?.page ?? 1;
@@ -7664,6 +7670,12 @@ var STable = react.forwardRef(function STable2({
7664
7670
  isRightEdge && scrolledRight && "shadow-[-5px_0_8px_0_rgba(34,34,34,0.1)]"
7665
7671
  );
7666
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
+ );
7667
7679
  const colgroup = /* @__PURE__ */ jsxRuntime.jsxs("colgroup", { children: [
7668
7680
  selectable && /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: SELECTABLE_COLUMN_WIDTH } }),
7669
7681
  visibleCols.map((col, i) => /* @__PURE__ */ jsxRuntime.jsx("col", { style: col.autoWidth ? void 0 : { width: columnWidths[i] } }, col.name))
@@ -7785,97 +7797,106 @@ var STable = react.forwardRef(function STable2({
7785
7797
  )
7786
7798
  }
7787
7799
  ),
7788
- /* @__PURE__ */ jsxRuntime.jsx(
7789
- "div",
7790
- {
7791
- ref: scrollRef,
7792
- onScroll: handleScroll,
7793
- className: cn(
7794
- // 헤더 하단 구분선은 body 상단 border로 그린다. body 래퍼는 스크롤바를 포함한
7795
- // 전체 폭을 차지하므로(스크롤바는 border 안쪽) 헤더 거터의 border-right와 미터가
7796
- // 생기지 않아 색·길이가 균일한 한 줄이 된다.
7797
- "min-h-0 flex-1 overflow-auto border-t border-solid border-[color:var(--cmp-table-border-color)]",
7798
- SCROLLBAR_CLASS,
7799
- SCROLLBAR_TRACK_BG_CLASS,
7800
- SCROLLBAR_TRACK_BORDER_CLASS,
7801
- // 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 스크롤 차단
7802
- (isLoading || rowCount === 0) && "overflow-hidden"
7803
- ),
7804
- children: /* @__PURE__ */ jsxRuntime.jsxs(
7805
- "table",
7806
- {
7807
- className: "w-full table-fixed border-separate border-spacing-0 text-left",
7808
- style: { fontSize: 12 },
7809
- children: [
7810
- colgroup,
7811
- /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
7812
- useVirtualScroll && topSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: topSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) }),
7813
- rowCount === 0 ? null : bodyRows.map((row, ri) => {
7814
- const isSel = selectedKeys.has(row[rowKey]);
7815
- const rowBg = "bg-white";
7816
- return /* @__PURE__ */ jsxRuntime.jsxs(
7817
- "tr",
7818
- {
7819
- onClick: () => onRowClick?.(row),
7820
- className: cn(
7821
- "group/table-row hover:bg-[var(--color-grey-05)]",
7822
- onRowClick && "cursor-pointer"
7823
- ),
7824
- style: { height: useVirtualScroll ? effectiveRowHeight : rowH },
7825
- children: [
7826
- selectable && /* @__PURE__ */ jsxRuntime.jsx(
7827
- "td",
7828
- {
7829
- className: cn(
7830
- // 원본 .td--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
7831
- "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)]",
7832
- rowBg,
7833
- stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
7834
- ),
7835
- style: {
7836
- width: SELECTABLE_COLUMN_WIDTH,
7837
- minWidth: SELECTABLE_COLUMN_WIDTH,
7838
- maxWidth: SELECTABLE_COLUMN_WIDTH
7839
- },
7840
- onClick: (e) => e.stopPropagation(),
7841
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SCheckbox, { value: isSel, onValueChange: () => toggleRow(row) }) })
7842
- }
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"
7843
7832
  ),
7844
- visibleCols.map((col, i) => /* @__PURE__ */ jsxRuntime.jsx(
7845
- "td",
7846
- {
7847
- 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(
7848
7856
  // 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
7849
7857
  // 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
7850
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)]",
7851
7859
  rowBg,
7852
- "group-hover/table-row:bg-[var(--color-grey-05)]",
7860
+ !noHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
7853
7861
  stickyShadowClass(i),
7854
7862
  typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
7855
- ),
7856
- style: {
7863
+ );
7864
+ const tdStyle = {
7857
7865
  paddingLeft: cellPadX,
7858
7866
  paddingRight: cellPadX,
7859
7867
  paddingTop: cellPadY,
7860
7868
  paddingBottom: cellPadY,
7861
7869
  textAlign: col.align ?? "left",
7862
7870
  ...cellStyle(i)
7863
- },
7864
- children: col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row)
7865
- },
7866
- col.name
7867
- ))
7868
- ]
7869
- },
7870
- row[rowKey] ?? ri
7871
- );
7872
- }),
7873
- useVirtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
7874
- ] })
7875
- ]
7876
- }
7877
- )
7878
- }
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
+ )
7879
7900
  ),
7880
7901
  isNoData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7881
7902
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -7885,7 +7906,7 @@ var STable = react.forwardRef(function STable2({
7885
7906
  className: "pointer-events-none absolute left-0 right-0 top-0 z-[31] h-[var(--cmp-table-header-height)] bg-white/60"
7886
7907
  }
7887
7908
  ),
7888
- /* @__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 }) })
7889
7910
  ] }),
7890
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 }) })
7891
7912
  ]