@sellmate/design-system 1.3.0 → 1.4.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 (60) hide show
  1. package/dist/cjs/{component.table-CMqGfEui.js → component.table-qOFez3z3.js} +3 -0
  2. package/dist/cjs/design-system.cjs.js +1 -1
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/sd-calendar_2.cjs.entry.js +6 -5
  5. package/dist/cjs/sd-key-value-table.cjs.entry.js +1 -1
  6. package/dist/cjs/sd-pagination_4.cjs.entry.js +19 -28
  7. package/dist/cjs/sd-table.cjs.entry.js +25 -27
  8. package/dist/cjs/{sd-table.config-BIpldZtw.js → sd-table.config-B7psrvV4.js} +4 -2
  9. package/dist/cjs/sd-td.cjs.entry.js +18 -9
  10. package/dist/collection/components/sd-calendar/sd-calendar.css +2 -0
  11. package/dist/collection/components/sd-calendar/sd-calendar.js +5 -4
  12. package/dist/collection/components/sd-table/sd-table.js +24 -26
  13. package/dist/collection/components/sd-table/sd-td/sd-td.js +18 -9
  14. package/dist/collection/components/sd-table/sd-tr/sd-tr.css +6 -2
  15. package/dist/collection/components/sd-table/sd-tr/sd-tr.js +16 -25
  16. package/dist/components/{p-BkWaPXXj.js → p-BDVrZ5mV.js} +1 -1
  17. package/dist/components/p-CETxX4-M.js +1 -0
  18. package/dist/components/p-DQFHAKL_.js +1 -0
  19. package/dist/components/p-DiP0LJGq.js +1 -0
  20. package/dist/components/{p-CPuyhF6g.js → p-DwgaMhOM.js} +1 -1
  21. package/dist/components/p-DykVq5VY.js +1 -0
  22. package/dist/components/sd-calendar.js +1 -1
  23. package/dist/components/sd-date-picker.js +1 -1
  24. package/dist/components/sd-key-value-table.js +1 -1
  25. package/dist/components/sd-table.js +1 -1
  26. package/dist/components/sd-td.js +1 -1
  27. package/dist/components/sd-thead.js +1 -1
  28. package/dist/components/sd-tr.js +1 -1
  29. package/dist/design-system/design-system.esm.js +1 -1
  30. package/dist/design-system/p-29fd86d8.entry.js +1 -0
  31. package/dist/design-system/p-36d744fb.entry.js +1 -0
  32. package/dist/design-system/{p-fe0a5368.entry.js → p-42f7febe.entry.js} +1 -1
  33. package/dist/design-system/p-522d1481.entry.js +1 -0
  34. package/dist/design-system/p-DQFHAKL_.js +1 -0
  35. package/dist/design-system/p-DykVq5VY.js +1 -0
  36. package/dist/design-system/{p-00854a0a.entry.js → p-d890a680.entry.js} +1 -1
  37. package/dist/esm/{component.table-BnfUIhUj.js → component.table-DQFHAKL_.js} +3 -0
  38. package/dist/esm/design-system.js +1 -1
  39. package/dist/esm/loader.js +1 -1
  40. package/dist/esm/sd-calendar_2.entry.js +6 -5
  41. package/dist/esm/sd-key-value-table.entry.js +1 -1
  42. package/dist/esm/sd-pagination_4.entry.js +19 -28
  43. package/dist/esm/{sd-table.config-B-VgXXT7.js → sd-table.config-DU7Pc6YH.js} +4 -2
  44. package/dist/esm/sd-table.entry.js +25 -27
  45. package/dist/esm/sd-td.entry.js +18 -9
  46. package/dist/types/components/sd-table/sd-table.d.ts +1 -1
  47. package/dist/types/components/sd-table/sd-td/sd-td.d.ts +2 -2
  48. package/dist/types/components/sd-table/sd-tr/sd-tr.d.ts +1 -2
  49. package/hydrate/index.js +70 -66
  50. package/hydrate/index.mjs +70 -66
  51. package/package.json +1 -1
  52. package/dist/components/p-B8o25hOw.js +0 -1
  53. package/dist/components/p-BnfUIhUj.js +0 -1
  54. package/dist/components/p-WAsath62.js +0 -1
  55. package/dist/components/p-mmdt-WnS.js +0 -1
  56. package/dist/design-system/p-563b6fc2.entry.js +0 -1
  57. package/dist/design-system/p-BnfUIhUj.js +0 -1
  58. package/dist/design-system/p-f721a6c6.entry.js +0 -1
  59. package/dist/design-system/p-ffaa4b5d.entry.js +0 -1
  60. package/dist/design-system/p-mmdt-WnS.js +0 -1
@@ -2,8 +2,8 @@
2
2
 
3
3
  var index = require('./index-Cw-78mnC.js');
4
4
  var constants = require('./constants-DJRV1upE.js');
5
- var sdTable_config = require('./sd-table.config-BIpldZtw.js');
6
- require('./component.table-CMqGfEui.js');
5
+ var sdTable_config = require('./sd-table.config-B7psrvV4.js');
6
+ require('./component.table-qOFez3z3.js');
7
7
  require('./system-VmZRYp6V.js');
8
8
 
9
9
  let urlAlphabet =
@@ -58,7 +58,9 @@ const SdTable = class {
58
58
  get effectiveRowHeight() {
59
59
  if (this.rowHeight != null)
60
60
  return this.rowHeight;
61
- return this.dense ? Number(sdTable_config.TABLE_BODY_LAYOUT.dense.height) : Number(sdTable_config.TABLE_BODY_LAYOUT.default.height);
61
+ return this.dense
62
+ ? Number(sdTable_config.TABLE_BODY_LAYOUT.dense.height)
63
+ : Number(sdTable_config.TABLE_BODY_LAYOUT.default.height);
62
64
  }
63
65
  virtualBuffer = 5;
64
66
  virtualEndThreshold = 10;
@@ -252,7 +254,6 @@ const SdTable = class {
252
254
  el.unregisterSpanSync = this.unregisterSpanSync.bind(this);
253
255
  el.getSpanSync = this.getSpanSync.bind(this);
254
256
  el.isCoveredSync = this.isCoveredSync.bind(this);
255
- el.isVisualLastRowSync = this.isVisualLastRowSync.bind(this);
256
257
  el.registerSeparatorSync = this.registerSeparatorSync.bind(this);
257
258
  el.unregisterSeparatorSync = this.unregisterSeparatorSync.bind(this);
258
259
  el.isVisualLastRowBeforeSeparatorSync = this.isVisualLastRowBeforeSeparatorSync.bind(this);
@@ -263,6 +264,7 @@ const SdTable = class {
263
264
  el.registerUseFrameSync = this.registerUseFrameSync.bind(this);
264
265
  el.unregisterUseFrameSync = this.unregisterUseFrameSync.bind(this);
265
266
  el.hasUseFrameInRowSync = this.hasUseFrameInRowSync.bind(this);
267
+ el.isCellUseFrameSync = this.isCellUseFrameSync.bind(this);
266
268
  if (Array.isArray(this.rows)) {
267
269
  this.rowCount = this.rows.length;
268
270
  this.pushRowsToChildren(this.rows);
@@ -340,8 +342,15 @@ const SdTable = class {
340
342
  }
341
343
  });
342
344
  this.noDataContentResizeObserver.observe(target);
343
- const measured = Math.ceil(target.scrollHeight);
344
- this.noDataBodyHeight = Math.max(60, measured);
345
+ index.readTask(() => {
346
+ if (!this.noDataContentEl)
347
+ return;
348
+ const measured = Math.ceil(this.noDataContentEl.scrollHeight);
349
+ const next = Math.max(60, measured);
350
+ if (next !== this.noDataBodyHeight) {
351
+ this.noDataBodyHeight = next;
352
+ }
353
+ });
345
354
  }
346
355
  // light DOM(manual mode 자식)과 shadow DOM(autoThead/autoTbody fallback) 양쪽 모두에서 자식을 찾는다.
347
356
  queryChildEl(selector) {
@@ -465,6 +474,9 @@ const SdTable = class {
465
474
  const fields = this.useFrameRegistry.get(rowKey);
466
475
  return fields != null && fields.size > 0;
467
476
  }
477
+ isCellUseFrameSync(rowKey, field) {
478
+ return this.useFrameRegistry.get(rowKey)?.has(field) ?? false;
479
+ }
468
480
  isRowSelectedSync(row) {
469
481
  return Array.from(this.innerSelected).some(r => r[this.rowKey ?? 'id'] === row[this.rowKey ?? 'id']);
470
482
  }
@@ -736,7 +748,7 @@ const SdTable = class {
736
748
  return false;
737
749
  }
738
750
  // rowspan을 반영한 셀의 시각적 하단 행 인덱스를 반환한다.
739
- // isVisualLastRowSync·isVisualLastRowBeforeSeparatorSync 공통 헬퍼.
751
+ // isVisualLastRowBeforeSeparatorSync 헬퍼.
740
752
  resolveVisualBottom(rowKey, field) {
741
753
  const myRowIdx = this.resolveRowIndex(rowKey);
742
754
  if (myRowIdx == null)
@@ -745,20 +757,6 @@ const SdTable = class {
745
757
  const rs = Math.max(1, span?.rowspan ?? 1);
746
758
  return myRowIdx + rs - 1;
747
759
  }
748
- // 셀의 시각적 하단이 테이블(또는 현재 페이지)의 마지막 행인지 판정.
749
- // 마지막 행에 border-bottom: none을 적용하기 위함.
750
- isVisualLastRowSync(rowKey, field) {
751
- if (this.rowCount <= 0)
752
- return false;
753
- const visualBottom = this.resolveVisualBottom(rowKey, field);
754
- if (visualBottom == null)
755
- return false;
756
- const pageInfo = this.getPaginationInfoSync();
757
- const lastVisibleIdx = pageInfo
758
- ? Math.min(pageInfo.endIndex - 1, this.rowCount - 1)
759
- : this.rowCount - 1;
760
- return visualBottom === lastVisibleIdx;
761
- }
762
760
  registerSeparatorSync(prevRowKey) {
763
761
  const idx = this.resolveRowIndex(prevRowKey);
764
762
  if (idx != null)
@@ -875,25 +873,25 @@ const SdTable = class {
875
873
  '--table-body-line-height': `${sdTable_config.TABLE_BODY_TYPOGRAPHY.lineHeight}px`,
876
874
  '--table-body-text-decoration': sdTable_config.TABLE_BODY_TYPOGRAPHY.textDecoration,
877
875
  };
878
- return (index.h(index.Host, { key: '02d716bdac3832710bf58d63741aeeb4b04d434b', style: hostStyle }, index.h("div", { key: '88faad346e032ca727375889aa0552a330f5799a', class: "sd-table__container", style: {
876
+ return (index.h(index.Host, { key: '2b7c1eaf862c45c73751af6035a022e8ce0314b4', style: hostStyle }, index.h("div", { key: '35851e539eef8ff69ff03bd31f5d55d95eb8bf7a', class: "sd-table__container", style: {
879
877
  '--table-width': this.width,
880
878
  '--table-height': effectiveTableHeight,
881
879
  '--table-container-height': `calc(${effectiveTableHeight} - ${paginationHeight}px)`,
882
- } }, index.h("div", { key: '783934f349e0da5bab77cbb44cc12f0dfeb9ec71', class: {
880
+ } }, index.h("div", { key: 'e3bf5576fd1b1ee9ffab5d240de904204f4288d5', class: {
883
881
  'sd-table__wrapper': true,
884
882
  'sd-table__wrapper--radius-use-top': this.radius === 'useTop',
885
- } }, index.h("div", { key: 'd3a76ad0e853c6adf16df633c0e0b7f5bb580f24', class: {
883
+ } }, index.h("div", { key: 'a67ebcb802a3ed443cca1fc33a00787642e08e84', class: {
886
884
  'sd-table__scroll-container': true,
887
885
  'sd-table__scroll-container--loading': this.isLoading,
888
886
  'sd-table__scroll-container--no-data': isNoData,
889
- } }, this.isLoading && (index.h("div", { key: 'cc77ce58ff0eebf3fc1d7dd9dbf11578f94d4dd1', class: "sd-table__loading", style: { top: `${this.loadingScrollTop}px` } }, index.h("sd-circle-progress", { key: 'bda7ed774342089a23d13b49a506b04527026275', indeterminate: true }))), isNoData && (index.h(index.h.Fragment, null, index.h("div", { key: 'f2ce89d0ae9eefe0f0f8509e477756cb74dbef86', class: "sd-table__no-data-header-overlay" }), index.h("div", { key: '84d739563123d0f0fc33166b1a6e80021ba06e1c', class: "sd-table__no-data" }, index.h("div", { key: '3507f718a25b79c44fdf283fb41356ab72f2a384', class: "sd-table__no-data-content", ref: el => {
887
+ } }, this.isLoading && (index.h("div", { key: '2cdaff94dab50598c05364930dd3e763a6f2f79a', class: "sd-table__loading", style: { top: `${this.loadingScrollTop}px` } }, index.h("sd-circle-progress", { key: '49211d7555a38996d3fd9cfce0df50bb626fa1d6', indeterminate: true }))), isNoData && (index.h(index.h.Fragment, null, index.h("div", { key: '3da9d42ecedbdc63858a06040f0e22d265a8183b', class: "sd-table__no-data-header-overlay" }), index.h("div", { key: '20b5d8be682572a4ddbce21b6cd265894d014499', class: "sd-table__no-data" }, index.h("div", { key: 'a024fa084f4a137a70fe176cee6918b4f701fd42', class: "sd-table__no-data-content", ref: el => {
890
888
  this.noDataContentEl = el;
891
889
  if (el)
892
890
  this.syncNoDataContentObserver();
893
- } }, index.h("slot", { key: '818129819b2ff4a6f9fc1224dc59a9aa5861296d', name: "no-data" }, index.h("span", { key: 'c03cfb713e6dadd5ab4c60d7d27fd502d7aa9348' }, this.resolvedNoDataLabel)))))), index.h("table", { key: '8864714a828069985bac6535bc40cbb043dfcb28', class: this.tableClasses }, this.autoThead ? (index.h("slot", { name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange }, index.h("sd-thead", { rows: this.rows ?? [] }))) : (index.h("slot", { name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange })), this.autoTbody ? (index.h("slot", { name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange }, index.h("sd-tbody", { rows: this.rows ?? [] }, this.renderAutoRows()))) : (index.h("slot", { name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange }))))), this.pagination &&
891
+ } }, index.h("slot", { key: '9603eefa63fd5bc05dfa132c6be2302497d4c228', name: "no-data" }, index.h("span", { key: '0dad4e143d8251e375f748d1e5e1a77909fab164' }, this.resolvedNoDataLabel)))))), index.h("table", { key: '83325a8970f18bb9cf7a78dc665d16a24edc18da', class: this.tableClasses }, this.autoThead ? (index.h("slot", { name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange }, index.h("sd-thead", { rows: this.rows ?? [] }))) : (index.h("slot", { name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange })), this.autoTbody ? (index.h("slot", { name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange }, index.h("sd-tbody", { rows: this.rows ?? [] }, this.renderAutoRows()))) : (index.h("slot", { name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange }))))), this.pagination &&
894
892
  this.pagination.rowsPerPage > 0 &&
895
893
  this.rowCount > 0 &&
896
- !this.useVirtualScroll && (index.h("div", { key: 'bdac4b4d551152ec7ee0cdc31bfb992748836928', class: "sd-table__pagination" }, index.h("sd-pagination", { key: '2c60fff7f8ac3a3bd22da2173b8a9187bb686ddf', currentPage: !this.useInternalPagination ? this.pagination.page : this.currentPage, lastPage: !this.useInternalPagination ? this.pagination.lastPage : this.lastPageNumber, onSdPageChange: (e) => this.changePage(e.detail) }), this.useRowsPerPageSelect && (index.h("sd-select", { key: '7a662f58e13c15e705341773570f899f503f12c0', value: this.useInternalPagination
894
+ !this.useVirtualScroll && (index.h("div", { key: '935b0f916cbc1de29a7f6b3805a5a3c25eaba467', class: "sd-table__pagination" }, index.h("sd-pagination", { key: '7faad5d0b2efe652a9ed989910551aa8bc5592ec', currentPage: !this.useInternalPagination ? this.pagination.page : this.currentPage, lastPage: !this.useInternalPagination ? this.pagination.lastPage : this.lastPageNumber, onSdPageChange: (e) => this.changePage(e.detail) }), this.useRowsPerPageSelect && (index.h("sd-select", { key: 'd514c41459a60ac47ffcd476a635c47386232c50', value: this.useInternalPagination
897
895
  ? this.innerRowsPerPage
898
896
  : this.pagination.rowsPerPage, options: this.rowsPerPageOption, width: "128px", emitValue: true, onSdUpdate: e => {
899
897
  if (!this.isRowsPerPageValue(e.detail))
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var component_table = require('./component.table-CMqGfEui.js');
3
+ var component_table = require('./component.table-qOFez3z3.js');
4
4
  var system = require('./system-VmZRYp6V.js');
5
5
 
6
6
  // ── Header Tokens ──
@@ -33,7 +33,9 @@ const TABLE_BODY_LAYOUT = {
33
33
  height: component_table.tableTokens.table.body.dense.height,
34
34
  paddingY: component_table.tableTokens.table.body.dense.paddingY,
35
35
  },
36
- paddingX: component_table.tableTokens.table.body.paddingX};
36
+ paddingX: component_table.tableTokens.table.body.paddingX,
37
+ framePadding: component_table.tableTokens.table.body.frame.padding,
38
+ };
37
39
  const TABLE_BODY_TYPOGRAPHY = {
38
40
  fontFamily: component_table.tableTokens.table.body.typography.fontFamily,
39
41
  fontWeight: component_table.tableTokens.table.body.typography.fontWeight,
@@ -27,11 +27,13 @@ const SdTd = class {
27
27
  this.syncSlotName();
28
28
  this.syncSpanRegistration();
29
29
  this.syncCellClassRegistration(oldField);
30
+ this.syncUseFrameRegistration(oldField);
30
31
  }
31
32
  handleRowKeyChange(_newKey, oldKey) {
32
33
  this.syncSlotName();
33
34
  this.syncSpanRegistration();
34
35
  this.syncCellClassRegistration(undefined, oldKey);
36
+ this.syncUseFrameRegistration(undefined, oldKey);
35
37
  }
36
38
  handleSpanChange() {
37
39
  this.syncSpanRegistration();
@@ -42,15 +44,15 @@ const SdTd = class {
42
44
  handleDividerChange() {
43
45
  this.syncCellClassRegistration();
44
46
  }
45
- handleUseFieldChange() {
46
- this.syncUseFieldRegistration();
47
+ handleUseFrameChange() {
48
+ this.syncUseFrameRegistration();
47
49
  this.requestParentTrUpdate();
48
50
  }
49
51
  componentWillLoad() {
50
52
  this.syncSlotName();
51
53
  this.syncSpanRegistration();
52
54
  this.syncCellClassRegistration();
53
- this.syncUseFieldRegistration();
55
+ this.syncUseFrameRegistration();
54
56
  // slot 타이밍 엇갈림 대응: 부모 sd-tr forceUpdate로 슬롯 재매칭
55
57
  const parentTr = this.el.parentElement;
56
58
  if (parentTr?.tagName?.toLowerCase() === 'sd-tr') {
@@ -61,7 +63,7 @@ const SdTd = class {
61
63
  this.syncSlotName();
62
64
  this.syncSpanRegistration();
63
65
  this.syncCellClassRegistration();
64
- this.syncUseFieldRegistration();
66
+ this.syncUseFrameRegistration();
65
67
  }
66
68
  // React StrictMode에서는 disconnect/reconnect 사이클이 일어나면서
67
69
  // 동일 인스턴스의 componentWillLoad는 더 이상 호출되지 않는다.
@@ -69,7 +71,7 @@ const SdTd = class {
69
71
  connectedCallback() {
70
72
  this.syncSpanRegistration();
71
73
  this.syncCellClassRegistration();
72
- this.syncUseFieldRegistration();
74
+ this.syncUseFrameRegistration();
73
75
  }
74
76
  disconnectedCallback() {
75
77
  const table = this.findTable();
@@ -126,9 +128,16 @@ const SdTd = class {
126
128
  table.registerCellClassSync(String(this.rowKey), this.field, combinedClass);
127
129
  this.requestParentTrUpdate();
128
130
  }
129
- syncUseFieldRegistration() {
131
+ syncUseFrameRegistration(prevField, prevRowKey) {
130
132
  const table = this.findTable();
131
- if (!table || this.field === '' || this.rowKey == null)
133
+ if (!table)
134
+ return;
135
+ const oldField = prevField ?? this.field;
136
+ const oldRowKey = prevRowKey ?? (this.rowKey != null ? String(this.rowKey) : undefined);
137
+ if (oldField !== '' && oldRowKey != null) {
138
+ table.unregisterUseFrameSync?.(oldRowKey, oldField);
139
+ }
140
+ if (this.field === '' || this.rowKey == null)
132
141
  return;
133
142
  if (this.useFrame) {
134
143
  table.registerUseFrameSync?.(String(this.rowKey), this.field);
@@ -149,7 +158,7 @@ const SdTd = class {
149
158
  }
150
159
  }
151
160
  render() {
152
- return (index.h(index.Host, { key: '7d51ea5f02ba2df099f4440be26c2f0be8a73a6b', class: { [`align-${this.align}`]: Boolean(this.align) } }, index.h("slot", { key: '9a6a634e2bcd206ec9099c6be738c3853d0cbebf' })));
161
+ return (index.h(index.Host, { key: '505b602b609050870e7e80df9157dbc50d0cb8c1', class: { [`align-${this.align}`]: Boolean(this.align) } }, index.h("slot", { key: '9910f02d98ce5e115b2a380954dd0a994f9f1c12' })));
153
162
  }
154
163
  static get watchers() { return {
155
164
  "field": [{
@@ -174,7 +183,7 @@ const SdTd = class {
174
183
  "handleDividerChange": 0
175
184
  }],
176
185
  "useFrame": [{
177
- "handleUseFieldChange": 0
186
+ "handleUseFrameChange": 0
178
187
  }]
179
188
  }; }
180
189
  };
@@ -122,7 +122,9 @@ sd-calendar .sd-calendar__dot-row {
122
122
  flex-wrap: wrap;
123
123
  justify-content: center;
124
124
  gap: var(--calendar-day-dot-gap);
125
+ box-sizing: border-box;
125
126
  width: 100%;
127
+ min-height: 14px;
126
128
  padding-top: var(--calendar-day-dot-padding-y);
127
129
  padding-bottom: var(--calendar-day-dot-padding-y);
128
130
  }
@@ -171,7 +171,8 @@ export class SdCalendar {
171
171
  };
172
172
  const eventMap = this.eventMap;
173
173
  const legend = this.legendItems;
174
- return (h("div", { key: '66c0bec57c13af12b05f2e90fbc5e1674ab052c8', class: "sd-calendar", style: cssVars }, h("div", { key: '4df4f1c6d1ddcbe1478a69a481a228e66fc33c0a', class: "sd-calendar__header" }, h("div", { key: '378c04444b3ddcc7df92ecce0f49056e919cd8e5', class: "sd-calendar__nav-group" }, h("sd-ghost-button", { key: '47426c62a26b05a9db58144acc33770713e7fce4', ariaLabel: "prevYear", size: "xxs", icon: "chevronLeft", onClick: this.goPrevYear }), h("span", { key: '3b32e76a8a35705d820803c0b747829370079324', class: "sd-calendar__label" }, this.currentYear), h("sd-ghost-button", { key: '2e890a2cea91c9f49a03f0db3a4b943c707e312e', ariaLabel: "nextYear", size: "xxs", icon: "chevronRight", onClick: this.goNextYear })), h("span", { key: '795bb8452e75303c25a8dc6d95f819f1e42f7f49', class: "sd-calendar__divider", "aria-hidden": "true" }), h("div", { key: '6df460ec38917c51eff851732c7f37b7e09475f6', class: "sd-calendar__nav-group sd-calendar__nav-group-month" }, h("sd-ghost-button", { key: '36ef9dfdcfac5d9da08d05ca357fc9ec4100af4f', ariaLabel: "prevMonth", size: "xxs", icon: "chevronLeft", onClick: this.goPrevMonth }), h("span", { key: 'b2e0cc74570724c0d97fb2afbcb775c0794583af', class: "sd-calendar__label sd-calendar__label-month" }, this.currentMonth, "\uC6D4"), h("sd-ghost-button", { key: '4c45467356411f7a5d137c19931d8fc62084c742', ariaLabel: "nextMonth", size: "xxs", icon: "chevronRight", onClick: this.goNextMonth }))), h("div", { key: 'e1637a39795fb44bd33d138c8b244cc15b5f85f6', class: "sd-calendar__week" }, WEEK_LABELS.map(label => (h("span", { key: label, class: "sd-calendar__week-cell" }, label)))), h("div", { key: '45642dc93b1373dc760f64ba74dd931e651279dd', class: "sd-calendar__grid" }, this.cells.map(cell => {
174
+ const hasEvents = (this.events?.length ?? 0) > 0;
175
+ return (h("div", { key: '79cfdb58f8d44085c87cfea6458e60654bfa09bb', class: "sd-calendar", style: cssVars }, h("div", { key: '065620bcd155de11ef2272720de57ef6fcd9fd20', class: "sd-calendar__header" }, h("div", { key: 'ae27c8fe51c44137932b18cc83b64dcce7e2bbaa', class: "sd-calendar__nav-group" }, h("sd-ghost-button", { key: '8207f6d77705999419f451db032c059564ea0c17', ariaLabel: "prevYear", size: "xxs", icon: "chevronLeft", onClick: this.goPrevYear }), h("span", { key: 'b5bf63784dd06c3ce5a4d4c5514fea22efb08793', class: "sd-calendar__label" }, this.currentYear), h("sd-ghost-button", { key: '14512de68825e3b158704c3084306029ade8fcc1', ariaLabel: "nextYear", size: "xxs", icon: "chevronRight", onClick: this.goNextYear })), h("span", { key: 'e37eb90d72c2e64b8ebb1da4ddf3fccb7ff18cc3', class: "sd-calendar__divider", "aria-hidden": "true" }), h("div", { key: '07b1696b663ddb992e5a8d8b5ab98205ba136d9d', class: "sd-calendar__nav-group sd-calendar__nav-group-month" }, h("sd-ghost-button", { key: 'b742889a44643d3e4d3b6da90784923c40e5a07f', ariaLabel: "prevMonth", size: "xxs", icon: "chevronLeft", onClick: this.goPrevMonth }), h("span", { key: 'c97402106312c3a6eb220798263ba818419e7d27', class: "sd-calendar__label sd-calendar__label-month" }, this.currentMonth, "\uC6D4"), h("sd-ghost-button", { key: '55411b1328acb781d71a7a84996d2a29886612cd', ariaLabel: "nextMonth", size: "xxs", icon: "chevronRight", onClick: this.goNextMonth }))), h("div", { key: 'd10b03d31be412b545999d7e70bd9a349e5f1880', class: "sd-calendar__week" }, WEEK_LABELS.map(label => (h("span", { key: label, class: "sd-calendar__week-cell" }, label)))), h("div", { key: '0b8f82db3753fe08435b07dee695d49a192786c0', class: "sd-calendar__grid" }, this.cells.map(cell => {
175
176
  const isSelected = cell.inCurrentMonth && this.value !== '' && this.value === cell.date;
176
177
  const isToday = cell.inCurrentMonth && today === cell.date;
177
178
  const isDisabled = cell.inCurrentMonth && this.isDisabled(cell.date);
@@ -182,10 +183,10 @@ export class SdCalendar {
182
183
  'sd-calendar__day--today': isToday,
183
184
  'sd-calendar__day--selected': isSelected,
184
185
  'sd-calendar__day--disabled': isDisabled,
185
- }, disabled: !cell.inCurrentMonth || isDisabled, tabindex: !cell.inCurrentMonth ? -1 : undefined, "aria-hidden": !cell.inCurrentMonth ? 'true' : undefined, onClick: () => cell.inCurrentMonth && this.handleDayClick(cell) }, h("span", { class: "sd-calendar__day-circle" }, cell.inCurrentMonth ? cell.day : ''), dayEvents && dayEvents.length > 0 && (h("span", { class: "sd-calendar__dot-row", "aria-hidden": "true" }, dayEvents.map((ev, i) => (h("span", { key: `${ev.color}|${ev.label}|${i}`, class: "sd-calendar__dot", style: { backgroundColor: ev.color } })))))));
186
+ }, disabled: !cell.inCurrentMonth || isDisabled, tabindex: !cell.inCurrentMonth ? -1 : undefined, "aria-hidden": !cell.inCurrentMonth ? 'true' : undefined, onClick: () => cell.inCurrentMonth && this.handleDayClick(cell) }, h("span", { class: "sd-calendar__day-circle" }, cell.inCurrentMonth ? cell.day : ''), hasEvents && (h("span", { class: "sd-calendar__dot-row", "aria-hidden": "true" }, dayEvents?.map((ev, i) => (h("span", { key: `${ev.color}|${ev.label}|${i}`, class: "sd-calendar__dot", style: { backgroundColor: ev.color } })))))));
186
187
  })), legend.length > 0 && [
187
- h("span", { key: '0872cb7627db7d33721fbd1e1c9a601bd3c6c3e1', class: "sd-calendar__divider-bottom", "aria-hidden": "true" }),
188
- h("div", { key: 'd9c6be0684720aa9d2af24b2d0cf372a036dc8d5', class: "sd-calendar__legend" }, legend.map(item => (h("span", { key: `${item.color}|${item.label}`, class: "sd-calendar__legend-item" }, h("span", { class: "sd-calendar__legend-dot", style: { backgroundColor: item.color }, "aria-hidden": "true" }), h("span", { class: "sd-calendar__legend-label" }, item.label))))),
188
+ h("span", { key: 'a837c5956da658561fcbd2e646b0abbb0fa84a20', class: "sd-calendar__divider-bottom", "aria-hidden": "true" }),
189
+ h("div", { key: '190b9947e5ecd627fad03b40c58c2e0c8719daaa', class: "sd-calendar__legend" }, legend.map(item => (h("span", { key: `${item.color}|${item.label}`, class: "sd-calendar__legend-item" }, h("span", { class: "sd-calendar__legend-dot", style: { backgroundColor: item.color }, "aria-hidden": "true" }), h("span", { class: "sd-calendar__legend-label" }, item.label))))),
189
190
  ]));
190
191
  }
191
192
  static get is() { return "sd-calendar"; }
@@ -1,7 +1,7 @@
1
1
  import { h, Host, readTask, forceUpdate, } from "@stencil/core";
2
2
  import { nanoid } from "nanoid";
3
3
  import { TABLE_ID_ATTR, } from "./constants";
4
- import { TABLE_RADIUS, TABLE_BORDER, TABLE_BODY_TYPOGRAPHY, TABLE_BODY_LAYOUT } from "./sd-table.config";
4
+ import { TABLE_RADIUS, TABLE_BORDER, TABLE_BODY_TYPOGRAPHY, TABLE_BODY_LAYOUT, } from "./sd-table.config";
5
5
  export class SdTable {
6
6
  static DEFAULT_NO_DATA_LABEL = '데이터가 없습니다.';
7
7
  el;
@@ -31,7 +31,9 @@ export class SdTable {
31
31
  get effectiveRowHeight() {
32
32
  if (this.rowHeight != null)
33
33
  return this.rowHeight;
34
- return this.dense ? Number(TABLE_BODY_LAYOUT.dense.height) : Number(TABLE_BODY_LAYOUT.default.height);
34
+ return this.dense
35
+ ? Number(TABLE_BODY_LAYOUT.dense.height)
36
+ : Number(TABLE_BODY_LAYOUT.default.height);
35
37
  }
36
38
  virtualBuffer = 5;
37
39
  virtualEndThreshold = 10;
@@ -225,7 +227,6 @@ export class SdTable {
225
227
  el.unregisterSpanSync = this.unregisterSpanSync.bind(this);
226
228
  el.getSpanSync = this.getSpanSync.bind(this);
227
229
  el.isCoveredSync = this.isCoveredSync.bind(this);
228
- el.isVisualLastRowSync = this.isVisualLastRowSync.bind(this);
229
230
  el.registerSeparatorSync = this.registerSeparatorSync.bind(this);
230
231
  el.unregisterSeparatorSync = this.unregisterSeparatorSync.bind(this);
231
232
  el.isVisualLastRowBeforeSeparatorSync = this.isVisualLastRowBeforeSeparatorSync.bind(this);
@@ -236,6 +237,7 @@ export class SdTable {
236
237
  el.registerUseFrameSync = this.registerUseFrameSync.bind(this);
237
238
  el.unregisterUseFrameSync = this.unregisterUseFrameSync.bind(this);
238
239
  el.hasUseFrameInRowSync = this.hasUseFrameInRowSync.bind(this);
240
+ el.isCellUseFrameSync = this.isCellUseFrameSync.bind(this);
239
241
  if (Array.isArray(this.rows)) {
240
242
  this.rowCount = this.rows.length;
241
243
  this.pushRowsToChildren(this.rows);
@@ -313,8 +315,15 @@ export class SdTable {
313
315
  }
314
316
  });
315
317
  this.noDataContentResizeObserver.observe(target);
316
- const measured = Math.ceil(target.scrollHeight);
317
- this.noDataBodyHeight = Math.max(60, measured);
318
+ readTask(() => {
319
+ if (!this.noDataContentEl)
320
+ return;
321
+ const measured = Math.ceil(this.noDataContentEl.scrollHeight);
322
+ const next = Math.max(60, measured);
323
+ if (next !== this.noDataBodyHeight) {
324
+ this.noDataBodyHeight = next;
325
+ }
326
+ });
318
327
  }
319
328
  // light DOM(manual mode 자식)과 shadow DOM(autoThead/autoTbody fallback) 양쪽 모두에서 자식을 찾는다.
320
329
  queryChildEl(selector) {
@@ -438,6 +447,9 @@ export class SdTable {
438
447
  const fields = this.useFrameRegistry.get(rowKey);
439
448
  return fields != null && fields.size > 0;
440
449
  }
450
+ isCellUseFrameSync(rowKey, field) {
451
+ return this.useFrameRegistry.get(rowKey)?.has(field) ?? false;
452
+ }
441
453
  isRowSelectedSync(row) {
442
454
  return Array.from(this.innerSelected).some(r => r[this.rowKey ?? 'id'] === row[this.rowKey ?? 'id']);
443
455
  }
@@ -709,7 +721,7 @@ export class SdTable {
709
721
  return false;
710
722
  }
711
723
  // rowspan을 반영한 셀의 시각적 하단 행 인덱스를 반환한다.
712
- // isVisualLastRowSync·isVisualLastRowBeforeSeparatorSync 공통 헬퍼.
724
+ // isVisualLastRowBeforeSeparatorSync 헬퍼.
713
725
  resolveVisualBottom(rowKey, field) {
714
726
  const myRowIdx = this.resolveRowIndex(rowKey);
715
727
  if (myRowIdx == null)
@@ -718,20 +730,6 @@ export class SdTable {
718
730
  const rs = Math.max(1, span?.rowspan ?? 1);
719
731
  return myRowIdx + rs - 1;
720
732
  }
721
- // 셀의 시각적 하단이 테이블(또는 현재 페이지)의 마지막 행인지 판정.
722
- // 마지막 행에 border-bottom: none을 적용하기 위함.
723
- isVisualLastRowSync(rowKey, field) {
724
- if (this.rowCount <= 0)
725
- return false;
726
- const visualBottom = this.resolveVisualBottom(rowKey, field);
727
- if (visualBottom == null)
728
- return false;
729
- const pageInfo = this.getPaginationInfoSync();
730
- const lastVisibleIdx = pageInfo
731
- ? Math.min(pageInfo.endIndex - 1, this.rowCount - 1)
732
- : this.rowCount - 1;
733
- return visualBottom === lastVisibleIdx;
734
- }
735
733
  registerSeparatorSync(prevRowKey) {
736
734
  const idx = this.resolveRowIndex(prevRowKey);
737
735
  if (idx != null)
@@ -848,25 +846,25 @@ export class SdTable {
848
846
  '--table-body-line-height': `${TABLE_BODY_TYPOGRAPHY.lineHeight}px`,
849
847
  '--table-body-text-decoration': TABLE_BODY_TYPOGRAPHY.textDecoration,
850
848
  };
851
- return (h(Host, { key: '02d716bdac3832710bf58d63741aeeb4b04d434b', style: hostStyle }, h("div", { key: '88faad346e032ca727375889aa0552a330f5799a', class: "sd-table__container", style: {
849
+ return (h(Host, { key: '2b7c1eaf862c45c73751af6035a022e8ce0314b4', style: hostStyle }, h("div", { key: '35851e539eef8ff69ff03bd31f5d55d95eb8bf7a', class: "sd-table__container", style: {
852
850
  '--table-width': this.width,
853
851
  '--table-height': effectiveTableHeight,
854
852
  '--table-container-height': `calc(${effectiveTableHeight} - ${paginationHeight}px)`,
855
- } }, h("div", { key: '783934f349e0da5bab77cbb44cc12f0dfeb9ec71', class: {
853
+ } }, h("div", { key: 'e3bf5576fd1b1ee9ffab5d240de904204f4288d5', class: {
856
854
  'sd-table__wrapper': true,
857
855
  'sd-table__wrapper--radius-use-top': this.radius === 'useTop',
858
- } }, h("div", { key: 'd3a76ad0e853c6adf16df633c0e0b7f5bb580f24', class: {
856
+ } }, h("div", { key: 'a67ebcb802a3ed443cca1fc33a00787642e08e84', class: {
859
857
  'sd-table__scroll-container': true,
860
858
  'sd-table__scroll-container--loading': this.isLoading,
861
859
  'sd-table__scroll-container--no-data': isNoData,
862
- } }, this.isLoading && (h("div", { key: 'cc77ce58ff0eebf3fc1d7dd9dbf11578f94d4dd1', class: "sd-table__loading", style: { top: `${this.loadingScrollTop}px` } }, h("sd-circle-progress", { key: 'bda7ed774342089a23d13b49a506b04527026275', indeterminate: true }))), isNoData && (h(h.Fragment, null, h("div", { key: 'f2ce89d0ae9eefe0f0f8509e477756cb74dbef86', class: "sd-table__no-data-header-overlay" }), h("div", { key: '84d739563123d0f0fc33166b1a6e80021ba06e1c', class: "sd-table__no-data" }, h("div", { key: '3507f718a25b79c44fdf283fb41356ab72f2a384', class: "sd-table__no-data-content", ref: el => {
860
+ } }, this.isLoading && (h("div", { key: '2cdaff94dab50598c05364930dd3e763a6f2f79a', class: "sd-table__loading", style: { top: `${this.loadingScrollTop}px` } }, h("sd-circle-progress", { key: '49211d7555a38996d3fd9cfce0df50bb626fa1d6', indeterminate: true }))), isNoData && (h(h.Fragment, null, h("div", { key: '3da9d42ecedbdc63858a06040f0e22d265a8183b', class: "sd-table__no-data-header-overlay" }), h("div", { key: '20b5d8be682572a4ddbce21b6cd265894d014499', class: "sd-table__no-data" }, h("div", { key: 'a024fa084f4a137a70fe176cee6918b4f701fd42', class: "sd-table__no-data-content", ref: el => {
863
861
  this.noDataContentEl = el;
864
862
  if (el)
865
863
  this.syncNoDataContentObserver();
866
- } }, h("slot", { key: '818129819b2ff4a6f9fc1224dc59a9aa5861296d', name: "no-data" }, h("span", { key: 'c03cfb713e6dadd5ab4c60d7d27fd502d7aa9348' }, this.resolvedNoDataLabel)))))), h("table", { key: '8864714a828069985bac6535bc40cbb043dfcb28', class: this.tableClasses }, this.autoThead ? (h("slot", { name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange }, h("sd-thead", { rows: this.rows ?? [] }))) : (h("slot", { name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange })), this.autoTbody ? (h("slot", { name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange }, h("sd-tbody", { rows: this.rows ?? [] }, this.renderAutoRows()))) : (h("slot", { name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange }))))), this.pagination &&
864
+ } }, h("slot", { key: '9603eefa63fd5bc05dfa132c6be2302497d4c228', name: "no-data" }, h("span", { key: '0dad4e143d8251e375f748d1e5e1a77909fab164' }, this.resolvedNoDataLabel)))))), h("table", { key: '83325a8970f18bb9cf7a78dc665d16a24edc18da', class: this.tableClasses }, this.autoThead ? (h("slot", { name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange }, h("sd-thead", { rows: this.rows ?? [] }))) : (h("slot", { name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange })), this.autoTbody ? (h("slot", { name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange }, h("sd-tbody", { rows: this.rows ?? [] }, this.renderAutoRows()))) : (h("slot", { name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange }))))), this.pagination &&
867
865
  this.pagination.rowsPerPage > 0 &&
868
866
  this.rowCount > 0 &&
869
- !this.useVirtualScroll && (h("div", { key: 'bdac4b4d551152ec7ee0cdc31bfb992748836928', class: "sd-table__pagination" }, h("sd-pagination", { key: '2c60fff7f8ac3a3bd22da2173b8a9187bb686ddf', currentPage: !this.useInternalPagination ? this.pagination.page : this.currentPage, lastPage: !this.useInternalPagination ? this.pagination.lastPage : this.lastPageNumber, onSdPageChange: (e) => this.changePage(e.detail) }), this.useRowsPerPageSelect && (h("sd-select", { key: '7a662f58e13c15e705341773570f899f503f12c0', value: this.useInternalPagination
867
+ !this.useVirtualScroll && (h("div", { key: '935b0f916cbc1de29a7f6b3805a5a3c25eaba467', class: "sd-table__pagination" }, h("sd-pagination", { key: '7faad5d0b2efe652a9ed989910551aa8bc5592ec', currentPage: !this.useInternalPagination ? this.pagination.page : this.currentPage, lastPage: !this.useInternalPagination ? this.pagination.lastPage : this.lastPageNumber, onSdPageChange: (e) => this.changePage(e.detail) }), this.useRowsPerPageSelect && (h("sd-select", { key: 'd514c41459a60ac47ffcd476a635c47386232c50', value: this.useInternalPagination
870
868
  ? this.innerRowsPerPage
871
869
  : this.pagination.rowsPerPage, options: this.rowsPerPageOption, width: "128px", emitValue: true, onSdUpdate: e => {
872
870
  if (!this.isRowsPerPageValue(e.detail))
@@ -19,11 +19,13 @@ export class SdTd {
19
19
  this.syncSlotName();
20
20
  this.syncSpanRegistration();
21
21
  this.syncCellClassRegistration(oldField);
22
+ this.syncUseFrameRegistration(oldField);
22
23
  }
23
24
  handleRowKeyChange(_newKey, oldKey) {
24
25
  this.syncSlotName();
25
26
  this.syncSpanRegistration();
26
27
  this.syncCellClassRegistration(undefined, oldKey);
28
+ this.syncUseFrameRegistration(undefined, oldKey);
27
29
  }
28
30
  handleSpanChange() {
29
31
  this.syncSpanRegistration();
@@ -34,15 +36,15 @@ export class SdTd {
34
36
  handleDividerChange() {
35
37
  this.syncCellClassRegistration();
36
38
  }
37
- handleUseFieldChange() {
38
- this.syncUseFieldRegistration();
39
+ handleUseFrameChange() {
40
+ this.syncUseFrameRegistration();
39
41
  this.requestParentTrUpdate();
40
42
  }
41
43
  componentWillLoad() {
42
44
  this.syncSlotName();
43
45
  this.syncSpanRegistration();
44
46
  this.syncCellClassRegistration();
45
- this.syncUseFieldRegistration();
47
+ this.syncUseFrameRegistration();
46
48
  // slot 타이밍 엇갈림 대응: 부모 sd-tr forceUpdate로 슬롯 재매칭
47
49
  const parentTr = this.el.parentElement;
48
50
  if (parentTr?.tagName?.toLowerCase() === 'sd-tr') {
@@ -53,7 +55,7 @@ export class SdTd {
53
55
  this.syncSlotName();
54
56
  this.syncSpanRegistration();
55
57
  this.syncCellClassRegistration();
56
- this.syncUseFieldRegistration();
58
+ this.syncUseFrameRegistration();
57
59
  }
58
60
  // React StrictMode에서는 disconnect/reconnect 사이클이 일어나면서
59
61
  // 동일 인스턴스의 componentWillLoad는 더 이상 호출되지 않는다.
@@ -61,7 +63,7 @@ export class SdTd {
61
63
  connectedCallback() {
62
64
  this.syncSpanRegistration();
63
65
  this.syncCellClassRegistration();
64
- this.syncUseFieldRegistration();
66
+ this.syncUseFrameRegistration();
65
67
  }
66
68
  disconnectedCallback() {
67
69
  const table = this.findTable();
@@ -118,9 +120,16 @@ export class SdTd {
118
120
  table.registerCellClassSync(String(this.rowKey), this.field, combinedClass);
119
121
  this.requestParentTrUpdate();
120
122
  }
121
- syncUseFieldRegistration() {
123
+ syncUseFrameRegistration(prevField, prevRowKey) {
122
124
  const table = this.findTable();
123
- if (!table || this.field === '' || this.rowKey == null)
125
+ if (!table)
126
+ return;
127
+ const oldField = prevField ?? this.field;
128
+ const oldRowKey = prevRowKey ?? (this.rowKey != null ? String(this.rowKey) : undefined);
129
+ if (oldField !== '' && oldRowKey != null) {
130
+ table.unregisterUseFrameSync?.(oldRowKey, oldField);
131
+ }
132
+ if (this.field === '' || this.rowKey == null)
124
133
  return;
125
134
  if (this.useFrame) {
126
135
  table.registerUseFrameSync?.(String(this.rowKey), this.field);
@@ -141,7 +150,7 @@ export class SdTd {
141
150
  }
142
151
  }
143
152
  render() {
144
- return (h(Host, { key: '7d51ea5f02ba2df099f4440be26c2f0be8a73a6b', class: { [`align-${this.align}`]: Boolean(this.align) } }, h("slot", { key: '9a6a634e2bcd206ec9099c6be738c3853d0cbebf' })));
153
+ return (h(Host, { key: '505b602b609050870e7e80df9157dbc50d0cb8c1', class: { [`align-${this.align}`]: Boolean(this.align) } }, h("slot", { key: '9910f02d98ce5e115b2a380954dd0a994f9f1c12' })));
145
154
  }
146
155
  static get is() { return "sd-td"; }
147
156
  static get originalStyleUrls() {
@@ -357,7 +366,7 @@ export class SdTd {
357
366
  "methodName": "handleDividerChange"
358
367
  }, {
359
368
  "propName": "useFrame",
360
- "methodName": "handleUseFieldChange"
369
+ "methodName": "handleUseFrameChange"
361
370
  }];
362
371
  }
363
372
  }
@@ -14,6 +14,9 @@ sd-tr * {
14
14
  .tr--no-hover:hover .td {
15
15
  background-color: white;
16
16
  }
17
+ .tr--separator:hover .td {
18
+ background-color: var(--table-separator-color, #eeeeee);
19
+ }
17
20
 
18
21
  .td {
19
22
  display: table-cell;
@@ -118,8 +121,9 @@ sd-tr * {
118
121
  background-color: white;
119
122
  }
120
123
 
121
- .td.td--last-row {
122
- border-bottom: none;
124
+ .tr--separator:hover .td.sticky-left,
125
+ .tr--separator:hover .td.sticky-right {
126
+ background-color: var(--table-separator-color, #eeeeee);
123
127
  }
124
128
 
125
129
  .tr--separator .td--separator {
@@ -170,6 +170,13 @@ export class SdTr {
170
170
  const fieldName = typeof col.field === 'string' ? col.field : col.name;
171
171
  return this.tableEl.getCellClassSync(this.rowKey, fieldName);
172
172
  }
173
+ getFramePaddingStyle(field) {
174
+ if (!this._dense)
175
+ return undefined;
176
+ if (!(this.tableEl?.isCellUseFrameSync?.(this.rowKey, field) ?? false))
177
+ return undefined;
178
+ return { padding: `${TABLE_BODY_LAYOUT.framePadding}px` };
179
+ }
173
180
  expandCellClass(classStr) {
174
181
  if (classStr == null || classStr === '')
175
182
  return {};
@@ -178,20 +185,6 @@ export class SdTr {
178
185
  .filter(Boolean)
179
186
  .map(c => [c, true]));
180
187
  }
181
- isVisualLastRow(col) {
182
- if (!this.tableEl?.isVisualLastRowSync)
183
- return false;
184
- const fieldName = typeof col.field === 'string' ? col.field : col.name;
185
- return this.tableEl.isVisualLastRowSync(this.rowKey, fieldName);
186
- }
187
- // selectable td는 column 정보가 없으므로 빈 field로 평가한다.
188
- // 해당 위치는 rowspan을 등록할 수 없으므로 spanRegistry에 매칭이 없고,
189
- // 결과적으로 "내 row 자체가 시각적 마지막인지"가 판정된다.
190
- isVisualLastRowForSelfRow() {
191
- if (!this.tableEl?.isVisualLastRowSync)
192
- return false;
193
- return this.tableEl.isVisualLastRowSync(this.rowKey, '');
194
- }
195
188
  isVisualLastRowBeforeSeparator(col) {
196
189
  if (!this.tableEl?.isVisualLastRowBeforeSeparatorSync)
197
190
  return false;
@@ -212,12 +205,13 @@ export class SdTr {
212
205
  const hasRowspan = this.tableEl?.hasRowspanSync?.() ?? false;
213
206
  const isUseFrameRow = this.tableEl?.hasUseFrameInRowSync?.(this.rowKey) ?? false;
214
207
  const effectiveDense = this._dense && !isUseFrameRow;
215
- const bodyLayout = effectiveDense ? TABLE_BODY_LAYOUT.dense : TABLE_BODY_LAYOUT.default;
208
+ const rowLayoutY = effectiveDense ? TABLE_BODY_LAYOUT.dense : TABLE_BODY_LAYOUT.default;
209
+ const rowPaddingX = this._dense && isUseFrameRow ? TABLE_BODY_LAYOUT.paddingX : TABLE_BODY_LAYOUT.paddingX;
216
210
  const rowStyle = {
217
211
  'display': this.isVisible ? '' : 'none',
218
- '--table-body-height': `${bodyLayout.height}px`,
219
- '--table-body-padding-y': `${bodyLayout.paddingY}px`,
220
- '--table-body-padding-x': `${TABLE_BODY_LAYOUT.paddingX}px`,
212
+ '--table-body-height': `${rowLayoutY.height}px`,
213
+ '--table-body-padding-y': `${rowLayoutY.paddingY}px`,
214
+ '--table-body-padding-x': `${rowPaddingX}px`,
221
215
  '--table-body-font-family': TABLE_BODY_TYPOGRAPHY.fontFamily,
222
216
  '--table-body-font-weight': TABLE_BODY_TYPOGRAPHY.fontWeight,
223
217
  '--table-body-font-size': `${TABLE_BODY_TYPOGRAPHY.fontSize}px`,
@@ -235,7 +229,6 @@ export class SdTr {
235
229
  return (h(Host, { style: rowStyle }, h("tr", { class: { 'tr': true, 'tr--no-hover': hasRowspan } }, this._selectable && (h("td", { class: {
236
230
  'td': true,
237
231
  'td--selected': true,
238
- 'td--last-row': this.isVisualLastRowForSelfRow(),
239
232
  'td--before-separator': this.isVisualLastRowBeforeSeparatorForSelfRow(),
240
233
  'sticky-left': true,
241
234
  'sticky-left-edge': stickyLeftCount === 0,
@@ -243,19 +236,19 @@ export class SdTr {
243
236
  }, style: { '--sticky-left-offset': '0px' } }, h("sd-checkbox", { value: this.isSelected(), onSdUpdate: () => this.handleSelect() }))), stickyLeftCols.map((col, idx) => {
244
237
  if (this.isCovered(idx))
245
238
  return null;
239
+ const fieldName = typeof col.field === 'string' ? col.field : col.name;
246
240
  const span = this.getSpanFor(col);
247
241
  const sdCellClass = this.getCellClassFor(col);
248
242
  return (h("td", { key: col.name, rowSpan: span?.rowspan, colSpan: span?.colspan, class: {
249
243
  'td': true,
250
244
  [`td--${col.align || 'left'}`]: true,
251
- 'td--last-row': this.isVisualLastRow(col),
252
245
  'td--before-separator': this.isVisualLastRowBeforeSeparator(col),
253
246
  'sticky-left': true,
254
247
  'sticky-left-edge': idx === stickyLeftCount - 1,
255
248
  'is-scrolled-left': idx === stickyLeftCount - 1 && this._scrolledLeft,
256
249
  [`${col.tdClass}`]: Boolean(col.tdClass),
257
250
  ...this.expandCellClass(sdCellClass),
258
- }, style: this.getStickyStyle(idx) }, h("slot", { name: `${this.tableId}-${typeof col.field === 'string' ? col.field : col.name}-${this.rowKey}` }, h("span", null, this.getCellValue(col)))));
251
+ }, style: { ...this.getStickyStyle(idx), ...this.getFramePaddingStyle(fieldName) } }, h("slot", { name: `${this.tableId}-${fieldName}-${this.rowKey}` }, h("span", null, this.getCellValue(col)))));
259
252
  }), middleCols.map((col, relativeIdx) => {
260
253
  const actualColIdx = stickyLeftCount + relativeIdx;
261
254
  if (this.isCovered(actualColIdx))
@@ -266,11 +259,10 @@ export class SdTr {
266
259
  return (h("td", { key: col.name, rowSpan: span?.rowspan, colSpan: span?.colspan, class: {
267
260
  'td': true,
268
261
  [`td--${col.align || 'left'}`]: true,
269
- 'td--last-row': this.isVisualLastRow(col),
270
262
  'td--before-separator': this.isVisualLastRowBeforeSeparator(col),
271
263
  [`${col.tdClass}`]: Boolean(col.tdClass),
272
264
  ...this.expandCellClass(sdCellClass),
273
- }, style: this.getStickyStyle(actualColIdx) }, h("slot", { name: `${this.tableId}-${fieldName}-${this.rowKey}` }, h("span", null, this.getCellValue(col)))));
265
+ }, style: { ...this.getStickyStyle(actualColIdx), ...this.getFramePaddingStyle(fieldName) } }, h("slot", { name: `${this.tableId}-${fieldName}-${this.rowKey}` }, h("span", null, this.getCellValue(col)))));
274
266
  }), stickyRightCols.map((col, relativeIdx) => {
275
267
  const actualColIdx = this.visibleColumns.length - stickyRightCount + relativeIdx;
276
268
  if (this.isCovered(actualColIdx))
@@ -281,14 +273,13 @@ export class SdTr {
281
273
  return (h("td", { key: col.name, rowSpan: span?.rowspan, colSpan: span?.colspan, class: {
282
274
  'td': true,
283
275
  [`td--${col.align || 'left'}`]: true,
284
- 'td--last-row': this.isVisualLastRow(col),
285
276
  'td--before-separator': this.isVisualLastRowBeforeSeparator(col),
286
277
  'sticky-right': true,
287
278
  'sticky-right-edge': relativeIdx === 0,
288
279
  'is-scrolled-right': relativeIdx === 0 && this._scrolledRight,
289
280
  [`${col.tdClass}`]: Boolean(col.tdClass),
290
281
  ...this.expandCellClass(sdCellClass),
291
- }, style: this.getStickyStyle(actualColIdx) }, h("slot", { name: `${this.tableId}-${fieldName}-${this.rowKey}` }, h("span", null, this.getCellValue(col)))));
282
+ }, style: { ...this.getStickyStyle(actualColIdx), ...this.getFramePaddingStyle(fieldName) } }, h("slot", { name: `${this.tableId}-${fieldName}-${this.rowKey}` }, h("span", null, this.getCellValue(col)))));
292
283
  }))));
293
284
  }
294
285
  static get is() { return "sd-tr"; }