@sellmate/design-system 1.0.75 → 1.0.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/design-system.cjs.js +1 -1
- package/dist/cjs/index.cjs.js +5 -0
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/sd-button_4.cjs.entry.js +2 -2
- package/dist/cjs/sd-ghost-button.cjs.entry.js +10 -5
- package/dist/cjs/sd-modal-container.cjs.entry.js +76 -68
- package/dist/cjs/sd-pagination_5.cjs.entry.js +889 -0
- package/dist/cjs/sd-radio-button.cjs.entry.js +6 -1
- package/dist/cjs/sd-select-v2-list-item_4.cjs.entry.js +65 -5
- package/dist/cjs/sd-switch.cjs.entry.js +1 -1
- package/dist/cjs/sd-table.cjs.entry.js +167 -20
- package/dist/cjs/sd-tabs.cjs.entry.js +1 -1
- package/dist/cjs/sd-tag.cjs.entry.js +2 -2
- package/dist/cjs/sd-td.cjs.entry.js +53 -1
- package/dist/cjs/sd-text-link.cjs.entry.js +3 -3
- package/dist/cjs/sd-textarea.cjs.entry.js +1 -1
- package/dist/cjs/sd-toast-container.cjs.entry.js +1 -1
- package/dist/cjs/sd-toast.cjs.entry.js +2 -2
- package/dist/cjs/sd-toggle.cjs.entry.js +1 -1
- package/dist/collection/components/sd-ghost-button/sd-ghost-button.js +10 -5
- package/dist/collection/components/sd-modal-container/sd-modal-container.js +77 -71
- package/dist/collection/components/sd-radio-button/sd-radio-button.js +6 -1
- package/dist/collection/components/sd-select-v2/sd-select-v2-listbox/sd-select-v2-listbox.js +103 -3
- package/dist/collection/components/sd-select-v2/sd-select-v2-trigger/sd-select-v2-trigger.js +2 -2
- package/dist/collection/components/sd-select-v2/sd-select-v2.js +82 -4
- package/dist/collection/components/sd-switch/sd-switch.js +1 -1
- package/dist/collection/components/sd-table/sd-table.css +1 -1
- package/dist/collection/components/sd-table/sd-table.js +170 -21
- package/dist/collection/components/sd-table/sd-tbody/sd-tbody.js +7 -2
- package/dist/collection/components/sd-table/sd-td/sd-td.js +91 -1
- package/dist/collection/components/sd-table/sd-thead/sd-thead.js +9 -4
- package/dist/collection/components/sd-table/sd-tr/sd-tr.css +8 -0
- package/dist/collection/components/sd-table/sd-tr/sd-tr.js +62 -12
- package/dist/collection/components/sd-tabs/sd-tabs.js +1 -1
- package/dist/collection/components/sd-tag/sd-tag.js +2 -2
- package/dist/collection/components/sd-text-link/sd-text-link.js +3 -3
- package/dist/collection/components/sd-textarea/sd-textarea.js +1 -1
- package/dist/collection/components/sd-toast/sd-toast.js +2 -2
- package/dist/collection/components/sd-toast-container/sd-toast-container.js +1 -1
- package/dist/collection/components/sd-toggle/sd-toggle.js +1 -1
- package/dist/collection/components/sd-tooltip/sd-tooltip.js +2 -2
- package/dist/collection/utils/modal.js +5 -0
- package/dist/components/index.js +1 -1
- package/dist/components/{p-BALOEavB.js → p-6AvsuYqF.js} +1 -1
- package/dist/components/{p-CTwEbxRN.js → p-6PsyRF61.js} +1 -1
- package/dist/components/{p-DEBakAhm.js → p-7DKZPPev.js} +1 -1
- package/dist/components/p-BBD_1E3n.js +1 -0
- package/dist/components/p-BQvugXhH.js +1 -0
- package/dist/components/p-BRfPoWUn.js +1 -0
- package/dist/components/{p-CHFGWh0m.js → p-C-BOe23n.js} +1 -1
- package/dist/components/p-C7h8lwnU.js +1 -0
- package/dist/components/{p-SDBnyM8D.js → p-CUg9NH6y.js} +1 -1
- package/dist/components/{p-C3dI7f7C.js → p-CgMyz4NQ.js} +1 -1
- package/dist/components/p-Csfj4h1A.js +1 -0
- package/dist/components/{p-Bp0B8tcl.js → p-DAC3TaZV.js} +1 -1
- package/dist/components/p-DfOYYI9m.js +1 -0
- package/dist/components/{p-H-9uoufd.js → p-d4UB2UF7.js} +1 -1
- package/dist/components/p-eEC3ITv0.js +1 -0
- package/dist/components/{p-CWEeXx2E.js → p-nVHDJc9g.js} +1 -1
- package/dist/components/{p-D8fG9Yt7.js → p-rnbt1m4L.js} +1 -1
- package/dist/components/sd-action-modal.js +1 -1
- package/dist/components/sd-barcode-input.js +1 -1
- package/dist/components/sd-chip.js +1 -1
- package/dist/components/sd-confirm-modal.js +1 -1
- package/dist/components/sd-date-picker-calendar.js +1 -1
- package/dist/components/sd-date-picker.js +1 -1
- package/dist/components/sd-date-range-picker-calendar.js +1 -1
- package/dist/components/sd-date-range-picker.js +1 -1
- package/dist/components/sd-field.js +1 -1
- package/dist/components/sd-file-picker.js +1 -1
- package/dist/components/sd-ghost-button.js +1 -1
- package/dist/components/sd-guide.js +1 -1
- package/dist/components/sd-input.js +1 -1
- package/dist/components/sd-modal-container.js +1 -1
- package/dist/components/sd-number-input.js +1 -1
- package/dist/components/sd-popover.js +1 -1
- package/dist/components/sd-radio-button.js +1 -1
- package/dist/components/sd-select-dropdown.js +1 -1
- package/dist/components/sd-select-group.js +1 -1
- package/dist/components/sd-select-multiple-group.js +1 -1
- package/dist/components/sd-select-multiple.js +1 -1
- package/dist/components/sd-select-search-input.js +1 -1
- package/dist/components/sd-select-v2-listbox.js +1 -1
- package/dist/components/sd-select-v2-trigger.js +1 -1
- package/dist/components/sd-select-v2.js +1 -1
- package/dist/components/sd-select.js +1 -1
- package/dist/components/sd-switch.js +1 -1
- package/dist/components/sd-table.js +1 -1
- package/dist/components/sd-tabs.js +1 -1
- package/dist/components/sd-tag.js +1 -1
- package/dist/components/sd-tbody.js +1 -1
- package/dist/components/sd-td.js +1 -1
- package/dist/components/sd-text-link.js +1 -1
- package/dist/components/sd-textarea.js +1 -1
- package/dist/components/sd-thead.js +1 -1
- package/dist/components/sd-toast-container.js +1 -1
- package/dist/components/sd-toast.js +1 -1
- package/dist/components/sd-toggle.js +1 -1
- package/dist/components/sd-tooltip.js +1 -1
- package/dist/components/sd-tr.js +1 -1
- package/dist/design-system/design-system.esm.js +1 -1
- package/dist/design-system/index.esm.js +1 -1
- package/dist/design-system/p-0e1b27cc.entry.js +1 -0
- package/dist/design-system/p-11029f6e.entry.js +1 -0
- package/dist/design-system/{p-cc62c180.entry.js → p-140b40ab.entry.js} +1 -1
- package/dist/design-system/p-34f7345b.entry.js +1 -0
- package/dist/design-system/p-363c9451.entry.js +1 -0
- package/dist/design-system/{p-fdcfaa7c.entry.js → p-506f2b68.entry.js} +1 -1
- package/dist/design-system/{p-8200b5f2.entry.js → p-531a6a82.entry.js} +1 -1
- package/dist/design-system/p-55b65a41.entry.js +1 -0
- package/dist/design-system/{p-d1dfa0e1.entry.js → p-68d0d67e.entry.js} +1 -1
- package/dist/design-system/p-7fe3a466.entry.js +1 -0
- package/dist/design-system/{p-05a1c092.entry.js → p-9466cd93.entry.js} +1 -1
- package/dist/design-system/{p-33bec0e3.entry.js → p-b683f2fe.entry.js} +1 -1
- package/dist/design-system/p-c521e731.entry.js +1 -0
- package/dist/design-system/{p-16a15368.entry.js → p-c9eb70f5.entry.js} +1 -1
- package/dist/design-system/p-d1846df9.entry.js +1 -0
- package/dist/design-system/{p-2d154fe0.entry.js → p-fdb52620.entry.js} +1 -1
- package/dist/esm/design-system.js +1 -1
- package/dist/esm/index.js +5 -0
- package/dist/esm/loader.js +1 -1
- package/dist/esm/sd-button_4.entry.js +2 -2
- package/dist/esm/sd-ghost-button.entry.js +10 -5
- package/dist/esm/sd-modal-container.entry.js +76 -68
- package/dist/esm/sd-pagination_5.entry.js +883 -0
- package/dist/esm/sd-radio-button.entry.js +6 -1
- package/dist/esm/sd-select-v2-list-item_4.entry.js +65 -5
- package/dist/esm/sd-switch.entry.js +1 -1
- package/dist/esm/sd-table.entry.js +168 -21
- package/dist/esm/sd-tabs.entry.js +1 -1
- package/dist/esm/sd-tag.entry.js +2 -2
- package/dist/esm/sd-td.entry.js +53 -1
- package/dist/esm/sd-text-link.entry.js +3 -3
- package/dist/esm/sd-textarea.entry.js +1 -1
- package/dist/esm/sd-toast-container.entry.js +1 -1
- package/dist/esm/sd-toast.entry.js +2 -2
- package/dist/esm/sd-toggle.entry.js +1 -1
- package/dist/types/components/sd-ghost-button/sd-ghost-button.d.ts +1 -0
- package/dist/types/components/sd-modal-container/sd-modal-container.config.d.ts +1 -1
- package/dist/types/components/sd-modal-container/sd-modal-container.d.ts +6 -4
- package/dist/types/components/sd-radio-button/sd-radio-button.d.ts +1 -0
- package/dist/types/components/sd-select-v2/sd-select-v2-listbox/sd-select-v2-listbox.d.ts +9 -0
- package/dist/types/components/sd-select-v2/sd-select-v2.d.ts +4 -0
- package/dist/types/components/sd-table/sd-table.d.ts +17 -0
- package/dist/types/components/sd-table/sd-td/sd-td.d.ts +8 -0
- package/dist/types/components/sd-table/sd-tr/sd-tr.d.ts +4 -0
- package/dist/types/components.d.ts +52 -0
- package/hydrate/index.js +481 -141
- package/hydrate/index.mjs +481 -141
- package/package.json +1 -1
- package/dist/cjs/sd-pagination_2.cjs.entry.js +0 -427
- package/dist/cjs/sd-tbody.cjs.entry.js +0 -66
- package/dist/cjs/sd-thead.cjs.entry.js +0 -179
- package/dist/cjs/sd-tr.cjs.entry.js +0 -171
- package/dist/components/p-Bbs5Ws0k.js +0 -1
- package/dist/components/p-CgL8_FSD.js +0 -1
- package/dist/components/p-DuMkBStM.js +0 -1
- package/dist/components/p-vQDL-PZ8.js +0 -1
- package/dist/design-system/p-380198bc.entry.js +0 -1
- package/dist/design-system/p-6b537e2f.entry.js +0 -1
- package/dist/design-system/p-6e90fb80.entry.js +0 -1
- package/dist/design-system/p-7b77c65c.entry.js +0 -1
- package/dist/design-system/p-8f88bd67.entry.js +0 -1
- package/dist/design-system/p-ba5fea6f.entry.js +0 -1
- package/dist/design-system/p-be54d6bd.entry.js +0 -1
- package/dist/design-system/p-c3379a6e.entry.js +0 -1
- package/dist/design-system/p-dc07d618.entry.js +0 -1
- package/dist/design-system/p-ef09409c.entry.js +0 -1
- package/dist/design-system/p-f8237991.entry.js +0 -1
- package/dist/esm/sd-pagination_2.entry.js +0 -424
- package/dist/esm/sd-tbody.entry.js +0 -64
- package/dist/esm/sd-thead.entry.js +0 -177
- package/dist/esm/sd-tr.entry.js +0 -169
|
@@ -40,7 +40,7 @@ export class SdSwitch {
|
|
|
40
40
|
'--sd-switch-line-height': `${SWITCH_TYPOGRAPHY.lineHeight}px`,
|
|
41
41
|
'--sd-switch-text-decoration': SWITCH_TYPOGRAPHY.textDecoration,
|
|
42
42
|
};
|
|
43
|
-
return (h("label", { key: '
|
|
43
|
+
return (h("label", { key: '469c012285d3c8a33792a460e74d8566c384efe8', "aria-label": this.label || 'switch', class: this.switchClasses, style: cssVars }, h("input", { key: '9678e3325339a47e3e2d81ce3cd752c86ed0f906', type: "checkbox", checked: this.value, disabled: this.disabled, onInput: this.handleChange }), h("div", { key: '47348914869f5215957a652cfcf3a11807a0216f', class: "sd-switch__track" }, h("div", { key: '0676260c42e6b79acec710f0f9ba72f01a3a7c18', class: "sd-switch__knob" })), this.label && h("span", { key: 'b92597092795bff38d2acf0cff76f9c381435438', class: "sd-switch__label" }, this.label)));
|
|
44
44
|
}
|
|
45
45
|
static get is() { return "sd-switch"; }
|
|
46
46
|
static get originalStyleUrls() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { h, Host, readTask, } from "@stencil/core";
|
|
1
|
+
import { h, Host, readTask, forceUpdate, } from "@stencil/core";
|
|
2
2
|
import { nanoid } from "nanoid";
|
|
3
3
|
import { TABLE_ID_ATTR, } from "./constants";
|
|
4
4
|
export class SdTable {
|
|
@@ -47,11 +47,17 @@ export class SdTable {
|
|
|
47
47
|
scrolledRight = false;
|
|
48
48
|
rowCount = 0;
|
|
49
49
|
loadingScrollTop = 0;
|
|
50
|
+
// light DOM에 sd-thead / sd-tbody 자식이 없으면 sd-table이 직접 렌더해야 함을 알리는 플래그.
|
|
51
|
+
// componentWillLoad에서 한 번 결정되며, 이후 동적 토글은 지원하지 않는다.
|
|
52
|
+
autoThead = false;
|
|
53
|
+
autoTbody = false;
|
|
50
54
|
vsStart = 0;
|
|
51
55
|
vsEnd = 0;
|
|
52
56
|
lastReachEndNotifiedRowCount = -1;
|
|
53
57
|
scrollContainer = null;
|
|
54
58
|
onScroll;
|
|
59
|
+
// 키: `${rowKey}::${field}` → { rowspan, colspan }
|
|
60
|
+
spanRegistry = new Map();
|
|
55
61
|
toFiniteNumber(value, fallback) {
|
|
56
62
|
const n = typeof value === 'number' ? value : Number(value);
|
|
57
63
|
return Number.isFinite(n) ? n : fallback;
|
|
@@ -130,9 +136,16 @@ export class SdTable {
|
|
|
130
136
|
this.innerRowsPerPage = newVal.rowsPerPage;
|
|
131
137
|
}
|
|
132
138
|
}
|
|
139
|
+
detectChildren() {
|
|
140
|
+
const hasThead = !!this.el.querySelector(':scope > sd-thead');
|
|
141
|
+
const hasTbody = !!this.el.querySelector(':scope > sd-tbody');
|
|
142
|
+
this.autoThead = !hasThead;
|
|
143
|
+
this.autoTbody = !hasTbody;
|
|
144
|
+
}
|
|
133
145
|
componentWillLoad() {
|
|
134
146
|
this.syncTableIdAttribute();
|
|
135
147
|
this.handleNoDataLabelChange(this.noDataLabel);
|
|
148
|
+
this.detectChildren();
|
|
136
149
|
this.innerSelected = new Set(this.selected || []);
|
|
137
150
|
this.columnWidths = (this.columns || []).map(c => parseInt(c.width || '120', 10));
|
|
138
151
|
if (this.pagination?.page) {
|
|
@@ -155,6 +168,11 @@ export class SdTable {
|
|
|
155
168
|
el.getTableIdSync = () => this.getResolvedTableId();
|
|
156
169
|
el.getVirtualScrollConfigSync = this.getVirtualScrollConfigSync.bind(this);
|
|
157
170
|
el.calculateVisibleRange = this.calculateVisibleRange.bind(this);
|
|
171
|
+
el.registerSpanSync = this.registerSpanSync.bind(this);
|
|
172
|
+
el.unregisterSpanSync = this.unregisterSpanSync.bind(this);
|
|
173
|
+
el.getSpanSync = this.getSpanSync.bind(this);
|
|
174
|
+
el.isCoveredSync = this.isCoveredSync.bind(this);
|
|
175
|
+
el.hasRowspanSync = this.hasRowspanSync.bind(this);
|
|
158
176
|
if (Array.isArray(this.rows)) {
|
|
159
177
|
this.rowCount = this.rows.length;
|
|
160
178
|
this.pushRowsToChildren(this.rows);
|
|
@@ -203,11 +221,22 @@ export class SdTable {
|
|
|
203
221
|
this.scrollContainer.removeEventListener('scroll', this.onScroll);
|
|
204
222
|
}
|
|
205
223
|
}
|
|
224
|
+
// light DOM(manual mode 자식)과 shadow DOM(autoThead/autoTbody fallback) 양쪽 모두에서 자식을 찾는다.
|
|
225
|
+
queryChildEl(selector) {
|
|
226
|
+
return (this.el.querySelector(selector) ??
|
|
227
|
+
this.el.shadowRoot?.querySelector(selector) ??
|
|
228
|
+
null);
|
|
229
|
+
}
|
|
230
|
+
queryAllTr() {
|
|
231
|
+
const light = Array.from(this.el.querySelectorAll('sd-tr'));
|
|
232
|
+
const shadow = Array.from(this.el.shadowRoot?.querySelectorAll('sd-tr') ?? []);
|
|
233
|
+
return [...light, ...shadow];
|
|
234
|
+
}
|
|
206
235
|
pushRowsToChildren(rows) {
|
|
207
|
-
const tbody = this.
|
|
236
|
+
const tbody = this.queryChildEl('sd-tbody');
|
|
208
237
|
if (tbody)
|
|
209
238
|
tbody.rows = rows;
|
|
210
|
-
const thead = this.
|
|
239
|
+
const thead = this.queryChildEl('sd-thead');
|
|
211
240
|
if (thead)
|
|
212
241
|
thead.rows = rows;
|
|
213
242
|
}
|
|
@@ -218,16 +247,14 @@ export class SdTable {
|
|
|
218
247
|
this.refreshChildrenConfig();
|
|
219
248
|
};
|
|
220
249
|
refreshChildrenSelection() {
|
|
221
|
-
const thead = this.
|
|
222
|
-
const rows = this.el.querySelectorAll('sd-tr');
|
|
250
|
+
const thead = this.queryChildEl('sd-thead');
|
|
223
251
|
thead?.refreshSelection?.();
|
|
224
|
-
|
|
252
|
+
this.queryAllTr().forEach(tr => tr?.refreshSelection?.());
|
|
225
253
|
}
|
|
226
254
|
refreshChildrenConfig() {
|
|
227
|
-
const thead = this.
|
|
228
|
-
const rows = this.el.querySelectorAll('sd-tr');
|
|
255
|
+
const thead = this.queryChildEl('sd-thead');
|
|
229
256
|
thead?.refreshConfig?.();
|
|
230
|
-
|
|
257
|
+
this.queryAllTr().forEach(tr => tr?.refreshConfig?.());
|
|
231
258
|
}
|
|
232
259
|
maybeEmitVirtualReachEnd(start, end) {
|
|
233
260
|
const threshold = Math.max(1, this.virtualEndThreshold);
|
|
@@ -259,7 +286,7 @@ export class SdTable {
|
|
|
259
286
|
this.vsEnd = end;
|
|
260
287
|
const topHeight = start * this.rowHeight;
|
|
261
288
|
const bottomHeight = Math.max(0, (this.rowCount - end) * this.rowHeight);
|
|
262
|
-
const tbody = this.
|
|
289
|
+
const tbody = this.queryChildEl('sd-tbody');
|
|
263
290
|
tbody?.setSpacersSync?.(topHeight, bottomHeight);
|
|
264
291
|
if (rangeChanged) {
|
|
265
292
|
this.sdVirtualUpdate.emit({
|
|
@@ -351,8 +378,7 @@ export class SdTable {
|
|
|
351
378
|
this.updateRowsVisibility();
|
|
352
379
|
}
|
|
353
380
|
updateRowsVisibility() {
|
|
354
|
-
|
|
355
|
-
rows.forEach(tr => tr?.updateVisibility?.());
|
|
381
|
+
this.queryAllTr().forEach(tr => tr?.updateVisibility?.());
|
|
356
382
|
}
|
|
357
383
|
changeRowsPerPage(perPage) {
|
|
358
384
|
const changedRowsPerPage = perPage ? Number(perPage) : 0;
|
|
@@ -389,10 +415,9 @@ export class SdTable {
|
|
|
389
415
|
const delta = moveEvent.clientX - startX;
|
|
390
416
|
const newWidth = Math.min(Math.max(startWidth + (reversed ? -delta : delta), minWidth), maxWidth);
|
|
391
417
|
this.columnWidths = this.columnWidths.map((width, idx) => (idx === index ? newWidth : width));
|
|
392
|
-
const thead = this.
|
|
393
|
-
const rows = this.el.querySelectorAll('sd-tr');
|
|
418
|
+
const thead = this.queryChildEl('sd-thead');
|
|
394
419
|
thead?.setColumnWidths?.(this.columnWidths);
|
|
395
|
-
|
|
420
|
+
this.queryAllTr().forEach(tr => tr?.setColumnWidths?.(this.columnWidths));
|
|
396
421
|
const stickyRightCount = this.stickyColumn?.right || 0;
|
|
397
422
|
const visibleColCount = this.columns.filter(c => c.visible !== false).length;
|
|
398
423
|
const isRightStickyEdgeResizer = stickyRightCount > 0 && index === visibleColCount - stickyRightCount;
|
|
@@ -429,6 +454,112 @@ export class SdTable {
|
|
|
429
454
|
async getStickyStyle(colIdx) {
|
|
430
455
|
return this.getStickyStyleSync(colIdx);
|
|
431
456
|
}
|
|
457
|
+
// ─── rowspan / colspan registry ─────────────────────────────────
|
|
458
|
+
// sd-td가 mount/unmount 시 자기 (rowKey, field)와 span을 등록한다.
|
|
459
|
+
// sd-tr는 render마다 isCoveredSync로 자신의 셀 위치가 다른 셀의 span에
|
|
460
|
+
// 덮였는지 판정해 <td>를 그릴지 결정한다.
|
|
461
|
+
spanKey(rowKey, field) {
|
|
462
|
+
return `${rowKey}::${field}`;
|
|
463
|
+
}
|
|
464
|
+
// span 등록은 sd-td의 lifecycle에서 비동기적으로 일어나므로,
|
|
465
|
+
// 등록/해제 직후 형제 sd-tr들이 새 레지스트리 상태로 다시 그려져야
|
|
466
|
+
// 덮인 셀이 사라지거나 다시 나타난다.
|
|
467
|
+
// forceUpdate는 React 래퍼 환경에서 prop 동기화 사이클과 부딪혀 누락되는
|
|
468
|
+
// 경우가 있어, sd-tr의 @State (spansVersion)을 통해 재렌더를 강제한다.
|
|
469
|
+
requestAllTrUpdate() {
|
|
470
|
+
this.queryAllTr().forEach(tr => {
|
|
471
|
+
const trAny = tr;
|
|
472
|
+
if (typeof trAny.bumpSpansVersion === 'function') {
|
|
473
|
+
trAny.bumpSpansVersion();
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
forceUpdate(tr);
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
registerSpanSync(rowKey, field, rowspan, colspan) {
|
|
481
|
+
if (rowKey == null || !field)
|
|
482
|
+
return;
|
|
483
|
+
const safeRowspan = Math.max(1, Math.floor(rowspan || 1));
|
|
484
|
+
const safeColspan = Math.max(1, Math.floor(colspan || 1));
|
|
485
|
+
const key = this.spanKey(rowKey, field);
|
|
486
|
+
const prev = this.spanRegistry.get(key);
|
|
487
|
+
if (safeRowspan === 1 && safeColspan === 1) {
|
|
488
|
+
if (!prev)
|
|
489
|
+
return;
|
|
490
|
+
this.spanRegistry.delete(key);
|
|
491
|
+
this.requestAllTrUpdate();
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (prev && prev.rowspan === safeRowspan && prev.colspan === safeColspan)
|
|
495
|
+
return;
|
|
496
|
+
this.spanRegistry.set(key, { rowspan: safeRowspan, colspan: safeColspan });
|
|
497
|
+
this.requestAllTrUpdate();
|
|
498
|
+
}
|
|
499
|
+
unregisterSpanSync(rowKey, field) {
|
|
500
|
+
if (rowKey == null || !field)
|
|
501
|
+
return;
|
|
502
|
+
const key = this.spanKey(rowKey, field);
|
|
503
|
+
if (!this.spanRegistry.has(key))
|
|
504
|
+
return;
|
|
505
|
+
this.spanRegistry.delete(key);
|
|
506
|
+
this.requestAllTrUpdate();
|
|
507
|
+
}
|
|
508
|
+
getSpanSync(rowKey, field) {
|
|
509
|
+
return this.spanRegistry.get(this.spanKey(rowKey, field));
|
|
510
|
+
}
|
|
511
|
+
// 레지스트리에 rowspan>1 항목이 하나라도 있으면 true.
|
|
512
|
+
// hover 동작을 끌지 결정하는 데 사용 — colspan만 있는 경우는 그대로 hover 유지.
|
|
513
|
+
hasRowspanSync() {
|
|
514
|
+
for (const span of this.spanRegistry.values()) {
|
|
515
|
+
if (span.rowspan > 1)
|
|
516
|
+
return true;
|
|
517
|
+
}
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
isCoveredSync(rowKey, colIdx, columns) {
|
|
521
|
+
if (this.spanRegistry.size === 0)
|
|
522
|
+
return false;
|
|
523
|
+
const visibleCols = columns.filter(c => c.visible !== false);
|
|
524
|
+
// 1. 같은 행 왼쪽 스캔 — colspan으로 이 위치를 덮는 셀이 있는가
|
|
525
|
+
for (let i = 0; i < colIdx; i++) {
|
|
526
|
+
const c = visibleCols[i];
|
|
527
|
+
if (!c)
|
|
528
|
+
continue;
|
|
529
|
+
const field = typeof c.field === 'string' ? c.field : c.name;
|
|
530
|
+
const span = this.spanRegistry.get(this.spanKey(rowKey, field));
|
|
531
|
+
if (!span)
|
|
532
|
+
continue;
|
|
533
|
+
if (i + span.colspan > colIdx)
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
// 2. 위쪽 행 스캔 — 숫자 변환 가능한 rowKey만 rowspan 평가
|
|
537
|
+
const myRowIdx = Number(rowKey);
|
|
538
|
+
if (!Number.isFinite(myRowIdx))
|
|
539
|
+
return false;
|
|
540
|
+
for (const [key, span] of this.spanRegistry) {
|
|
541
|
+
if (span.rowspan <= 1)
|
|
542
|
+
continue;
|
|
543
|
+
const sepIdx = key.indexOf('::');
|
|
544
|
+
if (sepIdx < 0)
|
|
545
|
+
continue;
|
|
546
|
+
const otherRowKey = key.slice(0, sepIdx);
|
|
547
|
+
const otherField = key.slice(sepIdx + 2);
|
|
548
|
+
const otherRowIdx = Number(otherRowKey);
|
|
549
|
+
if (!Number.isFinite(otherRowIdx))
|
|
550
|
+
continue;
|
|
551
|
+
if (otherRowIdx >= myRowIdx)
|
|
552
|
+
continue;
|
|
553
|
+
if (otherRowIdx + span.rowspan <= myRowIdx)
|
|
554
|
+
continue;
|
|
555
|
+
const otherColIdx = visibleCols.findIndex(c => (typeof c.field === 'string' ? c.field : c.name) === otherField);
|
|
556
|
+
if (otherColIdx < 0)
|
|
557
|
+
continue;
|
|
558
|
+
if (otherColIdx <= colIdx && otherColIdx + span.colspan > colIdx)
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
432
563
|
setRowCountSync(count) {
|
|
433
564
|
const safeCount = Math.max(0, Math.floor(this.toFiniteNumber(count, 0)));
|
|
434
565
|
if (safeCount !== this.rowCount) {
|
|
@@ -476,6 +607,22 @@ export class SdTable {
|
|
|
476
607
|
return null;
|
|
477
608
|
return { from: this.vsStart, to: this.vsEnd };
|
|
478
609
|
}
|
|
610
|
+
// autoTbody fallback에서 sd-table이 직접 sd-tr을 만들어내는 경로.
|
|
611
|
+
// 가상 스크롤은 사용자가 직접 SdTbody+SdTr을 작성해야 하므로 빈 배열을 반환한다.
|
|
612
|
+
renderAutoRows() {
|
|
613
|
+
if (this.useVirtualScroll)
|
|
614
|
+
return null;
|
|
615
|
+
const allRows = this.rows ?? [];
|
|
616
|
+
const pageInfo = this.getPaginationInfoSync();
|
|
617
|
+
const startIdx = pageInfo?.startIndex ?? 0;
|
|
618
|
+
const displayed = pageInfo
|
|
619
|
+
? allRows.slice(pageInfo.startIndex, pageInfo.endIndex)
|
|
620
|
+
: allRows;
|
|
621
|
+
return displayed.map((row, i) => {
|
|
622
|
+
const absoluteIdx = startIdx + i;
|
|
623
|
+
return (h("sd-tr", { key: absoluteIdx, "row-key": String(absoluteIdx), row: row }));
|
|
624
|
+
});
|
|
625
|
+
}
|
|
479
626
|
get tableClasses() {
|
|
480
627
|
return [
|
|
481
628
|
'sd-table',
|
|
@@ -495,24 +642,24 @@ export class SdTable {
|
|
|
495
642
|
}
|
|
496
643
|
render() {
|
|
497
644
|
const resolvedTableId = this.getResolvedTableId();
|
|
498
|
-
return (h(Host, { key: '
|
|
645
|
+
return (h(Host, { key: 'd73cd690ad11ce92af37b6f32374f6f891c5b677' }, h("div", { key: 'f51d23212885ad8121b9a4e895fb854f1e142bc4', class: "sd-table__container", style: {
|
|
499
646
|
'--table-width': this.width,
|
|
500
647
|
'--table-height': this.height,
|
|
501
648
|
'--table-container-height': `calc(${this.height || '100%'} - ${this.pagination && this.rowCount > 0 && !this.useVirtualScroll ? 48 : 0}px)`,
|
|
502
|
-
} }, h("div", { key: '
|
|
649
|
+
} }, h("div", { key: '84b1ba7b2220ff55304b9c19e59304ca2257cff0', class: {
|
|
503
650
|
'sd-table__clip': true,
|
|
504
651
|
'sd-table__clip--has-pagination': !!(this.pagination &&
|
|
505
652
|
this.pagination.rowsPerPage > 0 &&
|
|
506
653
|
this.rowCount > 0 &&
|
|
507
654
|
!this.useVirtualScroll),
|
|
508
|
-
} }, h("div", { key: '
|
|
655
|
+
} }, h("div", { key: 'c901eba67eae29515bf0b3edcc6632b2aacf0f80', class: {
|
|
509
656
|
'sd-table__wrapper': true,
|
|
510
657
|
'sd-table__wrapper--loading': this.isLoading,
|
|
511
658
|
'sd-table__wrapper--no-data': this.rowCount === 0 && !this.isLoading,
|
|
512
|
-
} }, this.isLoading && (h("div", { key: '
|
|
659
|
+
} }, this.isLoading && (h("div", { key: '35a237d0203b2479dbdb77ac42c918a9375bdfd3', class: "sd-table__loading", style: { top: `${this.loadingScrollTop}px` } }, h("sd-circle-progress", { key: '21a29981c1cdbd679f46abd2e7de7794c9ebbca9', indeterminate: true }))), this.rowCount === 0 && !this.isLoading && (h("div", { key: '07ad28bc6e7556cfe229fc1e952410f388424a7f', class: "sd-table__no-data" }, h("slot", { key: 'bf21e60f5b86614587b704bea2965b9467c7f467', name: "no-data" }, h("span", { key: 'f3d012d12e9189545b0cef52250502d46cb9a764' }, this.resolvedNoDataLabel)))), h("table", { key: '655d3dc017c6445ec454faef0e5e9837b7ee0013', 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 &&
|
|
513
660
|
this.pagination.rowsPerPage > 0 &&
|
|
514
661
|
this.rowCount > 0 &&
|
|
515
|
-
!this.useVirtualScroll && (h("div", { key: '
|
|
662
|
+
!this.useVirtualScroll && (h("div", { key: '7ab0b30a0c0e0a197b0f79c6b07ef5614d5d2879', class: "sd-table__pagination" }, h("sd-pagination", { key: '71d44bba5a82f4d8f7c067e525db15fe9a36c305', 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-v2", { key: 'a9ab33347db0714da188f658a2ca1902502db690', value: this.useInternalPagination
|
|
516
663
|
? this.innerRowsPerPage
|
|
517
664
|
: this.pagination.rowsPerPage, options: this.rowsPerPageOption, width: "128px", emitValue: true, onSdUpdate: e => {
|
|
518
665
|
if (!this.isRowsPerPageValue(e.detail))
|
|
@@ -992,7 +1139,9 @@ export class SdTable {
|
|
|
992
1139
|
"scrolledLeft": {},
|
|
993
1140
|
"scrolledRight": {},
|
|
994
1141
|
"rowCount": {},
|
|
995
|
-
"loadingScrollTop": {}
|
|
1142
|
+
"loadingScrollTop": {},
|
|
1143
|
+
"autoThead": {},
|
|
1144
|
+
"autoTbody": {}
|
|
996
1145
|
};
|
|
997
1146
|
}
|
|
998
1147
|
static get events() {
|
|
@@ -28,7 +28,12 @@ export class SdTbody {
|
|
|
28
28
|
this.syncTableContext();
|
|
29
29
|
}
|
|
30
30
|
syncTableContext() {
|
|
31
|
-
|
|
31
|
+
// sd-table이 shadow:true이므로 fallback content로 렌더되면 closest가 경계를 못 넘는다.
|
|
32
|
+
// 그 경우 getRootNode().host(=sd-table)로 폴백한다.
|
|
33
|
+
const closest = this.el.closest('sd-table');
|
|
34
|
+
const root = this.el.getRootNode();
|
|
35
|
+
const fromShadow = root instanceof ShadowRoot ? root.host : null;
|
|
36
|
+
const table = closest ?? fromShadow;
|
|
32
37
|
this.tableEl = table;
|
|
33
38
|
const fromMethod = table?.getTableIdSync?.();
|
|
34
39
|
const fromAttr = table?.getAttribute(TABLE_ID_ATTR);
|
|
@@ -41,7 +46,7 @@ export class SdTbody {
|
|
|
41
46
|
}
|
|
42
47
|
render() {
|
|
43
48
|
const hasRows = this.rows.length > 0;
|
|
44
|
-
return (h(Host, { key: '
|
|
49
|
+
return (h(Host, { key: 'bc9fbd4f08f4d77da60b083dceef4e24e2fb5532', slot: `${this.tableId}-body` }, h("tbody", { key: '81ef875cbc39f988021a211ede716a98d3ea30cd', class: { 'tbody': true, 'tbody--empty': !hasRows } }, hasRows ? ([
|
|
45
50
|
this.topSpacerHeight > 0 && (h("tr", { key: "spacer-top", class: "tbody__spacer", style: { height: `${this.topSpacerHeight}px`, display: 'block' } })),
|
|
46
51
|
h("slot", null),
|
|
47
52
|
this.bottomSpacerHeight > 0 && (h("tr", { key: "spacer-bottom", class: "tbody__spacer", style: { height: `${this.bottomSpacerHeight}px`, display: 'block' } })),
|
|
@@ -5,14 +5,22 @@ export class SdTd {
|
|
|
5
5
|
field;
|
|
6
6
|
rowKey;
|
|
7
7
|
align;
|
|
8
|
+
rowspan;
|
|
9
|
+
colspan;
|
|
8
10
|
handleFieldChange() {
|
|
9
11
|
this.syncSlotName();
|
|
12
|
+
this.syncSpanRegistration();
|
|
10
13
|
}
|
|
11
14
|
handleRowKeyChange() {
|
|
12
15
|
this.syncSlotName();
|
|
16
|
+
this.syncSpanRegistration();
|
|
17
|
+
}
|
|
18
|
+
handleSpanChange() {
|
|
19
|
+
this.syncSpanRegistration();
|
|
13
20
|
}
|
|
14
21
|
componentWillLoad() {
|
|
15
22
|
this.syncSlotName();
|
|
23
|
+
this.syncSpanRegistration();
|
|
16
24
|
// slot 타이밍 엇갈림 대응: 부모 sd-tr forceUpdate로 슬롯 재매칭
|
|
17
25
|
const parentTr = this.el.parentElement;
|
|
18
26
|
if (parentTr?.tagName?.toLowerCase() === 'sd-tr') {
|
|
@@ -21,6 +29,44 @@ export class SdTd {
|
|
|
21
29
|
}
|
|
22
30
|
componentDidLoad() {
|
|
23
31
|
this.syncSlotName();
|
|
32
|
+
this.syncSpanRegistration();
|
|
33
|
+
}
|
|
34
|
+
// React StrictMode에서는 disconnect/reconnect 사이클이 일어나면서
|
|
35
|
+
// 동일 인스턴스의 componentWillLoad는 더 이상 호출되지 않는다.
|
|
36
|
+
// 재연결 시점에도 등록 상태를 복구해야 rowspan/colspan이 유지된다.
|
|
37
|
+
connectedCallback() {
|
|
38
|
+
this.syncSpanRegistration();
|
|
39
|
+
}
|
|
40
|
+
disconnectedCallback() {
|
|
41
|
+
const table = this.findTable();
|
|
42
|
+
if (table?.unregisterSpanSync && this.field && this.rowKey != null) {
|
|
43
|
+
table.unregisterSpanSync(String(this.rowKey), this.field);
|
|
44
|
+
this.requestParentTrUpdate();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
findTable() {
|
|
48
|
+
return this.el.closest('sd-table');
|
|
49
|
+
}
|
|
50
|
+
requestParentTrUpdate() {
|
|
51
|
+
const parentTr = this.el.parentElement;
|
|
52
|
+
if (parentTr?.tagName?.toLowerCase() !== 'sd-tr')
|
|
53
|
+
return;
|
|
54
|
+
const trAny = parentTr;
|
|
55
|
+
if (typeof trAny.bumpSpansVersion === 'function') {
|
|
56
|
+
trAny.bumpSpansVersion();
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
forceUpdate(parentTr);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
syncSpanRegistration() {
|
|
63
|
+
const table = this.findTable();
|
|
64
|
+
if (!table?.registerSpanSync || !this.field || this.rowKey == null)
|
|
65
|
+
return;
|
|
66
|
+
const rs = Math.max(1, Math.floor(Number(this.rowspan) || 1));
|
|
67
|
+
const cs = Math.max(1, Math.floor(Number(this.colspan) || 1));
|
|
68
|
+
table.registerSpanSync(String(this.rowKey), this.field, rs, cs);
|
|
69
|
+
this.requestParentTrUpdate();
|
|
24
70
|
}
|
|
25
71
|
syncSlotName() {
|
|
26
72
|
const table = this.el.closest('sd-table');
|
|
@@ -34,7 +80,7 @@ export class SdTd {
|
|
|
34
80
|
}
|
|
35
81
|
}
|
|
36
82
|
render() {
|
|
37
|
-
return (h(Host, { key: '
|
|
83
|
+
return (h(Host, { key: 'da9ce2edb986d4b3cf1a6e5f59030009f1288250', class: { [`align-${this.align}`]: Boolean(this.align) } }, h("slot", { key: '8514071bd38c4f5b1997ae7239b8585a25f97ce0' })));
|
|
38
84
|
}
|
|
39
85
|
static get is() { return "sd-td"; }
|
|
40
86
|
static get originalStyleUrls() {
|
|
@@ -105,6 +151,44 @@ export class SdTd {
|
|
|
105
151
|
"setter": false,
|
|
106
152
|
"reflect": false,
|
|
107
153
|
"attribute": "align"
|
|
154
|
+
},
|
|
155
|
+
"rowspan": {
|
|
156
|
+
"type": "number",
|
|
157
|
+
"mutable": false,
|
|
158
|
+
"complexType": {
|
|
159
|
+
"original": "number",
|
|
160
|
+
"resolved": "number | undefined",
|
|
161
|
+
"references": {}
|
|
162
|
+
},
|
|
163
|
+
"required": false,
|
|
164
|
+
"optional": true,
|
|
165
|
+
"docs": {
|
|
166
|
+
"tags": [],
|
|
167
|
+
"text": ""
|
|
168
|
+
},
|
|
169
|
+
"getter": false,
|
|
170
|
+
"setter": false,
|
|
171
|
+
"reflect": false,
|
|
172
|
+
"attribute": "rowspan"
|
|
173
|
+
},
|
|
174
|
+
"colspan": {
|
|
175
|
+
"type": "number",
|
|
176
|
+
"mutable": false,
|
|
177
|
+
"complexType": {
|
|
178
|
+
"original": "number",
|
|
179
|
+
"resolved": "number | undefined",
|
|
180
|
+
"references": {}
|
|
181
|
+
},
|
|
182
|
+
"required": false,
|
|
183
|
+
"optional": true,
|
|
184
|
+
"docs": {
|
|
185
|
+
"tags": [],
|
|
186
|
+
"text": ""
|
|
187
|
+
},
|
|
188
|
+
"getter": false,
|
|
189
|
+
"setter": false,
|
|
190
|
+
"reflect": false,
|
|
191
|
+
"attribute": "colspan"
|
|
108
192
|
}
|
|
109
193
|
};
|
|
110
194
|
}
|
|
@@ -116,6 +200,12 @@ export class SdTd {
|
|
|
116
200
|
}, {
|
|
117
201
|
"propName": "rowKey",
|
|
118
202
|
"methodName": "handleRowKeyChange"
|
|
203
|
+
}, {
|
|
204
|
+
"propName": "rowspan",
|
|
205
|
+
"methodName": "handleSpanChange"
|
|
206
|
+
}, {
|
|
207
|
+
"propName": "colspan",
|
|
208
|
+
"methodName": "handleSpanChange"
|
|
119
209
|
}];
|
|
120
210
|
}
|
|
121
211
|
}
|
|
@@ -38,7 +38,12 @@ export class SdThead {
|
|
|
38
38
|
this.resolveConfig();
|
|
39
39
|
}
|
|
40
40
|
syncTableContext() {
|
|
41
|
-
|
|
41
|
+
// sd-table이 shadow:true이므로 fallback content로 렌더되면 closest가 경계를 못 넘는다.
|
|
42
|
+
// 그 경우 getRootNode().host(=sd-table)로 폴백한다.
|
|
43
|
+
const closest = this.el.closest('sd-table');
|
|
44
|
+
const root = this.el.getRootNode();
|
|
45
|
+
const fromShadow = root instanceof ShadowRoot ? root.host : null;
|
|
46
|
+
const table = closest ?? fromShadow;
|
|
42
47
|
this.tableEl = table;
|
|
43
48
|
const fromMethod = table?.getTableIdSync?.();
|
|
44
49
|
const fromAttr = table?.getAttribute(TABLE_ID_ATTR);
|
|
@@ -128,16 +133,16 @@ export class SdThead {
|
|
|
128
133
|
const stickyLeftCols = this.visibleColumns.slice(0, stickyLeftCount);
|
|
129
134
|
const middleCols = this.visibleColumns.slice(stickyLeftCount, this.visibleColumns.length - stickyRightCount);
|
|
130
135
|
const stickyRightCols = this.visibleColumns.slice(this.visibleColumns.length - stickyRightCount);
|
|
131
|
-
return (h(Host, { key: '
|
|
136
|
+
return (h(Host, { key: '5aa1e38311b542d1a0b05b55abc7ef41927508bd', slot: `${this.tableId}-head` }, h("thead", { key: '6d17753988ecd02d900d8a3bd7f2115b534b68a7', class: {
|
|
132
137
|
'thead': true,
|
|
133
138
|
'thead--sticky': this._stickyHeader,
|
|
134
|
-
} }, h("tr", { key: '
|
|
139
|
+
} }, h("tr", { key: '9cc729603e126da2f9c8923fe29ece10c7750bb4', class: "tr" }, this._selectable && (h("th", { key: '37b2bcfa77eaf4c44465684c49ae84d566acc18b', class: {
|
|
135
140
|
'th': true,
|
|
136
141
|
'th--selected': true,
|
|
137
142
|
'sticky-left': true,
|
|
138
143
|
'sticky-left-edge': stickyLeftCount === 0,
|
|
139
144
|
'is-scrolled-left': stickyLeftCount === 0 && this._scrolledLeft,
|
|
140
|
-
}, style: { '--sticky-left-offset': '0px' } }, h("sd-checkbox", { key: '
|
|
145
|
+
}, style: { '--sticky-left-offset': '0px' } }, h("sd-checkbox", { key: '4284894821640ee1bdbd12b1759efb01e6c06488', value: this.getIsAllChecked(), disabled: !safeRows.length, onSdUpdate: (e) => this.handleSelectAll(e.detail) }))), stickyLeftCols.map((col, idx) => (h("th", { key: col.name, class: {
|
|
141
146
|
'th': true,
|
|
142
147
|
[`${col.thClass}`]: Boolean(col.thClass),
|
|
143
148
|
'sticky-left': true,
|
|
@@ -11,6 +11,9 @@ sd-tr * {
|
|
|
11
11
|
.tr:hover .td {
|
|
12
12
|
background-color: #F9F9F9;
|
|
13
13
|
}
|
|
14
|
+
.tr--no-hover:hover .td {
|
|
15
|
+
background-color: white;
|
|
16
|
+
}
|
|
14
17
|
|
|
15
18
|
.td {
|
|
16
19
|
display: table-cell;
|
|
@@ -108,4 +111,9 @@ sd-tr * {
|
|
|
108
111
|
.tr:hover .td.sticky-left,
|
|
109
112
|
.tr:hover .td.sticky-right {
|
|
110
113
|
background-color: #F9F9F9;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.tr--no-hover:hover .td.sticky-left,
|
|
117
|
+
.tr--no-hover:hover .td.sticky-right {
|
|
118
|
+
background-color: white;
|
|
111
119
|
}
|