@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.
Files changed (173) hide show
  1. package/dist/cjs/design-system.cjs.js +1 -1
  2. package/dist/cjs/index.cjs.js +5 -0
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/sd-button_4.cjs.entry.js +2 -2
  5. package/dist/cjs/sd-ghost-button.cjs.entry.js +10 -5
  6. package/dist/cjs/sd-modal-container.cjs.entry.js +76 -68
  7. package/dist/cjs/sd-pagination_5.cjs.entry.js +889 -0
  8. package/dist/cjs/sd-radio-button.cjs.entry.js +6 -1
  9. package/dist/cjs/sd-select-v2-list-item_4.cjs.entry.js +65 -5
  10. package/dist/cjs/sd-switch.cjs.entry.js +1 -1
  11. package/dist/cjs/sd-table.cjs.entry.js +167 -20
  12. package/dist/cjs/sd-tabs.cjs.entry.js +1 -1
  13. package/dist/cjs/sd-tag.cjs.entry.js +2 -2
  14. package/dist/cjs/sd-td.cjs.entry.js +53 -1
  15. package/dist/cjs/sd-text-link.cjs.entry.js +3 -3
  16. package/dist/cjs/sd-textarea.cjs.entry.js +1 -1
  17. package/dist/cjs/sd-toast-container.cjs.entry.js +1 -1
  18. package/dist/cjs/sd-toast.cjs.entry.js +2 -2
  19. package/dist/cjs/sd-toggle.cjs.entry.js +1 -1
  20. package/dist/collection/components/sd-ghost-button/sd-ghost-button.js +10 -5
  21. package/dist/collection/components/sd-modal-container/sd-modal-container.js +77 -71
  22. package/dist/collection/components/sd-radio-button/sd-radio-button.js +6 -1
  23. package/dist/collection/components/sd-select-v2/sd-select-v2-listbox/sd-select-v2-listbox.js +103 -3
  24. package/dist/collection/components/sd-select-v2/sd-select-v2-trigger/sd-select-v2-trigger.js +2 -2
  25. package/dist/collection/components/sd-select-v2/sd-select-v2.js +82 -4
  26. package/dist/collection/components/sd-switch/sd-switch.js +1 -1
  27. package/dist/collection/components/sd-table/sd-table.css +1 -1
  28. package/dist/collection/components/sd-table/sd-table.js +170 -21
  29. package/dist/collection/components/sd-table/sd-tbody/sd-tbody.js +7 -2
  30. package/dist/collection/components/sd-table/sd-td/sd-td.js +91 -1
  31. package/dist/collection/components/sd-table/sd-thead/sd-thead.js +9 -4
  32. package/dist/collection/components/sd-table/sd-tr/sd-tr.css +8 -0
  33. package/dist/collection/components/sd-table/sd-tr/sd-tr.js +62 -12
  34. package/dist/collection/components/sd-tabs/sd-tabs.js +1 -1
  35. package/dist/collection/components/sd-tag/sd-tag.js +2 -2
  36. package/dist/collection/components/sd-text-link/sd-text-link.js +3 -3
  37. package/dist/collection/components/sd-textarea/sd-textarea.js +1 -1
  38. package/dist/collection/components/sd-toast/sd-toast.js +2 -2
  39. package/dist/collection/components/sd-toast-container/sd-toast-container.js +1 -1
  40. package/dist/collection/components/sd-toggle/sd-toggle.js +1 -1
  41. package/dist/collection/components/sd-tooltip/sd-tooltip.js +2 -2
  42. package/dist/collection/utils/modal.js +5 -0
  43. package/dist/components/index.js +1 -1
  44. package/dist/components/{p-BALOEavB.js → p-6AvsuYqF.js} +1 -1
  45. package/dist/components/{p-CTwEbxRN.js → p-6PsyRF61.js} +1 -1
  46. package/dist/components/{p-DEBakAhm.js → p-7DKZPPev.js} +1 -1
  47. package/dist/components/p-BBD_1E3n.js +1 -0
  48. package/dist/components/p-BQvugXhH.js +1 -0
  49. package/dist/components/p-BRfPoWUn.js +1 -0
  50. package/dist/components/{p-CHFGWh0m.js → p-C-BOe23n.js} +1 -1
  51. package/dist/components/p-C7h8lwnU.js +1 -0
  52. package/dist/components/{p-SDBnyM8D.js → p-CUg9NH6y.js} +1 -1
  53. package/dist/components/{p-C3dI7f7C.js → p-CgMyz4NQ.js} +1 -1
  54. package/dist/components/p-Csfj4h1A.js +1 -0
  55. package/dist/components/{p-Bp0B8tcl.js → p-DAC3TaZV.js} +1 -1
  56. package/dist/components/p-DfOYYI9m.js +1 -0
  57. package/dist/components/{p-H-9uoufd.js → p-d4UB2UF7.js} +1 -1
  58. package/dist/components/p-eEC3ITv0.js +1 -0
  59. package/dist/components/{p-CWEeXx2E.js → p-nVHDJc9g.js} +1 -1
  60. package/dist/components/{p-D8fG9Yt7.js → p-rnbt1m4L.js} +1 -1
  61. package/dist/components/sd-action-modal.js +1 -1
  62. package/dist/components/sd-barcode-input.js +1 -1
  63. package/dist/components/sd-chip.js +1 -1
  64. package/dist/components/sd-confirm-modal.js +1 -1
  65. package/dist/components/sd-date-picker-calendar.js +1 -1
  66. package/dist/components/sd-date-picker.js +1 -1
  67. package/dist/components/sd-date-range-picker-calendar.js +1 -1
  68. package/dist/components/sd-date-range-picker.js +1 -1
  69. package/dist/components/sd-field.js +1 -1
  70. package/dist/components/sd-file-picker.js +1 -1
  71. package/dist/components/sd-ghost-button.js +1 -1
  72. package/dist/components/sd-guide.js +1 -1
  73. package/dist/components/sd-input.js +1 -1
  74. package/dist/components/sd-modal-container.js +1 -1
  75. package/dist/components/sd-number-input.js +1 -1
  76. package/dist/components/sd-popover.js +1 -1
  77. package/dist/components/sd-radio-button.js +1 -1
  78. package/dist/components/sd-select-dropdown.js +1 -1
  79. package/dist/components/sd-select-group.js +1 -1
  80. package/dist/components/sd-select-multiple-group.js +1 -1
  81. package/dist/components/sd-select-multiple.js +1 -1
  82. package/dist/components/sd-select-search-input.js +1 -1
  83. package/dist/components/sd-select-v2-listbox.js +1 -1
  84. package/dist/components/sd-select-v2-trigger.js +1 -1
  85. package/dist/components/sd-select-v2.js +1 -1
  86. package/dist/components/sd-select.js +1 -1
  87. package/dist/components/sd-switch.js +1 -1
  88. package/dist/components/sd-table.js +1 -1
  89. package/dist/components/sd-tabs.js +1 -1
  90. package/dist/components/sd-tag.js +1 -1
  91. package/dist/components/sd-tbody.js +1 -1
  92. package/dist/components/sd-td.js +1 -1
  93. package/dist/components/sd-text-link.js +1 -1
  94. package/dist/components/sd-textarea.js +1 -1
  95. package/dist/components/sd-thead.js +1 -1
  96. package/dist/components/sd-toast-container.js +1 -1
  97. package/dist/components/sd-toast.js +1 -1
  98. package/dist/components/sd-toggle.js +1 -1
  99. package/dist/components/sd-tooltip.js +1 -1
  100. package/dist/components/sd-tr.js +1 -1
  101. package/dist/design-system/design-system.esm.js +1 -1
  102. package/dist/design-system/index.esm.js +1 -1
  103. package/dist/design-system/p-0e1b27cc.entry.js +1 -0
  104. package/dist/design-system/p-11029f6e.entry.js +1 -0
  105. package/dist/design-system/{p-cc62c180.entry.js → p-140b40ab.entry.js} +1 -1
  106. package/dist/design-system/p-34f7345b.entry.js +1 -0
  107. package/dist/design-system/p-363c9451.entry.js +1 -0
  108. package/dist/design-system/{p-fdcfaa7c.entry.js → p-506f2b68.entry.js} +1 -1
  109. package/dist/design-system/{p-8200b5f2.entry.js → p-531a6a82.entry.js} +1 -1
  110. package/dist/design-system/p-55b65a41.entry.js +1 -0
  111. package/dist/design-system/{p-d1dfa0e1.entry.js → p-68d0d67e.entry.js} +1 -1
  112. package/dist/design-system/p-7fe3a466.entry.js +1 -0
  113. package/dist/design-system/{p-05a1c092.entry.js → p-9466cd93.entry.js} +1 -1
  114. package/dist/design-system/{p-33bec0e3.entry.js → p-b683f2fe.entry.js} +1 -1
  115. package/dist/design-system/p-c521e731.entry.js +1 -0
  116. package/dist/design-system/{p-16a15368.entry.js → p-c9eb70f5.entry.js} +1 -1
  117. package/dist/design-system/p-d1846df9.entry.js +1 -0
  118. package/dist/design-system/{p-2d154fe0.entry.js → p-fdb52620.entry.js} +1 -1
  119. package/dist/esm/design-system.js +1 -1
  120. package/dist/esm/index.js +5 -0
  121. package/dist/esm/loader.js +1 -1
  122. package/dist/esm/sd-button_4.entry.js +2 -2
  123. package/dist/esm/sd-ghost-button.entry.js +10 -5
  124. package/dist/esm/sd-modal-container.entry.js +76 -68
  125. package/dist/esm/sd-pagination_5.entry.js +883 -0
  126. package/dist/esm/sd-radio-button.entry.js +6 -1
  127. package/dist/esm/sd-select-v2-list-item_4.entry.js +65 -5
  128. package/dist/esm/sd-switch.entry.js +1 -1
  129. package/dist/esm/sd-table.entry.js +168 -21
  130. package/dist/esm/sd-tabs.entry.js +1 -1
  131. package/dist/esm/sd-tag.entry.js +2 -2
  132. package/dist/esm/sd-td.entry.js +53 -1
  133. package/dist/esm/sd-text-link.entry.js +3 -3
  134. package/dist/esm/sd-textarea.entry.js +1 -1
  135. package/dist/esm/sd-toast-container.entry.js +1 -1
  136. package/dist/esm/sd-toast.entry.js +2 -2
  137. package/dist/esm/sd-toggle.entry.js +1 -1
  138. package/dist/types/components/sd-ghost-button/sd-ghost-button.d.ts +1 -0
  139. package/dist/types/components/sd-modal-container/sd-modal-container.config.d.ts +1 -1
  140. package/dist/types/components/sd-modal-container/sd-modal-container.d.ts +6 -4
  141. package/dist/types/components/sd-radio-button/sd-radio-button.d.ts +1 -0
  142. package/dist/types/components/sd-select-v2/sd-select-v2-listbox/sd-select-v2-listbox.d.ts +9 -0
  143. package/dist/types/components/sd-select-v2/sd-select-v2.d.ts +4 -0
  144. package/dist/types/components/sd-table/sd-table.d.ts +17 -0
  145. package/dist/types/components/sd-table/sd-td/sd-td.d.ts +8 -0
  146. package/dist/types/components/sd-table/sd-tr/sd-tr.d.ts +4 -0
  147. package/dist/types/components.d.ts +52 -0
  148. package/hydrate/index.js +481 -141
  149. package/hydrate/index.mjs +481 -141
  150. package/package.json +1 -1
  151. package/dist/cjs/sd-pagination_2.cjs.entry.js +0 -427
  152. package/dist/cjs/sd-tbody.cjs.entry.js +0 -66
  153. package/dist/cjs/sd-thead.cjs.entry.js +0 -179
  154. package/dist/cjs/sd-tr.cjs.entry.js +0 -171
  155. package/dist/components/p-Bbs5Ws0k.js +0 -1
  156. package/dist/components/p-CgL8_FSD.js +0 -1
  157. package/dist/components/p-DuMkBStM.js +0 -1
  158. package/dist/components/p-vQDL-PZ8.js +0 -1
  159. package/dist/design-system/p-380198bc.entry.js +0 -1
  160. package/dist/design-system/p-6b537e2f.entry.js +0 -1
  161. package/dist/design-system/p-6e90fb80.entry.js +0 -1
  162. package/dist/design-system/p-7b77c65c.entry.js +0 -1
  163. package/dist/design-system/p-8f88bd67.entry.js +0 -1
  164. package/dist/design-system/p-ba5fea6f.entry.js +0 -1
  165. package/dist/design-system/p-be54d6bd.entry.js +0 -1
  166. package/dist/design-system/p-c3379a6e.entry.js +0 -1
  167. package/dist/design-system/p-dc07d618.entry.js +0 -1
  168. package/dist/design-system/p-ef09409c.entry.js +0 -1
  169. package/dist/design-system/p-f8237991.entry.js +0 -1
  170. package/dist/esm/sd-pagination_2.entry.js +0 -424
  171. package/dist/esm/sd-tbody.entry.js +0 -64
  172. package/dist/esm/sd-thead.entry.js +0 -177
  173. package/dist/esm/sd-tr.entry.js +0 -169
@@ -108,6 +108,11 @@ const SdRadioButton = class {
108
108
  disabled = false;
109
109
  name;
110
110
  change;
111
+ componentWillLoad() {
112
+ this.size ??= 'sm';
113
+ this.options ??= [];
114
+ this.disabled ??= false;
115
+ }
111
116
  handleRadioChange = (optionValue, optionDisabled) => {
112
117
  if (this.disabled || optionDisabled)
113
118
  return;
@@ -168,7 +173,7 @@ const SdRadioButton = class {
168
173
  '--sd-radio-button-content-select': RADIO_BUTTON_COLORS.content.select,
169
174
  '--sd-radio-button-content-disabled': RADIO_BUTTON_COLORS.content.disabled,
170
175
  };
171
- return (h("div", { key: '67c8e7ad03fb6ee4cabd06591e3e11e5d38914f0', class: this.getGroupClasses(), style: cssVars, role: "radiogroup", "aria-disabled": this.disabled.toString() }, this.options.map(option => {
176
+ return (h("div", { key: 'fbc0246d9cf615956121295e29bf8c702ee73edc', class: this.getGroupClasses(), style: cssVars, role: "radiogroup", "aria-disabled": this.disabled.toString() }, this.options.map(option => {
172
177
  const isSelected = this.isOptionSelected(option);
173
178
  const isDisabled = this.isOptionDisabled(option);
174
179
  return (h("label", { key: `radio-${option.value}`, class: this.getButtonClasses(option), "aria-label": option.label || 'radio option', "data-label": option.label }, h("input", { type: "radio", name: this.groupName, value: option.value.toString(), checked: isSelected, disabled: isDisabled, onInput: () => this.handleRadioChange(option.value, option.disabled) }), option.label && h("span", { class: "sd-radio-button__label" }, option.label)));
@@ -323,6 +323,8 @@ const SdSelectV2Listbox = class {
323
323
  options = [];
324
324
  value = null;
325
325
  emitValue = false;
326
+ useSearch = false;
327
+ useSelectAll = false;
326
328
  triggerWidth = '200px';
327
329
  maxWidth = '640px';
328
330
  maxHeight = '260px';
@@ -340,7 +342,40 @@ const SdSelectV2Listbox = class {
340
342
  get isMulti() {
341
343
  return this.type === 'multi' || this.type === 'multi_depth';
342
344
  }
345
+ static SELECT_ALL_OPTION = {
346
+ value: '__select_all__',
347
+ label: '전체',
348
+ };
349
+ get showSelectAll() {
350
+ return this.useSelectAll && this.isMulti;
351
+ }
352
+ getAllNonDisabledLeaves() {
353
+ const collect = (opts) => opts.flatMap(o => {
354
+ if (o.disabled)
355
+ return [];
356
+ if (o.children)
357
+ return collect(o.children);
358
+ return [o];
359
+ });
360
+ return collect(this.options);
361
+ }
362
+ get selectAllState() {
363
+ if (!this.showSelectAll)
364
+ return false;
365
+ const allLeaves = this.getAllNonDisabledLeaves();
366
+ if (allLeaves.length === 0)
367
+ return false;
368
+ const selectedValues = this.getSelectedValues();
369
+ const selectedCount = allLeaves.filter(l => selectedValues.has(l.value)).length;
370
+ if (selectedCount === 0)
371
+ return false;
372
+ if (selectedCount === allLeaves.length)
373
+ return true;
374
+ return null;
375
+ }
343
376
  get showSearch() {
377
+ if (!this.useSearch)
378
+ return false;
344
379
  const count = this.isDepth ? countLeaves(this.options) : this.options.length;
345
380
  return count >= SEARCH_THRESHOLD;
346
381
  }
@@ -442,6 +477,9 @@ const SdSelectV2Listbox = class {
442
477
  }
443
478
  get navigableOptions() {
444
479
  const items = [];
480
+ if (this.showSelectAll) {
481
+ items.push(SdSelectV2Listbox.SELECT_ALL_OPTION);
482
+ }
445
483
  const walk = (opts) => {
446
484
  for (const opt of opts) {
447
485
  const isGroup = !!opt.children;
@@ -455,6 +493,22 @@ const SdSelectV2Listbox = class {
455
493
  walk(this.filteredOptions);
456
494
  return items;
457
495
  }
496
+ isSelectAllOption(option) {
497
+ return this.showSelectAll && option.value === SdSelectV2Listbox.SELECT_ALL_OPTION.value;
498
+ }
499
+ emitSelectAll() {
500
+ if (!this.showSelectAll)
501
+ return;
502
+ const allLeaves = this.getAllNonDisabledLeaves();
503
+ this.optionSelect.emit({
504
+ option: { ...SdSelectV2Listbox.SELECT_ALL_OPTION, children: allLeaves },
505
+ leaves: allLeaves,
506
+ });
507
+ }
508
+ handleSelectAllClick = (e) => {
509
+ e.stopPropagation();
510
+ this.emitSelectAll();
511
+ };
458
512
  isOptionFocused(option) {
459
513
  if (this.focusedIndex < 0)
460
514
  return false;
@@ -527,7 +581,13 @@ const SdSelectV2Listbox = class {
527
581
  return;
528
582
  e.preventDefault();
529
583
  e.stopPropagation();
530
- this.emitOptionSelect(items[this.focusedIndex]);
584
+ const focused = items[this.focusedIndex];
585
+ if (this.isSelectAllOption(focused)) {
586
+ this.emitSelectAll();
587
+ }
588
+ else {
589
+ this.emitOptionSelect(focused);
590
+ }
531
591
  }
532
592
  };
533
593
  /**
@@ -606,9 +666,9 @@ const SdSelectV2Listbox = class {
606
666
  '--listbox-max-height': this.maxHeight,
607
667
  '--listbox-radius': `${LIST_BOX_LAYOUT.radius}px`,
608
668
  };
609
- return (h("div", { key: 'd4d80ebd565436cd929961a2f9ce50adf92c124b', class: "sd-select-v2-listbox", style: cssVars }, this.showSearch && (h("sd-select-v2-list-item-search", { key: 'bd549975fe6187aa7e77e718c8d2ba4a6d6e33de', isScrolled: this.isScrolled, onSdSearchFilter: this.handleSearchFilter })), h("div", { key: '4ac6a1512781942fef3e42d6ca32762962df1836', class: "sd-select-v2-listbox__list", onScroll: this.handleScroll, ref: el => {
669
+ return (h("div", { key: '34efe12dfb3829dd7024eb473d0bb6460ad07e61', class: "sd-select-v2-listbox", style: cssVars }, this.showSearch && (h("sd-select-v2-list-item-search", { key: 'd59a97386213e93f905a817b7c3242d1fb5d5035', isScrolled: this.isScrolled, onSdSearchFilter: this.handleSearchFilter })), h("div", { key: '0feb6763afe5ac661de85df2c1a3683e56b17035', class: "sd-select-v2-listbox__list", onScroll: this.handleScroll, ref: el => {
610
670
  this.listEl = el;
611
- } }, this.isEmpty ? (h("div", { class: "sd-select-v2-listbox__empty" }, EMPTY_MESSAGE)) : this.isDepth ? (this.renderOptions(this.filteredOptions)) : (this.filteredOptions.map(option => (h("sd-select-v2-list-item", { option: option, depth: 1, isSelected: this.isOptionSelected(option), isFocused: this.isOptionFocused(option), useCheckbox: this.isMulti, onSdListItemClick: this.handleOptionClick, onMouseEnter: () => this.handleOptionHover(option) })))))));
671
+ } }, this.showSelectAll && (h("sd-select-v2-list-item", { key: 'b4a765ddfadd39808baafd925d0cd2fcdab78800', option: SdSelectV2Listbox.SELECT_ALL_OPTION, depth: 1, isSelected: this.selectAllState, isFocused: this.isOptionFocused(SdSelectV2Listbox.SELECT_ALL_OPTION), useCheckbox: true, onSdListItemClick: this.handleSelectAllClick, onMouseEnter: () => this.handleOptionHover(SdSelectV2Listbox.SELECT_ALL_OPTION) })), this.isEmpty ? (h("div", { class: "sd-select-v2-listbox__empty" }, EMPTY_MESSAGE)) : this.isDepth ? (this.renderOptions(this.filteredOptions)) : (this.filteredOptions.map(option => (h("sd-select-v2-list-item", { option: option, depth: 1, isSelected: this.isOptionSelected(option), isFocused: this.isOptionFocused(option), useCheckbox: this.isMulti, onSdListItemClick: this.handleOptionClick, onMouseEnter: () => this.handleOptionHover(option) })))))));
612
672
  }
613
673
  static get watchers() { return {
614
674
  "searchKeyword": [{
@@ -668,13 +728,13 @@ const SdSelectV2Trigger = class {
668
728
  ? SELECT_COLORS.icon.disabled
669
729
  : SELECT_COLORS.icon.default,
670
730
  };
671
- return (h("div", { key: '7c4f60c972c17b5954cbf0d0cc7ee38c8e6c16a3', ref: el => {
731
+ return (h("div", { key: 'ec8bf544b2878082a046fbe881afa2369709033f', ref: el => {
672
732
  this.triggerEl = el;
673
733
  }, tabindex: this.disabled ? -1 : 0, class: {
674
734
  'sd-select-v2-trigger': true,
675
735
  'sd-select-v2-trigger--open': this.isOpen,
676
736
  'sd-select-v2-trigger--disabled': this.disabled,
677
- }, style: cssVars, onClick: this.handleClick, onFocus: this.handleFocus, onBlur: this.handleBlur }, h("div", { key: 'de5f5a44626fce29c5a83cf0a14dd03352d40b57', class: "sd-select-v2-trigger__content" }, h("span", { key: 'a36a013e9ef359160c2b9d24b42ee6f228aca302', class: "sd-select-v2-trigger__text" }, hasValue ? this.displayText : this.placeholder), h("sd-icon", { key: '4bfcfce96fbe2008517ee26d7802d4492292faa5', name: "chevronDown", size: 12, color: "var(--trigger-icon-color)", class: {
737
+ }, style: cssVars, onClick: this.handleClick, onFocus: this.handleFocus, onBlur: this.handleBlur }, h("div", { key: '1a6a5cf66208aa5a996e788886ff593ec0830d51', class: "sd-select-v2-trigger__content" }, h("span", { key: 'bd905f9149f3842e5e169e1a6086b33164b0ab66', class: "sd-select-v2-trigger__text" }, hasValue ? this.displayText : this.placeholder), h("sd-icon", { key: 'cc487e430f42fdd61540e265a9e5bb01e9045a58', name: "chevronDown", size: 12, color: "var(--trigger-icon-color)", class: {
678
738
  'sd-select-v2-trigger__icon': true,
679
739
  'sd-select-v2-trigger__icon--open': this.isOpen,
680
740
  } }))));
@@ -100,7 +100,7 @@ const SdSwitch = class {
100
100
  '--sd-switch-line-height': `${SWITCH_TYPOGRAPHY.lineHeight}px`,
101
101
  '--sd-switch-text-decoration': SWITCH_TYPOGRAPHY.textDecoration,
102
102
  };
103
- return (h("label", { key: 'ac6a35d06ddd04bc94369014ff586766dd745bbb', "aria-label": this.label || 'switch', class: this.switchClasses, style: cssVars }, h("input", { key: '9ebc810e93c9dfa3bf7407f279dadbada579196e', type: "checkbox", checked: this.value, disabled: this.disabled, onInput: this.handleChange }), h("div", { key: '7add76be99645d6434e95305f6318fac7da0de57', class: "sd-switch__track" }, h("div", { key: 'ed90778aa4dcd6f0853029579c36cfdb8640afcf', class: "sd-switch__knob" })), this.label && h("span", { key: '70e3ddf819e77da4c693a4853ddb7f392381964e', class: "sd-switch__label" }, this.label)));
103
+ 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)));
104
104
  }
105
105
  };
106
106
  SdSwitch.style = sdSwitchCss();
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, c as createEvent, a as getElement, d as readTask, h, H as Host } from './index-Bp7ytJz5.js';
1
+ import { r as registerInstance, c as createEvent, a as getElement, d as readTask, f as forceUpdate, h, H as Host } from './index-Bp7ytJz5.js';
2
2
  import { T as TABLE_ID_ATTR } from './constants-sZMi_32I.js';
3
3
 
4
4
  const urlAlphabet =
@@ -14,7 +14,7 @@ let nanoid = (size = 21) => {
14
14
  return id
15
15
  };
16
16
 
17
- const sdTableCss = () => `sd-table,:host{display:block;width:100%;max-width:100%;min-width:0}sd-table *,:host *{box-sizing:border-box}.sd-table__container{height:var(--table-height, auto);width:var(--table-width, 100%);max-width:100%;min-width:0;color:#222222;display:flex;flex-direction:column}.sd-table__clip{width:100%;min-width:0;height:var(--table-container-height, 400px);border:1px solid #E1E1E1;border-radius:8px;overflow:hidden}.sd-table__clip--has-pagination{border-radius:8px 8px 0 0}.sd-table__wrapper{width:100%;height:100%;display:flex;flex-direction:column;position:relative;font-size:12px;overflow:auto;background:#FFFFFF}.sd-table__wrapper--loading{overflow:hidden !important;pointer-events:none}.sd-table__wrapper--no-data{overflow:hidden;pointer-events:none}.sd-table__no-data{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:12px;color:#888888;pointer-events:none;z-index:200;background:rgba(255, 255, 255, 0.6)}.sd-table__loading{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(255, 255, 255, 0.6);z-index:200;display:flex;align-items:center;justify-content:center;pointer-events:none}.sd-table{background-color:white;display:table;width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.sd-table--selectable sd-thead,.sd-table--selectable sd-tbody{--selectable:true}.sd-table--sticky-header sd-thead thead{position:sticky;top:0;z-index:120}.sd-table--sticky-column sd-thead,.sd-table--sticky-column sd-tbody{--sticky-column:true}.sd-table--scrolled-left sd-thead,.sd-table--scrolled-left sd-tbody{--scrolled-left:true}.sd-table--scrolled-right sd-thead,.sd-table--scrolled-right sd-tbody{--scrolled-right:true}.sd-table--resizable sd-thead{--resizable:true}.sd-table--no-data sd-thead{opacity:0.4}.sd-table__pagination{position:relative;background:#F9F9F9;height:48px;display:flex;align-items:center;justify-content:center;border:1px solid #E1E1E1;border-top:none;border-radius:0 0 8px 8px}.sd-table__pagination sd-select-v2{position:absolute;right:10px;top:50%;transform:translateY(-50%)}`;
17
+ const sdTableCss = () => `sd-table,:host{display:block;width:100%;max-width:100%;min-width:0}sd-table *,:host *{box-sizing:border-box}.sd-table__container{height:var(--table-height, 100%);width:var(--table-width, 100%);max-width:100%;min-width:0;color:#222222;display:flex;flex-direction:column}.sd-table__clip{width:100%;min-width:0;height:var(--table-container-height, 400px);border:1px solid #E1E1E1;border-radius:8px;overflow:hidden}.sd-table__clip--has-pagination{border-radius:8px 8px 0 0}.sd-table__wrapper{width:100%;height:100%;display:flex;flex-direction:column;position:relative;font-size:12px;overflow:auto;background:#FFFFFF}.sd-table__wrapper--loading{overflow:hidden !important;pointer-events:none}.sd-table__wrapper--no-data{overflow:hidden;pointer-events:none}.sd-table__no-data{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:12px;color:#888888;pointer-events:none;z-index:200;background:rgba(255, 255, 255, 0.6)}.sd-table__loading{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(255, 255, 255, 0.6);z-index:200;display:flex;align-items:center;justify-content:center;pointer-events:none}.sd-table{background-color:white;display:table;width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.sd-table--selectable sd-thead,.sd-table--selectable sd-tbody{--selectable:true}.sd-table--sticky-header sd-thead thead{position:sticky;top:0;z-index:120}.sd-table--sticky-column sd-thead,.sd-table--sticky-column sd-tbody{--sticky-column:true}.sd-table--scrolled-left sd-thead,.sd-table--scrolled-left sd-tbody{--scrolled-left:true}.sd-table--scrolled-right sd-thead,.sd-table--scrolled-right sd-tbody{--scrolled-right:true}.sd-table--resizable sd-thead{--resizable:true}.sd-table--no-data sd-thead{opacity:0.4}.sd-table__pagination{position:relative;background:#F9F9F9;height:48px;display:flex;align-items:center;justify-content:center;border:1px solid #E1E1E1;border-top:none;border-radius:0 0 8px 8px}.sd-table__pagination sd-select-v2{position:absolute;right:10px;top:50%;transform:translateY(-50%)}`;
18
18
 
19
19
  const SdTable = class {
20
20
  constructor(hostRef) {
@@ -70,11 +70,17 @@ const SdTable = class {
70
70
  scrolledRight = false;
71
71
  rowCount = 0;
72
72
  loadingScrollTop = 0;
73
+ // light DOM에 sd-thead / sd-tbody 자식이 없으면 sd-table이 직접 렌더해야 함을 알리는 플래그.
74
+ // componentWillLoad에서 한 번 결정되며, 이후 동적 토글은 지원하지 않는다.
75
+ autoThead = false;
76
+ autoTbody = false;
73
77
  vsStart = 0;
74
78
  vsEnd = 0;
75
79
  lastReachEndNotifiedRowCount = -1;
76
80
  scrollContainer = null;
77
81
  onScroll;
82
+ // 키: `${rowKey}::${field}` → { rowspan, colspan }
83
+ spanRegistry = new Map();
78
84
  toFiniteNumber(value, fallback) {
79
85
  const n = typeof value === 'number' ? value : Number(value);
80
86
  return Number.isFinite(n) ? n : fallback;
@@ -153,9 +159,16 @@ const SdTable = class {
153
159
  this.innerRowsPerPage = newVal.rowsPerPage;
154
160
  }
155
161
  }
162
+ detectChildren() {
163
+ const hasThead = !!this.el.querySelector(':scope > sd-thead');
164
+ const hasTbody = !!this.el.querySelector(':scope > sd-tbody');
165
+ this.autoThead = !hasThead;
166
+ this.autoTbody = !hasTbody;
167
+ }
156
168
  componentWillLoad() {
157
169
  this.syncTableIdAttribute();
158
170
  this.handleNoDataLabelChange(this.noDataLabel);
171
+ this.detectChildren();
159
172
  this.innerSelected = new Set(this.selected || []);
160
173
  this.columnWidths = (this.columns || []).map(c => parseInt(c.width || '120', 10));
161
174
  if (this.pagination?.page) {
@@ -178,6 +191,11 @@ const SdTable = class {
178
191
  el.getTableIdSync = () => this.getResolvedTableId();
179
192
  el.getVirtualScrollConfigSync = this.getVirtualScrollConfigSync.bind(this);
180
193
  el.calculateVisibleRange = this.calculateVisibleRange.bind(this);
194
+ el.registerSpanSync = this.registerSpanSync.bind(this);
195
+ el.unregisterSpanSync = this.unregisterSpanSync.bind(this);
196
+ el.getSpanSync = this.getSpanSync.bind(this);
197
+ el.isCoveredSync = this.isCoveredSync.bind(this);
198
+ el.hasRowspanSync = this.hasRowspanSync.bind(this);
181
199
  if (Array.isArray(this.rows)) {
182
200
  this.rowCount = this.rows.length;
183
201
  this.pushRowsToChildren(this.rows);
@@ -226,11 +244,22 @@ const SdTable = class {
226
244
  this.scrollContainer.removeEventListener('scroll', this.onScroll);
227
245
  }
228
246
  }
247
+ // light DOM(manual mode 자식)과 shadow DOM(autoThead/autoTbody fallback) 양쪽 모두에서 자식을 찾는다.
248
+ queryChildEl(selector) {
249
+ return (this.el.querySelector(selector) ??
250
+ this.el.shadowRoot?.querySelector(selector) ??
251
+ null);
252
+ }
253
+ queryAllTr() {
254
+ const light = Array.from(this.el.querySelectorAll('sd-tr'));
255
+ const shadow = Array.from(this.el.shadowRoot?.querySelectorAll('sd-tr') ?? []);
256
+ return [...light, ...shadow];
257
+ }
229
258
  pushRowsToChildren(rows) {
230
- const tbody = this.el.querySelector('sd-tbody');
259
+ const tbody = this.queryChildEl('sd-tbody');
231
260
  if (tbody)
232
261
  tbody.rows = rows;
233
- const thead = this.el.querySelector('sd-thead');
262
+ const thead = this.queryChildEl('sd-thead');
234
263
  if (thead)
235
264
  thead.rows = rows;
236
265
  }
@@ -241,16 +270,14 @@ const SdTable = class {
241
270
  this.refreshChildrenConfig();
242
271
  };
243
272
  refreshChildrenSelection() {
244
- const thead = this.el.querySelector('sd-thead');
245
- const rows = this.el.querySelectorAll('sd-tr');
273
+ const thead = this.queryChildEl('sd-thead');
246
274
  thead?.refreshSelection?.();
247
- rows.forEach(tr => tr?.refreshSelection?.());
275
+ this.queryAllTr().forEach(tr => tr?.refreshSelection?.());
248
276
  }
249
277
  refreshChildrenConfig() {
250
- const thead = this.el.querySelector('sd-thead');
251
- const rows = this.el.querySelectorAll('sd-tr');
278
+ const thead = this.queryChildEl('sd-thead');
252
279
  thead?.refreshConfig?.();
253
- rows.forEach(tr => tr?.refreshConfig?.());
280
+ this.queryAllTr().forEach(tr => tr?.refreshConfig?.());
254
281
  }
255
282
  maybeEmitVirtualReachEnd(start, end) {
256
283
  const threshold = Math.max(1, this.virtualEndThreshold);
@@ -282,7 +309,7 @@ const SdTable = class {
282
309
  this.vsEnd = end;
283
310
  const topHeight = start * this.rowHeight;
284
311
  const bottomHeight = Math.max(0, (this.rowCount - end) * this.rowHeight);
285
- const tbody = this.el.querySelector('sd-tbody');
312
+ const tbody = this.queryChildEl('sd-tbody');
286
313
  tbody?.setSpacersSync?.(topHeight, bottomHeight);
287
314
  if (rangeChanged) {
288
315
  this.sdVirtualUpdate.emit({
@@ -374,8 +401,7 @@ const SdTable = class {
374
401
  this.updateRowsVisibility();
375
402
  }
376
403
  updateRowsVisibility() {
377
- const rows = this.el.querySelectorAll('sd-tr');
378
- rows.forEach(tr => tr?.updateVisibility?.());
404
+ this.queryAllTr().forEach(tr => tr?.updateVisibility?.());
379
405
  }
380
406
  changeRowsPerPage(perPage) {
381
407
  const changedRowsPerPage = perPage ? Number(perPage) : 0;
@@ -412,10 +438,9 @@ const SdTable = class {
412
438
  const delta = moveEvent.clientX - startX;
413
439
  const newWidth = Math.min(Math.max(startWidth + (reversed ? -delta : delta), minWidth), maxWidth);
414
440
  this.columnWidths = this.columnWidths.map((width, idx) => (idx === index ? newWidth : width));
415
- const thead = this.el.querySelector('sd-thead');
416
- const rows = this.el.querySelectorAll('sd-tr');
441
+ const thead = this.queryChildEl('sd-thead');
417
442
  thead?.setColumnWidths?.(this.columnWidths);
418
- rows.forEach(tr => tr?.setColumnWidths?.(this.columnWidths));
443
+ this.queryAllTr().forEach(tr => tr?.setColumnWidths?.(this.columnWidths));
419
444
  const stickyRightCount = this.stickyColumn?.right || 0;
420
445
  const visibleColCount = this.columns.filter(c => c.visible !== false).length;
421
446
  const isRightStickyEdgeResizer = stickyRightCount > 0 && index === visibleColCount - stickyRightCount;
@@ -452,6 +477,112 @@ const SdTable = class {
452
477
  async getStickyStyle(colIdx) {
453
478
  return this.getStickyStyleSync(colIdx);
454
479
  }
480
+ // ─── rowspan / colspan registry ─────────────────────────────────
481
+ // sd-td가 mount/unmount 시 자기 (rowKey, field)와 span을 등록한다.
482
+ // sd-tr는 render마다 isCoveredSync로 자신의 셀 위치가 다른 셀의 span에
483
+ // 덮였는지 판정해 <td>를 그릴지 결정한다.
484
+ spanKey(rowKey, field) {
485
+ return `${rowKey}::${field}`;
486
+ }
487
+ // span 등록은 sd-td의 lifecycle에서 비동기적으로 일어나므로,
488
+ // 등록/해제 직후 형제 sd-tr들이 새 레지스트리 상태로 다시 그려져야
489
+ // 덮인 셀이 사라지거나 다시 나타난다.
490
+ // forceUpdate는 React 래퍼 환경에서 prop 동기화 사이클과 부딪혀 누락되는
491
+ // 경우가 있어, sd-tr의 @State (spansVersion)을 통해 재렌더를 강제한다.
492
+ requestAllTrUpdate() {
493
+ this.queryAllTr().forEach(tr => {
494
+ const trAny = tr;
495
+ if (typeof trAny.bumpSpansVersion === 'function') {
496
+ trAny.bumpSpansVersion();
497
+ }
498
+ else {
499
+ forceUpdate(tr);
500
+ }
501
+ });
502
+ }
503
+ registerSpanSync(rowKey, field, rowspan, colspan) {
504
+ if (rowKey == null || !field)
505
+ return;
506
+ const safeRowspan = Math.max(1, Math.floor(rowspan || 1));
507
+ const safeColspan = Math.max(1, Math.floor(colspan || 1));
508
+ const key = this.spanKey(rowKey, field);
509
+ const prev = this.spanRegistry.get(key);
510
+ if (safeRowspan === 1 && safeColspan === 1) {
511
+ if (!prev)
512
+ return;
513
+ this.spanRegistry.delete(key);
514
+ this.requestAllTrUpdate();
515
+ return;
516
+ }
517
+ if (prev && prev.rowspan === safeRowspan && prev.colspan === safeColspan)
518
+ return;
519
+ this.spanRegistry.set(key, { rowspan: safeRowspan, colspan: safeColspan });
520
+ this.requestAllTrUpdate();
521
+ }
522
+ unregisterSpanSync(rowKey, field) {
523
+ if (rowKey == null || !field)
524
+ return;
525
+ const key = this.spanKey(rowKey, field);
526
+ if (!this.spanRegistry.has(key))
527
+ return;
528
+ this.spanRegistry.delete(key);
529
+ this.requestAllTrUpdate();
530
+ }
531
+ getSpanSync(rowKey, field) {
532
+ return this.spanRegistry.get(this.spanKey(rowKey, field));
533
+ }
534
+ // 레지스트리에 rowspan>1 항목이 하나라도 있으면 true.
535
+ // hover 동작을 끌지 결정하는 데 사용 — colspan만 있는 경우는 그대로 hover 유지.
536
+ hasRowspanSync() {
537
+ for (const span of this.spanRegistry.values()) {
538
+ if (span.rowspan > 1)
539
+ return true;
540
+ }
541
+ return false;
542
+ }
543
+ isCoveredSync(rowKey, colIdx, columns) {
544
+ if (this.spanRegistry.size === 0)
545
+ return false;
546
+ const visibleCols = columns.filter(c => c.visible !== false);
547
+ // 1. 같은 행 왼쪽 스캔 — colspan으로 이 위치를 덮는 셀이 있는가
548
+ for (let i = 0; i < colIdx; i++) {
549
+ const c = visibleCols[i];
550
+ if (!c)
551
+ continue;
552
+ const field = typeof c.field === 'string' ? c.field : c.name;
553
+ const span = this.spanRegistry.get(this.spanKey(rowKey, field));
554
+ if (!span)
555
+ continue;
556
+ if (i + span.colspan > colIdx)
557
+ return true;
558
+ }
559
+ // 2. 위쪽 행 스캔 — 숫자 변환 가능한 rowKey만 rowspan 평가
560
+ const myRowIdx = Number(rowKey);
561
+ if (!Number.isFinite(myRowIdx))
562
+ return false;
563
+ for (const [key, span] of this.spanRegistry) {
564
+ if (span.rowspan <= 1)
565
+ continue;
566
+ const sepIdx = key.indexOf('::');
567
+ if (sepIdx < 0)
568
+ continue;
569
+ const otherRowKey = key.slice(0, sepIdx);
570
+ const otherField = key.slice(sepIdx + 2);
571
+ const otherRowIdx = Number(otherRowKey);
572
+ if (!Number.isFinite(otherRowIdx))
573
+ continue;
574
+ if (otherRowIdx >= myRowIdx)
575
+ continue;
576
+ if (otherRowIdx + span.rowspan <= myRowIdx)
577
+ continue;
578
+ const otherColIdx = visibleCols.findIndex(c => (typeof c.field === 'string' ? c.field : c.name) === otherField);
579
+ if (otherColIdx < 0)
580
+ continue;
581
+ if (otherColIdx <= colIdx && otherColIdx + span.colspan > colIdx)
582
+ return true;
583
+ }
584
+ return false;
585
+ }
455
586
  setRowCountSync(count) {
456
587
  const safeCount = Math.max(0, Math.floor(this.toFiniteNumber(count, 0)));
457
588
  if (safeCount !== this.rowCount) {
@@ -499,6 +630,22 @@ const SdTable = class {
499
630
  return null;
500
631
  return { from: this.vsStart, to: this.vsEnd };
501
632
  }
633
+ // autoTbody fallback에서 sd-table이 직접 sd-tr을 만들어내는 경로.
634
+ // 가상 스크롤은 사용자가 직접 SdTbody+SdTr을 작성해야 하므로 빈 배열을 반환한다.
635
+ renderAutoRows() {
636
+ if (this.useVirtualScroll)
637
+ return null;
638
+ const allRows = this.rows ?? [];
639
+ const pageInfo = this.getPaginationInfoSync();
640
+ const startIdx = pageInfo?.startIndex ?? 0;
641
+ const displayed = pageInfo
642
+ ? allRows.slice(pageInfo.startIndex, pageInfo.endIndex)
643
+ : allRows;
644
+ return displayed.map((row, i) => {
645
+ const absoluteIdx = startIdx + i;
646
+ return (h("sd-tr", { key: absoluteIdx, "row-key": String(absoluteIdx), row: row }));
647
+ });
648
+ }
502
649
  get tableClasses() {
503
650
  return [
504
651
  'sd-table',
@@ -518,24 +665,24 @@ const SdTable = class {
518
665
  }
519
666
  render() {
520
667
  const resolvedTableId = this.getResolvedTableId();
521
- return (h(Host, { key: '0b90643721a90b7bb59a6c31f6edeb313849b973' }, h("div", { key: 'e55fe4f476dbea4888a168861e7e6d6951d7d489', class: "sd-table__container", style: {
668
+ return (h(Host, { key: 'd73cd690ad11ce92af37b6f32374f6f891c5b677' }, h("div", { key: 'f51d23212885ad8121b9a4e895fb854f1e142bc4', class: "sd-table__container", style: {
522
669
  '--table-width': this.width,
523
670
  '--table-height': this.height,
524
671
  '--table-container-height': `calc(${this.height || '100%'} - ${this.pagination && this.rowCount > 0 && !this.useVirtualScroll ? 48 : 0}px)`,
525
- } }, h("div", { key: 'de18a900037a7b2f619dd22981c30ed76f5a8111', class: {
672
+ } }, h("div", { key: '84b1ba7b2220ff55304b9c19e59304ca2257cff0', class: {
526
673
  'sd-table__clip': true,
527
674
  'sd-table__clip--has-pagination': !!(this.pagination &&
528
675
  this.pagination.rowsPerPage > 0 &&
529
676
  this.rowCount > 0 &&
530
677
  !this.useVirtualScroll),
531
- } }, h("div", { key: '028e0982d415033adaf420ee6b953241c8f3dbec', class: {
678
+ } }, h("div", { key: 'c901eba67eae29515bf0b3edcc6632b2aacf0f80', class: {
532
679
  'sd-table__wrapper': true,
533
680
  'sd-table__wrapper--loading': this.isLoading,
534
681
  'sd-table__wrapper--no-data': this.rowCount === 0 && !this.isLoading,
535
- } }, this.isLoading && (h("div", { key: '8c9110c9c2c26cddbbed8e1f2782ecfaafd3679c', class: "sd-table__loading", style: { top: `${this.loadingScrollTop}px` } }, h("sd-circle-progress", { key: '51b61f91b0ecebf63fe3e65b94012963f0375e5c', indeterminate: true }))), this.rowCount === 0 && !this.isLoading && (h("div", { key: '0a7a45049014869b8164b081a251218d3c814e87', class: "sd-table__no-data" }, h("slot", { key: 'd4b6219e5dcaaa22be3360f7f0f05a8b32533890', name: "no-data" }, h("span", { key: 'c76848aad8a1d3967f3cd239090e97266e46ab3e' }, this.resolvedNoDataLabel)))), h("table", { key: '2b560d112402549c7043b337d944b0de88c3ba0e', class: this.tableClasses }, h("slot", { key: '1c4583148df6a585f389c1bed0426fa4a3cb4899', name: `${resolvedTableId}-head`, onSlotchange: this.handleStructureSlotChange }), h("slot", { key: 'a5d983106de61c829f9cbeb541d1908fee48468c', name: `${resolvedTableId}-body`, onSlotchange: this.handleStructureSlotChange })))), this.pagination &&
682
+ } }, 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 &&
536
683
  this.pagination.rowsPerPage > 0 &&
537
684
  this.rowCount > 0 &&
538
- !this.useVirtualScroll && (h("div", { key: '004355d84e2cfc2fd38a9d4811f14fd66dc5c21b', class: "sd-table__pagination" }, h("sd-pagination", { key: '463586c7e57782a7989962f73cb3d4e8c04f5bce', 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: '1f26de447da63ef0c4a24ffb49666a0687db9991', value: this.useInternalPagination
685
+ !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
539
686
  ? this.innerRowsPerPage
540
687
  : this.pagination.rowsPerPage, options: this.rowsPerPageOption, width: "128px", emitValue: true, onSdUpdate: e => {
541
688
  if (!this.isRowsPerPageValue(e.detail))
@@ -186,7 +186,7 @@ const SdTabs = class {
186
186
  };
187
187
  }
188
188
  render() {
189
- return (h("div", { key: '390edfad274caa06df38af9d04580015a1744a44', class: this.getContainerClasses(), style: this.buildCssVars() }, this.tabs.map((tab, index) => {
189
+ return (h("div", { key: '3698b7b43e74ff053d61d5ce696b987373fd27d6', class: this.getContainerClasses(), style: this.buildCssVars() }, this.tabs.map((tab, index) => {
190
190
  const badgeName = this.getBadgeName(tab);
191
191
  return (h("div", { key: `tab-${index}`, class: this.getTabClasses(tab), "aria-label": tab.label || 'tab', onClick: () => this.handleTabClick(tab) }, h("span", { "data-label": tab.label, class: "sd-tabs__label" }, tab.label), tab.badge !== undefined && tab.badge !== null && tab.badge !== '' && (h("sd-tag", { name: badgeName, label: tab.badge.toString() }))));
192
192
  })));
@@ -170,7 +170,7 @@ const SdTag = class {
170
170
  render() {
171
171
  const config = this.resolvedConfig;
172
172
  const iconNode = this.renderIcon(config.icon, config.iconSize);
173
- return (h("span", { key: 'da19900d267d2b2f000e1790133966a7976bcded', class: "sd-tag", style: {
173
+ return (h("span", { key: 'def10730670f37a62fa76b507f7f15a1b1f956fc', class: "sd-tag", style: {
174
174
  '--sd-tag-background': config.background,
175
175
  '--sd-tag-content': config.content,
176
176
  '--sd-tag-height': config.height,
@@ -180,7 +180,7 @@ const SdTag = class {
180
180
  '--sd-tag-font-weight': config.fontWeight,
181
181
  '--sd-tag-line-height': config.lineHeight,
182
182
  '--sd-tag-radius': config.radius,
183
- }, "aria-label": this.label || 'tag' }, this.icon && this.isLeft && iconNode, h("span", { key: 'e426021988395058367872ac23658586b2895764', class: "sd-tag__label" }, this.label), this.icon && !this.isLeft && iconNode));
183
+ }, "aria-label": this.label || 'tag' }, this.icon && this.isLeft && iconNode, h("span", { key: '32082536736e20074263632aa29f36bc7709db39', class: "sd-tag__label" }, this.label), this.icon && !this.isLeft && iconNode));
184
184
  }
185
185
  };
186
186
  SdTag.style = sdTagCss();
@@ -11,14 +11,22 @@ const SdTd = class {
11
11
  field;
12
12
  rowKey;
13
13
  align;
14
+ rowspan;
15
+ colspan;
14
16
  handleFieldChange() {
15
17
  this.syncSlotName();
18
+ this.syncSpanRegistration();
16
19
  }
17
20
  handleRowKeyChange() {
18
21
  this.syncSlotName();
22
+ this.syncSpanRegistration();
23
+ }
24
+ handleSpanChange() {
25
+ this.syncSpanRegistration();
19
26
  }
20
27
  componentWillLoad() {
21
28
  this.syncSlotName();
29
+ this.syncSpanRegistration();
22
30
  // slot 타이밍 엇갈림 대응: 부모 sd-tr forceUpdate로 슬롯 재매칭
23
31
  const parentTr = this.el.parentElement;
24
32
  if (parentTr?.tagName?.toLowerCase() === 'sd-tr') {
@@ -27,6 +35,44 @@ const SdTd = class {
27
35
  }
28
36
  componentDidLoad() {
29
37
  this.syncSlotName();
38
+ this.syncSpanRegistration();
39
+ }
40
+ // React StrictMode에서는 disconnect/reconnect 사이클이 일어나면서
41
+ // 동일 인스턴스의 componentWillLoad는 더 이상 호출되지 않는다.
42
+ // 재연결 시점에도 등록 상태를 복구해야 rowspan/colspan이 유지된다.
43
+ connectedCallback() {
44
+ this.syncSpanRegistration();
45
+ }
46
+ disconnectedCallback() {
47
+ const table = this.findTable();
48
+ if (table?.unregisterSpanSync && this.field && this.rowKey != null) {
49
+ table.unregisterSpanSync(String(this.rowKey), this.field);
50
+ this.requestParentTrUpdate();
51
+ }
52
+ }
53
+ findTable() {
54
+ return this.el.closest('sd-table');
55
+ }
56
+ requestParentTrUpdate() {
57
+ const parentTr = this.el.parentElement;
58
+ if (parentTr?.tagName?.toLowerCase() !== 'sd-tr')
59
+ return;
60
+ const trAny = parentTr;
61
+ if (typeof trAny.bumpSpansVersion === 'function') {
62
+ trAny.bumpSpansVersion();
63
+ }
64
+ else {
65
+ forceUpdate(parentTr);
66
+ }
67
+ }
68
+ syncSpanRegistration() {
69
+ const table = this.findTable();
70
+ if (!table?.registerSpanSync || !this.field || this.rowKey == null)
71
+ return;
72
+ const rs = Math.max(1, Math.floor(Number(this.rowspan) || 1));
73
+ const cs = Math.max(1, Math.floor(Number(this.colspan) || 1));
74
+ table.registerSpanSync(String(this.rowKey), this.field, rs, cs);
75
+ this.requestParentTrUpdate();
30
76
  }
31
77
  syncSlotName() {
32
78
  const table = this.el.closest('sd-table');
@@ -40,7 +86,7 @@ const SdTd = class {
40
86
  }
41
87
  }
42
88
  render() {
43
- return (h(Host, { key: '672c967273dac405ed4a47fa5939463265075681', class: { [`align-${this.align}`]: Boolean(this.align) } }, h("slot", { key: 'c15e572fdf4a8c68fff8b69b586dfbf9f01dce1b' })));
89
+ return (h(Host, { key: 'da9ce2edb986d4b3cf1a6e5f59030009f1288250', class: { [`align-${this.align}`]: Boolean(this.align) } }, h("slot", { key: '8514071bd38c4f5b1997ae7239b8585a25f97ce0' })));
44
90
  }
45
91
  static get watchers() { return {
46
92
  "field": [{
@@ -48,6 +94,12 @@ const SdTd = class {
48
94
  }],
49
95
  "rowKey": [{
50
96
  "handleRowKeyChange": 0
97
+ }],
98
+ "rowspan": [{
99
+ "handleSpanChange": 0
100
+ }],
101
+ "colspan": [{
102
+ "handleSpanChange": 0
51
103
  }]
52
104
  }; }
53
105
  };
@@ -71,16 +71,16 @@ const SdTextLink = class {
71
71
  '--sd-text-link-text-decoration': typo.textDecoration,
72
72
  ...(this.disabled ? { '--sd-text-link-color': TEXT_LINK_COLORS.content.disabled } : {}),
73
73
  };
74
- return (h("span", { key: '1128254cddacf5869f320ce2b788b06646f27d7f', class: {
74
+ return (h("span", { key: '77c1aa4a4a6297af9431947b7146db2ddfad52b5', class: {
75
75
  'sd-text-link': true,
76
76
  'sd-text-link--disabled': this.disabled,
77
- }, style: cssVars, onClick: this.handleClick }, this.icon && (h("sd-icon", { key: '52c069d637a2ccf9cd4e7bd1ab3a62ea981d2e1e', name: this.icon, size: TEXT_LINK_LAYOUT.iconSize, color: iconColor, class: "sd-text-link__icon" })), h("span", { key: '99a09359c75c2eb6c2e2ef6b9e3b87d92c3f7810', class: labelClassName }, this.label), this.useArrow && (h("span", { key: 'c7e77454d9d002c0e043dc71a418c65ecd60cff5', class: "sd-text-link__arrow", style: {
77
+ }, style: cssVars, onClick: this.handleClick }, this.icon && (h("sd-icon", { key: '6f760b3c7e0adccd2aa08cb662cca90a3d3a227b', name: this.icon, size: TEXT_LINK_LAYOUT.iconSize, color: iconColor, class: "sd-text-link__icon" })), h("span", { key: '3ff017970956d8e5cb72b4d6e26d33aaf0551e76', class: labelClassName }, this.label), this.useArrow && (h("span", { key: '8332cbe3b2283ce866044e55804e35338569a38f', class: "sd-text-link__arrow", style: {
78
78
  width: `${TEXT_LINK_LAYOUT.arrowFrame}px`,
79
79
  height: `${TEXT_LINK_LAYOUT.arrowFrame}px`,
80
80
  display: 'inline-flex',
81
81
  alignItems: 'center',
82
82
  justifyContent: 'center',
83
- } }, h("sd-icon", { key: '677c88823b02084449cd2dec83cc6bd27dfb8006', name: "chevronRight", size: TEXT_LINK_LAYOUT.arrowIconSize, color: arrowColor })))));
83
+ } }, h("sd-icon", { key: '2fa166ef60f6d1ee933450146bc667ee89dad2ce', name: "chevronRight", size: TEXT_LINK_LAYOUT.arrowIconSize, color: arrowColor })))));
84
84
  }
85
85
  };
86
86
  SdTextLink.style = sdTextLinkCss();
@@ -128,7 +128,7 @@ const SdTextarea = class {
128
128
  '--sd-system-size-field-sm-height': 'auto',
129
129
  '--sd-system-radius-field-sm': `${TEXTAREA_TOKENS.radius}px`,
130
130
  };
131
- return (h("sd-field", { key: '345a70f335ee103a4e45c75e17559359beec01c9', name: this.name, label: this.label, labelWidth: this.labelWidth, addonLabel: this.addonLabel, addonAlign: this.addonAlign, hint: this.hint, errorMessage: this.errorMessage, width: this.width, rules: this.rules, error: this.error, disabled: this.disabled, focused: this.focused, hovered: this.hovered, status: this.status, icon: this.icon, labelTooltip: this.labelTooltip, labelTooltipProps: this.labelTooltipProps, ref: el => (this.formField = el), onMouseEnter: () => (this.hovered = true), onMouseLeave: () => (this.hovered = false), style: cssVars }, h("div", { key: 'dc09d61d06f3cefb15dce980e293a266fdf3d79d', class: "sd-textarea__content" }, h("textarea", { key: '085de248d7376e0d19d3588bc836bd5ad17cb335', name: this.name, ref: el => (this.nativeEl = el), class: `sd-textarea__native ${this.textareaClass}`, value: this.internalValue || '', placeholder: this.placeholder, disabled: this.disabled, readOnly: this.readonly, autofocus: this.autoFocus, maxLength: this.maxLength, rows: this.rows, spellcheck: this.spellcheck, onInput: this.handleInput, onFocus: event => this.handleFocus('focus', event), onBlur: event => this.handleFocus('blur', event), style: this.textareaStyle }))));
131
+ return (h("sd-field", { key: 'a77834af45e2ca7abaa019d18b6108a51f0cf4ae', name: this.name, label: this.label, labelWidth: this.labelWidth, addonLabel: this.addonLabel, addonAlign: this.addonAlign, hint: this.hint, errorMessage: this.errorMessage, width: this.width, rules: this.rules, error: this.error, disabled: this.disabled, focused: this.focused, hovered: this.hovered, status: this.status, icon: this.icon, labelTooltip: this.labelTooltip, labelTooltipProps: this.labelTooltipProps, ref: el => (this.formField = el), onMouseEnter: () => (this.hovered = true), onMouseLeave: () => (this.hovered = false), style: cssVars }, h("div", { key: '2cbc8ef4febeab89eb336cb29d34abdbf9f2f080', class: "sd-textarea__content" }, h("textarea", { key: '3b09e30b4e42affc7f03fb8a354387b57e5ee0fe', name: this.name, ref: el => (this.nativeEl = el), class: `sd-textarea__native ${this.textareaClass}`, value: this.internalValue || '', placeholder: this.placeholder, disabled: this.disabled, readOnly: this.readonly, autofocus: this.autoFocus, maxLength: this.maxLength, rows: this.rows, spellcheck: this.spellcheck, onInput: this.handleInput, onFocus: event => this.handleFocus('focus', event), onBlur: event => this.handleFocus('blur', event), style: this.textareaStyle }))));
132
132
  }
133
133
  static get watchers() { return {
134
134
  "value": [{
@@ -232,7 +232,7 @@ const SdToastContainer = class {
232
232
  const activeToasts = toasts.filter(t => t.state !== 'exiting').reverse();
233
233
  const indexMap = new Map();
234
234
  activeToasts.forEach((t, i) => indexMap.set(t.id, i));
235
- return (h("div", { key: '601c4c5aa55df02459866607ca7c59da53c2eda5', class: "sd-toast-container", style: this.getContainerStyles(), onMouseEnter: () => {
235
+ return (h("div", { key: '5057793be2d6ce213edc84d58f7273248646dc19', class: "sd-toast-container", style: this.getContainerStyles(), onMouseEnter: () => {
236
236
  this.expanded = true;
237
237
  this.pauseTimers();
238
238
  }, onMouseLeave: () => {