sellmate-design-system-react 1.1.1 → 1.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.
Files changed (58) hide show
  1. package/dist/components/SActionModal/SActionModal.cjs +7 -0
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.d.ts +1 -0
  4. package/dist/components/SActionModal/SActionModal.js +8 -1
  5. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  6. package/dist/components/SConfirmModal/SConfirmModal.cjs +6 -0
  7. package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
  8. package/dist/components/SConfirmModal/SConfirmModal.js +7 -1
  9. package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
  10. package/dist/components/SGnb/SGnb.cjs.map +1 -1
  11. package/dist/components/SGnb/SGnb.js.map +1 -1
  12. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +2 -2
  13. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  14. package/dist/components/SKeyValueTable/SKeyValueTable.js +2 -2
  15. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  16. package/dist/components/SLoadingModal/SLoadingModal.cjs +6 -0
  17. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  18. package/dist/components/SLoadingModal/SLoadingModal.js +7 -1
  19. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  20. package/dist/components/SModal/SModal.cjs +6 -0
  21. package/dist/components/SModal/SModal.cjs.map +1 -1
  22. package/dist/components/SModal/SModal.js +6 -0
  23. package/dist/components/SModal/SModal.js.map +1 -1
  24. package/dist/components/SModalContainer/SModalContainer.cjs +6 -0
  25. package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
  26. package/dist/components/SModalContainer/SModalContainer.js +7 -1
  27. package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
  28. package/dist/components/SPage/SPage.cjs +3 -3
  29. package/dist/components/SPage/SPage.cjs.map +1 -1
  30. package/dist/components/SPage/SPage.js +3 -3
  31. package/dist/components/SPage/SPage.js.map +1 -1
  32. package/dist/components/SPopup/SPopup.cjs +2 -2
  33. package/dist/components/SPopup/SPopup.cjs.map +1 -1
  34. package/dist/components/SPopup/SPopup.js +2 -2
  35. package/dist/components/SPopup/SPopup.js.map +1 -1
  36. package/dist/components/SScrollArea/SScrollArea.cjs +2 -2
  37. package/dist/components/SScrollArea/SScrollArea.cjs.map +1 -1
  38. package/dist/components/SScrollArea/SScrollArea.js +2 -2
  39. package/dist/components/SScrollArea/SScrollArea.js.map +1 -1
  40. package/dist/components/SSelect/SSelect.cjs +2 -2
  41. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  42. package/dist/components/SSelect/SSelect.js +2 -2
  43. package/dist/components/SSelect/SSelect.js.map +1 -1
  44. package/dist/components/STable/STable.cjs +137 -95
  45. package/dist/components/STable/STable.cjs.map +1 -1
  46. package/dist/components/STable/STable.d.ts +1 -1
  47. package/dist/components/STable/STable.js +137 -95
  48. package/dist/components/STable/STable.js.map +1 -1
  49. package/dist/index.cjs +145 -96
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.js +145 -96
  52. package/dist/index.js.map +1 -1
  53. package/dist/lib/scrollbar.cjs +3 -3
  54. package/dist/lib/scrollbar.cjs.map +1 -1
  55. package/dist/lib/scrollbar.js +3 -3
  56. package/dist/lib/scrollbar.js.map +1 -1
  57. package/dist/styles.css +33 -3
  58. package/package.json +1 -1
@@ -75,7 +75,7 @@ export interface STableProps {
75
75
  resizable?: boolean;
76
76
  width?: string;
77
77
  height?: string;
78
- /** 헤더 고정 */
78
+ /** @deprecated 헤더는 항상 세로 스크롤에서 제외되어 고정됩니다 (body만 세로 스크롤) */
79
79
  stickyHeader?: boolean;
80
80
  /** 고정할 좌/우 컬럼 수 */
81
81
  stickyColumn?: STableStickyColumn;
@@ -20,8 +20,8 @@ function cn(...inputs) {
20
20
  // src/lib/scrollbar.ts
21
21
  var FIREFOX_SCROLLBAR_CLASS = "supports-[not_selector(::-webkit-scrollbar)]:[scrollbar-width:thin] supports-[not_selector(::-webkit-scrollbar)]:[scrollbar-color:var(--color-grey-45)_transparent]";
22
22
  var SCROLLBAR_CLASS = `${FIREFOX_SCROLLBAR_CLASS} [&::-webkit-scrollbar]:h-[12px] [&::-webkit-scrollbar]:w-[12px] [&::-webkit-scrollbar]:bg-transparent [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:border-2 [&::-webkit-scrollbar-thumb]:border-solid [&::-webkit-scrollbar-thumb]:border-transparent [&::-webkit-scrollbar-thumb]:bg-[var(--color-grey-45)] [&::-webkit-scrollbar-thumb]:bg-clip-padding`;
23
- var SCROLLBAR_TRACK_BG_CLASS = "supports-[not_selector(::-webkit-scrollbar)]:[scrollbar-color:var(--color-grey-45)_var(--color-grey-10)] [&::-webkit-scrollbar]:bg-[var(--color-grey-10)] [&::-webkit-scrollbar-track]:bg-[var(--color-grey-10)]";
24
- var SCROLLBAR_TRACK_BORDER_CLASS = "[&::-webkit-scrollbar-track:vertical]:[border-left:1px_solid_var(--sys-color-border-default)] [&::-webkit-scrollbar-track:horizontal]:[border-top:1px_solid_var(--sys-color-border-default)] [&::-webkit-scrollbar-thumb:vertical]:[border-left-width:3px] [&::-webkit-scrollbar-thumb:horizontal]:[border-top-width:3px]";
23
+ var SCROLLBAR_TRACK_BG_CLASS = "supports-[not_selector(::-webkit-scrollbar)]:[scrollbar-color:var(--color-grey-45)_var(--color-grey-10)] [&::-webkit-scrollbar]:bg-[var(--color-grey-10)] [&::-webkit-scrollbar-track]:bg-[var(--color-grey-10)] [&::-webkit-scrollbar-corner]:bg-[var(--color-grey-10)]";
24
+ var SCROLLBAR_TRACK_BORDER_CLASS = "[&::-webkit-scrollbar-track:vertical]:[border-left:1px_solid_var(--sys-color-border-default)] [&::-webkit-scrollbar-track:horizontal]:[border-top:1px_solid_var(--sys-color-border-default)] [&::-webkit-scrollbar-corner]:[border-top:1px_solid_var(--sys-color-border-default)] [&::-webkit-scrollbar-corner]:[border-left:1px_solid_var(--sys-color-border-default)] [&::-webkit-scrollbar-thumb:vertical]:[border-left-width:3px] [&::-webkit-scrollbar-thumb:horizontal]:[border-top-width:3px]";
25
25
 
26
26
  // src/lib/color.ts
27
27
  var COLOR_KEYS = [
@@ -4505,7 +4505,6 @@ var STable = forwardRef(function STable2({
4505
4505
  resizable = false,
4506
4506
  width,
4507
4507
  height,
4508
- stickyHeader = false,
4509
4508
  stickyColumn,
4510
4509
  radius = "default",
4511
4510
  noDataLabel = "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
@@ -4571,6 +4570,8 @@ var STable = forwardRef(function STable2({
4571
4570
  const [rowCountOverride, setRowCountOverride] = useState(null);
4572
4571
  const rowCount = rowCountOverride ?? rows.length;
4573
4572
  const scrollRef = useRef(null);
4573
+ const headerScrollRef = useRef(null);
4574
+ const [headerGutter, setHeaderGutter] = useState(0);
4574
4575
  const [vsRange, setVsRange] = useState({ start: 0, end: 0 });
4575
4576
  const lastReachEndRef = useRef(-1);
4576
4577
  const cbRef = useRef({ onVirtualUpdate, onVirtualReachEnd });
@@ -4595,6 +4596,9 @@ var STable = forwardRef(function STable2({
4595
4596
  const handleScroll = useCallback(() => {
4596
4597
  const el = scrollRef.current;
4597
4598
  if (!el) return;
4599
+ const header = headerScrollRef.current;
4600
+ if (header) header.scrollLeft = el.scrollLeft;
4601
+ setHeaderGutter(el.offsetWidth - el.clientWidth);
4598
4602
  setScrolledLeft(el.scrollLeft > 0);
4599
4603
  setScrolledRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
4600
4604
  if (useVirtualScroll) {
@@ -4604,7 +4608,7 @@ var STable = forwardRef(function STable2({
4604
4608
  }, [useVirtualScroll, calcRange]);
4605
4609
  useEffect(() => {
4606
4610
  handleScroll();
4607
- }, [handleScroll, rowCount, columnWidths]);
4611
+ }, [handleScroll, rowCount, columnWidths, isLoading, height]);
4608
4612
  useEffect(() => {
4609
4613
  if (!useVirtualScroll) return;
4610
4614
  cbRef.current.onVirtualUpdate?.({ from: vsRange.start, to: vsRange.end });
@@ -4784,6 +4788,10 @@ var STable = forwardRef(function STable2({
4784
4788
  isRightEdge && scrolledRight && "shadow-[-5px_0_8px_0_rgba(34,34,34,0.1)]"
4785
4789
  );
4786
4790
  };
4791
+ const colgroup = /* @__PURE__ */ jsxs("colgroup", { children: [
4792
+ selectable && /* @__PURE__ */ jsx("col", { style: { width: SELECTABLE_COLUMN_WIDTH } }),
4793
+ visibleCols.map((col, i) => /* @__PURE__ */ jsx("col", { style: col.autoWidth ? void 0 : { width: columnWidths[i] } }, col.name))
4794
+ ] });
4787
4795
  return /* @__PURE__ */ jsxs(
4788
4796
  "div",
4789
4797
  {
@@ -4794,42 +4802,45 @@ var STable = forwardRef(function STable2({
4794
4802
  /* @__PURE__ */ jsxs(
4795
4803
  "div",
4796
4804
  {
4797
- ref: scrollRef,
4798
- onScroll: handleScroll,
4799
4805
  className: cn(
4800
- "bg-white relative overflow-auto border border-solid border-[color:var(--cmp-table-border-color)]",
4801
- SCROLLBAR_CLASS,
4802
- SCROLLBAR_TRACK_BG_CLASS,
4803
- SCROLLBAR_TRACK_BORDER_CLASS,
4806
+ "bg-white relative flex flex-col overflow-hidden border border-solid border-[color:var(--cmp-table-border-color)]",
4807
+ // height가 없으면 루트가 받은 높이를 끝까지 채운다. 호스트가 className으로
4808
+ // `flex-1 min-h-0` 등을 줘 루트 높이가 확정된 경우, 행이 적어도 테두리 박스가
4809
+ // 남은 영역을 그대로 차지한다. basis는 auto로 둬 높이가 확정되지 않은
4810
+ // 기본 사용(내용만큼 커지는 케이스)에서는 동작이 바뀌지 않는다.
4811
+ !height && "min-h-0 grow",
4804
4812
  radiusClass,
4805
- // 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 스크롤·인터랙션 차단
4806
- (isLoading || rowCount === 0) && "overflow-hidden pointer-events-none"
4813
+ // 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 인터랙션 차단
4814
+ (isLoading || rowCount === 0) && "pointer-events-none"
4807
4815
  ),
4808
4816
  style: {
4809
4817
  height,
4810
4818
  minHeight: isNoData ? "calc(var(--cmp-table-header-height) + 60px)" : void 0
4811
4819
  },
4812
4820
  children: [
4813
- /* @__PURE__ */ jsxs(
4814
- "table",
4821
+ /* @__PURE__ */ jsx(
4822
+ "div",
4815
4823
  {
4816
- className: "w-full table-fixed border-separate border-spacing-0 text-left",
4817
- style: { fontSize: 12 },
4818
- children: [
4819
- /* @__PURE__ */ jsx("thead", { className: cn(isNoData && "opacity-40"), children: /* @__PURE__ */ jsxs(
4820
- "tr",
4821
- {
4822
- className: cn(
4823
- "h-[var(--cmp-table-header-height)] bg-[var(--cmp-table-header-bg)]",
4824
- stickyHeader && "sticky top-0 z-20"
4825
- ),
4826
- children: [
4824
+ ref: headerScrollRef,
4825
+ className: "flex-none overflow-hidden",
4826
+ style: {
4827
+ borderRight: headerGutter ? `${headerGutter}px solid var(--cmp-table-header-bg)` : void 0
4828
+ },
4829
+ children: /* @__PURE__ */ jsxs(
4830
+ "table",
4831
+ {
4832
+ className: "w-full table-fixed border-separate border-spacing-0 text-left",
4833
+ style: { fontSize: 12 },
4834
+ children: [
4835
+ colgroup,
4836
+ /* @__PURE__ */ jsx("thead", { className: cn(isNoData && "opacity-40"), children: /* @__PURE__ */ jsxs("tr", { className: "h-[var(--cmp-table-header-height)] bg-[var(--cmp-table-header-bg)]", children: [
4827
4837
  selectable && /* @__PURE__ */ jsxs(
4828
4838
  "th",
4829
4839
  {
4830
4840
  className: cn(
4831
4841
  // 원본 .th--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
4832
- "sticky left-0 z-[7] border-b border-solid border-[color:var(--cmp-table-border-color)] bg-[var(--cmp-table-header-bg)] text-center align-middle",
4842
+ // 하단 border 헤더 래퍼가 연속으로 그리므로 셀에는 두지 않는다.
4843
+ "sticky left-0 z-[7] bg-[var(--cmp-table-header-bg)] text-center align-middle",
4833
4844
  stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
4834
4845
  ),
4835
4846
  style: {
@@ -4853,7 +4864,8 @@ var STable = forwardRef(function STable2({
4853
4864
  "th",
4854
4865
  {
4855
4866
  className: cn(
4856
- "relative border-b border-solid border-[color:var(--cmp-table-border-color)] bg-[var(--cmp-table-header-bg)] px-[16px] text-[12px] font-medium leading-[20px] text-[color:var(--sys-color-fg-primary)]",
4867
+ // 하단 border 헤더 래퍼가 연속으로 그린다 (거터 영역까지 이어짐).
4868
+ "relative bg-[var(--cmp-table-header-bg)] px-[16px] text-[12px] font-medium leading-[20px] text-[color:var(--sys-color-fg-primary)]",
4857
4869
  stickyInfo(i).isSticky && "z-[6]",
4858
4870
  stickyShadowClass(i),
4859
4871
  col.thClass
@@ -4891,74 +4903,102 @@ var STable = forwardRef(function STable2({
4891
4903
  },
4892
4904
  col.name
4893
4905
  ))
4894
- ]
4895
- }
4896
- ) }),
4897
- /* @__PURE__ */ jsxs("tbody", { children: [
4898
- useVirtualScroll && topSpacer > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": true, style: { height: topSpacer }, children: /* @__PURE__ */ jsx("td", { colSpan: totalColSpan, className: "p-0" }) }),
4899
- rowCount === 0 ? null : bodyRows.map((row, ri) => {
4900
- const isSel = selectedKeys.has(row[rowKey]);
4901
- const rowBg = "bg-white";
4902
- return /* @__PURE__ */ jsxs(
4903
- "tr",
4904
- {
4905
- onClick: () => onRowClick?.(row),
4906
- className: cn(
4907
- "group/table-row hover:bg-[var(--color-grey-05)]",
4908
- onRowClick && "cursor-pointer"
4909
- ),
4910
- style: { height: useVirtualScroll ? effectiveRowHeight : rowH },
4911
- children: [
4912
- selectable && /* @__PURE__ */ jsx(
4913
- "td",
4914
- {
4915
- className: cn(
4916
- // 원본 .td--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
4917
- "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)]",
4918
- rowBg,
4919
- stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
4920
- ),
4921
- style: {
4922
- width: SELECTABLE_COLUMN_WIDTH,
4923
- minWidth: SELECTABLE_COLUMN_WIDTH,
4924
- maxWidth: SELECTABLE_COLUMN_WIDTH
4925
- },
4926
- onClick: (e) => e.stopPropagation(),
4927
- children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(SCheckbox, { value: isSel, onValueChange: () => toggleRow(row) }) })
4928
- }
4929
- ),
4930
- visibleCols.map((col, i) => /* @__PURE__ */ jsx(
4931
- "td",
4932
- {
4933
- className: cn(
4934
- // 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
4935
- // 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
4936
- "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)]",
4937
- rowBg,
4938
- "group-hover/table-row:bg-[var(--color-grey-05)]",
4939
- stickyShadowClass(i),
4940
- typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
4906
+ ] }) })
4907
+ ]
4908
+ }
4909
+ )
4910
+ }
4911
+ ),
4912
+ /* @__PURE__ */ jsx(
4913
+ "div",
4914
+ {
4915
+ ref: scrollRef,
4916
+ onScroll: handleScroll,
4917
+ className: cn(
4918
+ // 헤더 하단 구분선은 body 상단 border로 그린다. body 래퍼는 스크롤바를 포함한
4919
+ // 전체 폭을 차지하므로(스크롤바는 border 안쪽) 헤더 거터의 border-right와 미터가
4920
+ // 생기지 않아 색·길이가 균일한 한 줄이 된다.
4921
+ "min-h-0 flex-1 overflow-auto border-t border-solid border-[color:var(--cmp-table-border-color)]",
4922
+ SCROLLBAR_CLASS,
4923
+ SCROLLBAR_TRACK_BG_CLASS,
4924
+ SCROLLBAR_TRACK_BORDER_CLASS,
4925
+ // 원본 sd-table__scroll-container--loading/--no-data: 로딩·데이터 없음 시 스크롤 차단
4926
+ (isLoading || rowCount === 0) && "overflow-hidden"
4927
+ ),
4928
+ children: /* @__PURE__ */ jsxs(
4929
+ "table",
4930
+ {
4931
+ className: "w-full table-fixed border-separate border-spacing-0 text-left",
4932
+ style: { fontSize: 12 },
4933
+ children: [
4934
+ colgroup,
4935
+ /* @__PURE__ */ jsxs("tbody", { children: [
4936
+ useVirtualScroll && topSpacer > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": true, style: { height: topSpacer }, children: /* @__PURE__ */ jsx("td", { colSpan: totalColSpan, className: "p-0" }) }),
4937
+ rowCount === 0 ? null : bodyRows.map((row, ri) => {
4938
+ const isSel = selectedKeys.has(row[rowKey]);
4939
+ const rowBg = "bg-white";
4940
+ return /* @__PURE__ */ jsxs(
4941
+ "tr",
4942
+ {
4943
+ onClick: () => onRowClick?.(row),
4944
+ className: cn(
4945
+ "group/table-row hover:bg-[var(--color-grey-05)]",
4946
+ onRowClick && "cursor-pointer"
4947
+ ),
4948
+ style: { height: useVirtualScroll ? effectiveRowHeight : rowH },
4949
+ children: [
4950
+ selectable && /* @__PURE__ */ jsx(
4951
+ "td",
4952
+ {
4953
+ className: cn(
4954
+ // 원본 .td--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
4955
+ "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)]",
4956
+ rowBg,
4957
+ stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
4958
+ ),
4959
+ style: {
4960
+ width: SELECTABLE_COLUMN_WIDTH,
4961
+ minWidth: SELECTABLE_COLUMN_WIDTH,
4962
+ maxWidth: SELECTABLE_COLUMN_WIDTH
4963
+ },
4964
+ onClick: (e) => e.stopPropagation(),
4965
+ children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(SCheckbox, { value: isSel, onValueChange: () => toggleRow(row) }) })
4966
+ }
4941
4967
  ),
4942
- style: {
4943
- paddingLeft: cellPadX,
4944
- paddingRight: cellPadX,
4945
- paddingTop: cellPadY,
4946
- paddingBottom: cellPadY,
4947
- textAlign: col.align ?? "left",
4948
- ...cellStyle(i)
4949
- },
4950
- children: col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row)
4951
- },
4952
- col.name
4953
- ))
4954
- ]
4955
- },
4956
- row[rowKey] ?? ri
4957
- );
4958
- }),
4959
- useVirtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
4960
- ] })
4961
- ]
4968
+ visibleCols.map((col, i) => /* @__PURE__ */ jsx(
4969
+ "td",
4970
+ {
4971
+ className: cn(
4972
+ // 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
4973
+ // 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
4974
+ "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)]",
4975
+ rowBg,
4976
+ "group-hover/table-row:bg-[var(--color-grey-05)]",
4977
+ stickyShadowClass(i),
4978
+ typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
4979
+ ),
4980
+ style: {
4981
+ paddingLeft: cellPadX,
4982
+ paddingRight: cellPadX,
4983
+ paddingTop: cellPadY,
4984
+ paddingBottom: cellPadY,
4985
+ textAlign: col.align ?? "left",
4986
+ ...cellStyle(i)
4987
+ },
4988
+ children: col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row)
4989
+ },
4990
+ col.name
4991
+ ))
4992
+ ]
4993
+ },
4994
+ row[rowKey] ?? ri
4995
+ );
4996
+ }),
4997
+ useVirtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
4998
+ ] })
4999
+ ]
5000
+ }
5001
+ )
4962
5002
  }
4963
5003
  ),
4964
5004
  isNoData && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -4977,7 +5017,9 @@ var STable = forwardRef(function STable2({
4977
5017
  ),
4978
5018
  showPagination && // 원본 sd-table__pagination: 테이블 하단에 이어붙는 회색 바(높이 48px, margin-top:-1px로 테두리 겹침).
4979
5019
  // SPagination은 전체 폭 기준 중앙, rows-per-page SSelect는 우측에 absolute 배치해 중앙 정렬을 유지한다.
4980
- /* @__PURE__ */ jsxs("div", { className: "relative -mt-px flex h-[48px] items-center justify-center rounded-[var(--cmp-table-radius)] border border-solid border-[color:var(--cmp-table-border-color)] bg-[var(--color-grey-05)]", children: [
5020
+ // 루트 높이가 확정된 경우(테이블이 남은 영역을 채우는 배치) 페이지네이션 바가
5021
+ // 눌리지 않도록 shrink-0으로 48px를 보장한다.
5022
+ /* @__PURE__ */ jsxs("div", { className: "relative -mt-px flex h-[48px] shrink-0 items-center justify-center rounded-[var(--cmp-table-radius)] border border-solid border-[color:var(--cmp-table-border-color)] bg-[var(--color-grey-05)]", children: [
4981
5023
  /* @__PURE__ */ jsx(SPagination, { currentPage: displayPage, lastPage, onPageChange: changePage }),
4982
5024
  useRowsPerPageSelect && /* @__PURE__ */ jsx("div", { className: "absolute right-[10px] top-1/2 -translate-y-1/2", children: /* @__PURE__ */ jsx(
4983
5025
  SSelect,