@sellmate/design-system 0.0.23 → 0.0.25

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 (196) hide show
  1. package/dist/cjs/design-system.cjs.js +1 -1
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/{esm/color-CgyTlXBV.js → cjs/resolveColor-DxvExwgo.js} +17 -4
  4. package/dist/cjs/{resolveColor-CauSLF0s.js.map → resolveColor-DxvExwgo.js.map} +1 -1
  5. package/dist/cjs/sd-badge.cjs.entry.js +2 -3
  6. package/dist/cjs/sd-badge.entry.cjs.js.map +1 -1
  7. package/dist/cjs/sd-button.sd-checkbox.sd-guide.sd-icon.sd-input.sd-pagination.sd-portal.sd-select.sd-select-option.sd-table.sd-tooltip.sd-tooltip-portal.entry.cjs.js.map +1 -0
  8. package/dist/cjs/{sd-checkbox_9.cjs.entry.js → sd-button_12.cjs.entry.js} +738 -816
  9. package/dist/cjs/sd-card.cjs.entry.js +1 -1
  10. package/dist/cjs/sd-date-picker.cjs.entry.js +2 -2
  11. package/dist/cjs/sd-date-range-picker.cjs.entry.js +2 -2
  12. package/dist/cjs/sd-popover.cjs.entry.js +2 -2
  13. package/dist/cjs/sd-select-multiple-group.cjs.entry.js +380 -0
  14. package/dist/cjs/sd-select-multiple-group.entry.cjs.js.map +1 -0
  15. package/dist/cjs/sd-select-multiple.cjs.entry.js +263 -0
  16. package/dist/cjs/sd-select-multiple.entry.cjs.js.map +1 -0
  17. package/dist/cjs/sd-select-option-group.cjs.entry.js +69 -0
  18. package/dist/cjs/sd-select-option-group.entry.cjs.js.map +1 -0
  19. package/dist/cjs/sd-tag.cjs.entry.js +1 -1
  20. package/dist/cjs/select-keyboard-navigation-6fO_V4En.js +119 -0
  21. package/dist/cjs/select-keyboard-navigation-6fO_V4En.js.map +1 -0
  22. package/dist/collection/components/sd-badge/sd-badge.js +1 -1
  23. package/dist/collection/components/sd-card/sd-card.js +1 -1
  24. package/dist/collection/components/sd-date-picker/sd-date-picker.js +2 -2
  25. package/dist/collection/components/sd-date-range-picker/sd-date-range-picker.js +2 -2
  26. package/dist/collection/components/sd-guide/sd-guide.css +6 -1
  27. package/dist/collection/components/sd-guide/sd-guide.js +4 -4
  28. package/dist/collection/components/sd-guide/sd-guide.js.map +1 -1
  29. package/dist/collection/components/sd-icon/sd-icon.js +1 -1
  30. package/dist/collection/components/sd-input/sd-input.js +2 -2
  31. package/dist/collection/components/sd-pagination/sd-pagination.js +2 -3
  32. package/dist/collection/components/sd-pagination/sd-pagination.js.map +1 -1
  33. package/dist/collection/components/sd-popover/sd-popover.js +2 -2
  34. package/dist/collection/components/sd-portal/sd-portal.js +25 -4
  35. package/dist/collection/components/sd-portal/sd-portal.js.map +1 -1
  36. package/dist/collection/components/sd-select/sd-select-option/sd-select-option.js +1 -1
  37. package/dist/collection/components/sd-select/sd-select.css +0 -6
  38. package/dist/collection/components/sd-select-multiple/sd-select-multiple.css +0 -6
  39. package/dist/collection/components/sd-select-multiple/sd-select-multiple.js +2 -2
  40. package/dist/collection/components/sd-select-multiple-group/sd-select-multiple-group.css +0 -6
  41. package/dist/collection/components/sd-select-multiple-group/sd-select-option-group/sd-select-option-group.js +3 -3
  42. package/dist/collection/components/sd-table/sd-table.css +7 -1316
  43. package/dist/collection/components/sd-table/sd-table.js +99 -8
  44. package/dist/collection/components/sd-table/sd-table.js.map +1 -1
  45. package/dist/collection/components/sd-tag/sd-tag.js +1 -1
  46. package/dist/collection/components/sd-tooltip/sd-tooltip.js +4 -4
  47. package/dist/collection/components/sd-tooltip-portal/sd-tooltip-portal.js +1 -1
  48. package/dist/components/{p-QBJzxOWs.js → p-B0qn2Tb-.js} +3 -3
  49. package/dist/components/{p-QBJzxOWs.js.map → p-B0qn2Tb-.js.map} +1 -1
  50. package/dist/components/{p-DNUN6dGL.js → p-BHl-WJWF.js} +6 -7
  51. package/dist/components/p-BHl-WJWF.js.map +1 -0
  52. package/dist/components/{p-BqIcTSCQ.js → p-BRrY7yTi.js} +3 -3
  53. package/dist/components/{p-BqIcTSCQ.js.map → p-BRrY7yTi.js.map} +1 -1
  54. package/dist/components/{p-CbTvFUCY.js → p-B_lWW-k_.js} +27 -6
  55. package/dist/components/p-B_lWW-k_.js.map +1 -0
  56. package/dist/components/{p-CZG8wDBH.js → p-CpfDowFL.js} +3 -3
  57. package/dist/components/{p-CZG8wDBH.js.map → p-CpfDowFL.js.map} +1 -1
  58. package/dist/components/{p-aU8C4Pcb.js → p-D9gy3nk_.js} +7 -7
  59. package/dist/components/{p-aU8C4Pcb.js.map → p-D9gy3nk_.js.map} +1 -1
  60. package/dist/components/p-Dar88QJr.js +323 -0
  61. package/dist/components/p-Dar88QJr.js.map +1 -0
  62. package/dist/components/{p-Bl-wgv-z.js → p-Db_plCmk.js} +5 -5
  63. package/dist/components/{p-Bl-wgv-z.js.map → p-Db_plCmk.js.map} +1 -1
  64. package/dist/components/{p-nehvpX7w.js → p-DzIffEfK.js} +3 -3
  65. package/dist/components/{p-nehvpX7w.js.map → p-DzIffEfK.js.map} +1 -1
  66. package/dist/components/{p-DpiRZxT1.js → p-Ed1-kFCj.js} +5 -5
  67. package/dist/components/{p-DpiRZxT1.js.map → p-Ed1-kFCj.js.map} +1 -1
  68. package/dist/components/{p-Cxrr7vOk.js → p-_8cdZlN5.js} +9 -9
  69. package/dist/components/{p-Cxrr7vOk.js.map → p-_8cdZlN5.js.map} +1 -1
  70. package/dist/components/sd-badge.js +1 -1
  71. package/dist/components/sd-button.js +1 -1
  72. package/dist/components/sd-card.js +1 -1
  73. package/dist/components/sd-checkbox.js +1 -1
  74. package/dist/components/sd-date-picker.js +5 -5
  75. package/dist/components/sd-date-range-picker.js +5 -5
  76. package/dist/components/sd-guide.js +8 -8
  77. package/dist/components/sd-guide.js.map +1 -1
  78. package/dist/components/sd-icon.js +1 -1
  79. package/dist/components/sd-input.js +1 -1
  80. package/dist/components/sd-pagination.js +1 -1
  81. package/dist/components/sd-popover.js +5 -5
  82. package/dist/components/sd-portal.js +1 -1
  83. package/dist/components/sd-select-multiple-group.js +6 -6
  84. package/dist/components/sd-select-multiple-group.js.map +1 -1
  85. package/dist/components/sd-select-multiple.js +8 -8
  86. package/dist/components/sd-select-multiple.js.map +1 -1
  87. package/dist/components/sd-select-option-group.js +1 -1
  88. package/dist/components/sd-select-option.js +1 -1
  89. package/dist/components/sd-select.js +1 -318
  90. package/dist/components/sd-select.js.map +1 -1
  91. package/dist/components/sd-table.js +73 -19
  92. package/dist/components/sd-table.js.map +1 -1
  93. package/dist/components/sd-tag.js +1 -1
  94. package/dist/components/sd-tooltip-portal.js +1 -1
  95. package/dist/components/sd-tooltip.js +1 -1
  96. package/dist/design-system/design-system.esm.js +1 -1
  97. package/dist/design-system/p-33ce46fa.entry.js +2 -0
  98. package/dist/design-system/p-33ce46fa.entry.js.map +1 -0
  99. package/dist/design-system/p-52365554.entry.js +2 -0
  100. package/dist/design-system/{p-2aef624e.entry.js → p-58257c45.entry.js} +2 -2
  101. package/dist/design-system/p-7a71b770.entry.js +2 -0
  102. package/dist/design-system/p-7a71b770.entry.js.map +1 -0
  103. package/dist/design-system/{p-CgyTlXBV.js → p-BYf-ybt2.js} +2 -2
  104. package/dist/design-system/{p-BoLmB6pG.js.map → p-BYf-ybt2.js.map} +1 -1
  105. package/dist/design-system/p-C2JaR3A6.js +2 -0
  106. package/dist/design-system/p-C2JaR3A6.js.map +1 -0
  107. package/dist/design-system/p-b6bb891c.entry.js +2 -0
  108. package/dist/design-system/{p-c4f5ed94.entry.js → p-c96e287b.entry.js} +2 -2
  109. package/dist/design-system/p-dc35d827.entry.js +2 -0
  110. package/dist/design-system/p-dc35d827.entry.js.map +1 -0
  111. package/dist/design-system/p-f00fc7be.entry.js +2 -0
  112. package/dist/design-system/p-f00fc7be.entry.js.map +1 -0
  113. package/dist/design-system/{p-b537f724.entry.js → p-fcbeccb8.entry.js} +2 -2
  114. package/dist/design-system/p-ffe8c43b.entry.js +2 -0
  115. package/dist/design-system/p-ffe8c43b.entry.js.map +1 -0
  116. package/dist/design-system/sd-badge.entry.esm.js.map +1 -1
  117. package/dist/design-system/sd-button.sd-checkbox.sd-guide.sd-icon.sd-input.sd-pagination.sd-portal.sd-select.sd-select-option.sd-table.sd-tooltip.sd-tooltip-portal.entry.esm.js.map +1 -0
  118. package/dist/design-system/sd-select-multiple-group.entry.esm.js.map +1 -0
  119. package/dist/design-system/sd-select-multiple.entry.esm.js.map +1 -0
  120. package/dist/design-system/sd-select-option-group.entry.esm.js.map +1 -0
  121. package/dist/esm/design-system.js +1 -1
  122. package/dist/esm/loader.js +1 -1
  123. package/dist/{cjs/color-Oz29vj7L.js → esm/resolveColor-BYf-ybt2.js} +14 -6
  124. package/dist/esm/{resolveColor-CswQ9y2Q.js.map → resolveColor-BYf-ybt2.js.map} +1 -1
  125. package/dist/esm/sd-badge.entry.js +2 -3
  126. package/dist/esm/sd-badge.entry.js.map +1 -1
  127. package/dist/esm/sd-button.sd-checkbox.sd-guide.sd-icon.sd-input.sd-pagination.sd-portal.sd-select.sd-select-option.sd-table.sd-tooltip.sd-tooltip-portal.entry.js.map +1 -0
  128. package/dist/esm/{sd-checkbox_9.entry.js → sd-button_12.entry.js} +732 -813
  129. package/dist/esm/sd-card.entry.js +1 -1
  130. package/dist/esm/sd-date-picker.entry.js +2 -2
  131. package/dist/esm/sd-date-range-picker.entry.js +2 -2
  132. package/dist/esm/sd-popover.entry.js +2 -2
  133. package/dist/esm/sd-select-multiple-group.entry.js +378 -0
  134. package/dist/esm/sd-select-multiple-group.entry.js.map +1 -0
  135. package/dist/esm/sd-select-multiple.entry.js +261 -0
  136. package/dist/esm/sd-select-multiple.entry.js.map +1 -0
  137. package/dist/esm/sd-select-option-group.entry.js +67 -0
  138. package/dist/esm/sd-select-option-group.entry.js.map +1 -0
  139. package/dist/esm/sd-tag.entry.js +1 -1
  140. package/dist/esm/select-keyboard-navigation-C2JaR3A6.js +116 -0
  141. package/dist/esm/select-keyboard-navigation-C2JaR3A6.js.map +1 -0
  142. package/dist/types/components/sd-table/sd-table.d.ts +4 -0
  143. package/dist/types/components.d.ts +24 -0
  144. package/hydrate/index.js +98 -47
  145. package/hydrate/index.mjs +98 -47
  146. package/package.json +2 -2
  147. package/dist/cjs/color-Oz29vj7L.js.map +0 -1
  148. package/dist/cjs/resolveColor-CauSLF0s.js +0 -18
  149. package/dist/cjs/sd-button.sd-tooltip-portal.entry.cjs.js.map +0 -1
  150. package/dist/cjs/sd-button_2.cjs.entry.js +0 -221
  151. package/dist/cjs/sd-checkbox.sd-icon.sd-input.sd-portal.sd-select.sd-select-multiple.sd-select-multiple-group.sd-select-option.sd-select-option-group.entry.cjs.js.map +0 -1
  152. package/dist/cjs/sd-guide.cjs.entry.js +0 -84
  153. package/dist/cjs/sd-guide.entry.cjs.js.map +0 -1
  154. package/dist/cjs/sd-pagination.sd-tooltip.entry.cjs.js.map +0 -1
  155. package/dist/cjs/sd-pagination_2.cjs.entry.js +0 -168
  156. package/dist/cjs/sd-table.cjs.entry.js +0 -231
  157. package/dist/cjs/sd-table.entry.cjs.js.map +0 -1
  158. package/dist/components/p-CbTvFUCY.js.map +0 -1
  159. package/dist/components/p-DNUN6dGL.js.map +0 -1
  160. package/dist/design-system/p-158f9392.entry.js +0 -2
  161. package/dist/design-system/p-158f9392.entry.js.map +0 -1
  162. package/dist/design-system/p-37042d15.entry.js +0 -2
  163. package/dist/design-system/p-37042d15.entry.js.map +0 -1
  164. package/dist/design-system/p-949de8eb.entry.js +0 -2
  165. package/dist/design-system/p-949de8eb.entry.js.map +0 -1
  166. package/dist/design-system/p-9f5eed30.entry.js +0 -2
  167. package/dist/design-system/p-BoLmB6pG.js +0 -2
  168. package/dist/design-system/p-CgyTlXBV.js.map +0 -1
  169. package/dist/design-system/p-abfa217b.entry.js +0 -2
  170. package/dist/design-system/p-abfa217b.entry.js.map +0 -1
  171. package/dist/design-system/p-adee3154.entry.js +0 -2
  172. package/dist/design-system/p-adee3154.entry.js.map +0 -1
  173. package/dist/design-system/p-bda05b6f.entry.js +0 -2
  174. package/dist/design-system/p-bda05b6f.entry.js.map +0 -1
  175. package/dist/design-system/p-f015c024.entry.js +0 -2
  176. package/dist/design-system/sd-button.sd-tooltip-portal.entry.esm.js.map +0 -1
  177. package/dist/design-system/sd-checkbox.sd-icon.sd-input.sd-portal.sd-select.sd-select-multiple.sd-select-multiple-group.sd-select-option.sd-select-option-group.entry.esm.js.map +0 -1
  178. package/dist/design-system/sd-guide.entry.esm.js.map +0 -1
  179. package/dist/design-system/sd-pagination.sd-tooltip.entry.esm.js.map +0 -1
  180. package/dist/design-system/sd-table.entry.esm.js.map +0 -1
  181. package/dist/esm/color-CgyTlXBV.js.map +0 -1
  182. package/dist/esm/resolveColor-CswQ9y2Q.js +0 -16
  183. package/dist/esm/sd-button.sd-tooltip-portal.entry.js.map +0 -1
  184. package/dist/esm/sd-button_2.entry.js +0 -218
  185. package/dist/esm/sd-checkbox.sd-icon.sd-input.sd-portal.sd-select.sd-select-multiple.sd-select-multiple-group.sd-select-option.sd-select-option-group.entry.js.map +0 -1
  186. package/dist/esm/sd-guide.entry.js +0 -82
  187. package/dist/esm/sd-guide.entry.js.map +0 -1
  188. package/dist/esm/sd-pagination.sd-tooltip.entry.js.map +0 -1
  189. package/dist/esm/sd-pagination_2.entry.js +0 -165
  190. package/dist/esm/sd-table.entry.js +0 -229
  191. package/dist/esm/sd-table.entry.js.map +0 -1
  192. /package/dist/design-system/{p-9f5eed30.entry.js.map → p-52365554.entry.js.map} +0 -0
  193. /package/dist/design-system/{p-2aef624e.entry.js.map → p-58257c45.entry.js.map} +0 -0
  194. /package/dist/design-system/{p-f015c024.entry.js.map → p-b6bb891c.entry.js.map} +0 -0
  195. /package/dist/design-system/{p-c4f5ed94.entry.js.map → p-c96e287b.entry.js.map} +0 -0
  196. /package/dist/design-system/{p-b537f724.entry.js.map → p-fcbeccb8.entry.js.map} +0 -0
@@ -1,8 +1,69 @@
1
1
  'use strict';
2
2
 
3
3
  var index = require('./index-BjPOPvqs.js');
4
- var resolveColor = require('./resolveColor-CauSLF0s.js');
5
- require('./color-Oz29vj7L.js');
4
+ var resolveColor = require('./resolveColor-DxvExwgo.js');
5
+ var selectKeyboardNavigation = require('./select-keyboard-navigation-6fO_V4En.js');
6
+ var tooltipArrow = require('./tooltipArrow-qwvq153k.js');
7
+
8
+ const sdButtonCss = ".sd-button{text-decoration:none;cursor:pointer;border-radius:4px;transition:all 0.2s ease-in-out;position:relative;overflow:hidden;white-space:nowrap;-webkit-user-select:none;user-select:none;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center}.sd-button--xs{padding:0 8px;font-size:12px;font-weight:500;line-height:20px;min-height:24px}.sd-button--sm{padding:0 12px;font-size:12px;font-weight:500;line-height:20px;min-height:28px}.sd-button--md{padding:0 20px;font-size:16px;font-weight:500;line-height:26px;min-height:34px}.sd-button--lg{padding:0 28px;font-size:18px;font-weight:500;line-height:30px;min-height:62px}.sd-button--primary{background-color:var(--button-color);color:white;transition:filter 0.2s ease}.sd-button--primary::before{content:\"\";position:absolute;inset:0;background:#000000;opacity:0;transition:opacity 0.2s ease;z-index:0}.sd-button--primary:hover:not(.sd-button--disabled):not(.sd-button--loading)::before{opacity:0.25}.sd-button--outline{background:white;border:1px solid var(--button-color);color:var(--button-color)}.sd-button--outline::before{content:\"\";position:absolute;inset:0;background:var(--button-color);opacity:0;transition:opacity 0.2s ease;z-index:0}.sd-button--outline:hover:not(.sd-button--disabled):not(.sd-button--loading)::before{opacity:0.15}.sd-button--outline .sd-button__content{position:relative;z-index:1}.sd-button--ghost{background-color:transparent;color:var(--button-color);border-color:transparent}.sd-button--ghost::before{content:\"\";position:absolute;inset:0;background:var(--button-color);opacity:0;transition:opacity 0.2s ease;z-index:0}.sd-button--ghost:hover:not(.sd-button--disabled):not(.sd-button--loading)::before{opacity:0.15}.sd-button--ghost .sd-button__content{position:relative;z-index:1}.sd-button--disabled{border:1px solid #cccccc;background:#e1e1e1;color:#888888;cursor:not-allowed !important}.sd-button--icon-only{padding:0;width:fit-content;height:fit-content;aspect-ratio:1/1}.sd-button--no-hover:hover::before{opacity:0 !important}.sd-button .sd-button__content{display:inline-flex;align-items:center;justify-content:center;gap:4px;z-index:1;font-weight:500}";
9
+
10
+ const ICON_SIZES = {
11
+ xs: 12,
12
+ sm: 16,
13
+ md: 20,
14
+ lg: 24,
15
+ };
16
+ const SdButton = class {
17
+ constructor(hostRef) {
18
+ index.registerInstance(this, hostRef);
19
+ this.sdClick = index.createEvent(this, "sdClick");
20
+ }
21
+ get el() { return index.getElement(this); }
22
+ variant = 'primary';
23
+ size = 'sm';
24
+ color = '#025497';
25
+ label = '';
26
+ disabled = false;
27
+ type = 'button';
28
+ icon;
29
+ iconColor;
30
+ iconSize;
31
+ iconRight;
32
+ noHover = false;
33
+ class = '';
34
+ sdClick;
35
+ handleClick = (event) => {
36
+ if (this.disabled) {
37
+ event.preventDefault();
38
+ event.stopPropagation();
39
+ return;
40
+ }
41
+ this.sdClick.emit(event);
42
+ };
43
+ getButtonClasses() {
44
+ const classes = ['sd-button'];
45
+ classes.push(`sd-button--${this.variant}`);
46
+ classes.push(`sd-button--${this.size}`);
47
+ classes.push(`sd-button--color-${this.color}`);
48
+ if (this.disabled) {
49
+ classes.push('sd-button--disabled');
50
+ }
51
+ if (!this.label && (this.icon || this.iconRight)) {
52
+ classes.push('sd-button--icon-only');
53
+ }
54
+ if (this.noHover) {
55
+ classes.push('sd-button--no-hover');
56
+ }
57
+ return classes.join(' ');
58
+ }
59
+ render() {
60
+ const buttonClasses = this.getButtonClasses();
61
+ // 유틸로 색상 키 -> HEX 매핑 (없으면 원본 그대로)
62
+ const resolvedColor = resolveColor.resolveColor(this.color);
63
+ return (index.h(index.Host, { key: 'b30c8006e2f187fb971bcd47f8ce4a91d1dc47a6', style: { '--button-color': resolvedColor } }, index.h("button", { key: 'f494c93fc0b9d55537b468f5c6458569df962633', class: `${buttonClasses} ${this.class}`, type: this.type, disabled: this.disabled, onClick: this.handleClick }, index.h("div", { key: '7d64a6526baeac8569cccc60d9befacef3e3777d', class: "sd-button__content" }, this.icon && (index.h("sd-icon", { key: '9439e9456783aa5b057d383252a6b0c45a44b588', class: "sd-button__icon sd-button__icon--left", name: this.icon, size: this.iconSize ? this.iconSize : ICON_SIZES[this.size], color: this.iconColor ? this.iconColor : this.variant === 'primary' ? '#fff' : resolvedColor })), this.label && index.h("div", { key: '324371a6f8864c444cda39e7b349b4c9ec19b7f6', class: "sd-button__label" }, this.label), this.iconRight && (index.h("sd-icon", { key: '733790ceda6e1822c71911b17e66f527936b15a2', class: "sd-button__icon sd-button__icon--right", name: this.iconRight, size: ICON_SIZES[this.size], color: this.variant === 'primary' ? '#fff' : resolvedColor }))))));
64
+ }
65
+ };
66
+ SdButton.style = sdButtonCss;
6
67
 
7
68
  const sdCheckboxCss = "sd-checkbox{display:inline-block;height:20px;line-height:0}sd-checkbox .sd-checkbox{cursor:pointer;display:inline-flex;align-items:center;gap:8px;height:20px;max-height:20px}sd-checkbox .sd-checkbox>input{display:none}sd-checkbox .sd-checkbox:hover.sd-checkbox--checked .sd-checkbox__bg,sd-checkbox .sd-checkbox:hover.sd-checkbox--indeterminate .sd-checkbox__bg{border-color:#005cc9;background:#005cc9}sd-checkbox .sd-checkbox:hover.sd-checkbox--unchecked .sd-checkbox__bg{border:1px solid #0075ff;background:#d9eaff}sd-checkbox .sd-checkbox:hover.sd-checkbox--disabled .sd-checkbox__bg{border:1px solid transparent;background:#eeeeee}sd-checkbox .sd-checkbox__bg{width:16px;height:16px;border-radius:2px;border:1px solid #888888;box-sizing:border-box;display:inline-flex;justify-content:center;align-items:center;overflow:hidden;line-height:0}sd-checkbox .sd-checkbox__label{font-size:12px;color:#333333;line-height:20px}sd-checkbox .sd-checkbox--checked.sd-checkbox--disabled .sd-checkbox__bg,sd-checkbox .sd-checkbox--indeterminate.sd-checkbox--disabled .sd-checkbox__bg{background:#eeeeee;border:1px solid #cccccc !important}sd-checkbox .sd-checkbox--checked .sd-checkbox__bg,sd-checkbox .sd-checkbox--indeterminate .sd-checkbox__bg{border:1px solid #0075ff;background:#0075ff}sd-checkbox .sd-checkbox--unchecked .sd-checkbox__bg{background:white}sd-checkbox .sd-checkbox--disabled{cursor:not-allowed}sd-checkbox .sd-checkbox--disabled .sd-checkbox__bg{background:#eeeeee;border:1px solid #cccccc !important}";
8
69
 
@@ -86,6 +147,83 @@ const SdCheckbox = class {
86
147
  };
87
148
  SdCheckbox.style = sdCheckboxCss;
88
149
 
150
+ const sdGuideCss = "@charset \"UTF-8\";.sd-button{text-decoration:none;cursor:pointer;border-radius:4px;transition:all 0.2s ease-in-out;position:relative;overflow:hidden;white-space:nowrap;-webkit-user-select:none;user-select:none;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center}.sd-button--xs{padding:0 8px;font-size:12px;font-weight:500;line-height:20px;min-height:24px}.sd-button--sm{padding:0 12px;font-size:12px;font-weight:500;line-height:20px;min-height:28px}.sd-button--md{padding:0 20px;font-size:16px;font-weight:500;line-height:26px;min-height:34px}.sd-button--lg{padding:0 28px;font-size:18px;font-weight:500;line-height:30px;min-height:62px}.sd-button--primary{background-color:var(--button-color);color:white;transition:filter 0.2s ease}.sd-button--primary::before{content:\"\";position:absolute;inset:0;background:#000000;opacity:0;transition:opacity 0.2s ease;z-index:0}.sd-button--primary:hover:not(.sd-button--disabled):not(.sd-button--loading)::before{opacity:0.25}.sd-button--outline{background:white;border:1px solid var(--button-color);color:var(--button-color)}.sd-button--outline::before{content:\"\";position:absolute;inset:0;background:var(--button-color);opacity:0;transition:opacity 0.2s ease;z-index:0}.sd-button--outline:hover:not(.sd-button--disabled):not(.sd-button--loading)::before{opacity:0.15}.sd-button--outline .sd-button__content{position:relative;z-index:1}.sd-button--ghost{background-color:transparent;color:var(--button-color);border-color:transparent}.sd-button--ghost::before{content:\"\";position:absolute;inset:0;background:var(--button-color);opacity:0;transition:opacity 0.2s ease;z-index:0}.sd-button--ghost:hover:not(.sd-button--disabled):not(.sd-button--loading)::before{opacity:0.15}.sd-button--ghost .sd-button__content{position:relative;z-index:1}.sd-button--disabled{border:1px solid #cccccc;background:#e1e1e1;color:#888888;cursor:not-allowed !important}.sd-button--icon-only{padding:0;width:fit-content;height:fit-content;aspect-ratio:1/1}.sd-button--no-hover:hover::before{opacity:0 !important}.sd-button .sd-button__content{display:inline-flex;align-items:center;justify-content:center;gap:4px;z-index:1;font-weight:500}sd-guide{display:inline-block;height:fit-content}sd-guide .sd-guide{display:inline-block}sd-guide .sd-guide .sd-button{padding:0 16px 0 12px;border-radius:16px;color:#333333 !important;display:flex;align-items:center;transition:none}sd-guide .sd-guide .sd-button .sd-button__content{color:#333333 !important}sd-guide .sd-guide .sd-button .sd-button__content .sd-button__label{color:#333333 !important;margin-left:4px}sd-guide .sd-guide--active .sd-button{border:1px solid #12b553}sd-guide .sd-guide--active .sd-button .sd-button__content .sd-button__label{color:white !important}.sd-guide__popup{position:relative;padding:20px 32px;border-radius:8px;box-shadow:4px 4px 24px 4px rgba(0, 0, 0, 0.1);background:white}.sd-guide__popup>.sd-guide__popup__close{position:absolute;top:12px;right:12px}.sd-guide__popup__header{display:flex;align-items:center;gap:8px;margin-bottom:12px}.sd-guide__popup__header .sd-guide__popup__title{margin-top:0;font-size:16px;font-weight:700;line-height:26px;color:#333333}.sd-guide__popup__list{width:100%;padding:0;margin:0}.sd-guide__popup__list__item{display:flex;width:100%;align-items:start;list-style:none;color:#333333;font-size:12px;font-weight:400}.sd-guide__popup__list__item p{width:100%;padding:0;margin:0;word-wrap:break-word;word-break:break-word;white-space:normal;overflow-wrap:break-word;min-width:0}.sd-guide__popup__list__item::before{display:block;content:\"-\";width:6px;color:#333333;font-size:12px;font-weight:400;margin-left:10px;margin-right:12px;flex-shrink:0}.sd-guide__popup__list__item--depth-2::before{content:\"•\"}.sd-guide__popup__list__item--depth-2{padding-left:26px}";
151
+
152
+ const GUIDE_LABEL = {
153
+ help: '활용 TIP',
154
+ pdf: 'PDF Guide',
155
+ youtube: 'Video Guide',
156
+ notion: '사용 가이드',
157
+ event: 'Event Button',
158
+ };
159
+ const GUIDE_ICON = {
160
+ help: {
161
+ name: 'helpOutline',
162
+ size: 20,
163
+ color: resolveColor.colors.green_70,
164
+ },
165
+ pdf: { name: 'pdf', size: 20, color: resolveColor.colors.red_75 },
166
+ youtube: { name: 'youtube', size: 20, color: resolveColor.colors.red_75 },
167
+ notion: { name: 'notion', size: 16, color: resolveColor.colors.black },
168
+ event: { name: 'event', size: 16, color: resolveColor.colors.brilliantblue_70 },
169
+ };
170
+ const SdGuide = class {
171
+ constructor(hostRef) {
172
+ index.registerInstance(this, hostRef);
173
+ }
174
+ get el() { return index.getElement(this); }
175
+ type = 'help';
176
+ label = '';
177
+ message = '';
178
+ guideUrl = '';
179
+ popupWidth;
180
+ popupShow = false;
181
+ guideRef;
182
+ handleClickGuide = () => {
183
+ if (this.type === 'help') {
184
+ this.popupShow = !this.popupShow;
185
+ return;
186
+ }
187
+ if (this.guideUrl) {
188
+ window.open(this.guideUrl, '_blank');
189
+ }
190
+ };
191
+ get guideClass() {
192
+ const classes = ['sd-guide', `sd-guide--${this.type}`];
193
+ if (this.popupShow)
194
+ classes.push('sd-guide--active');
195
+ return classes.join(' ');
196
+ }
197
+ closeDropdown = () => {
198
+ this.popupShow = false;
199
+ };
200
+ render() {
201
+ const { name: iconName, size: iconSize, color: iconColor } = GUIDE_ICON[this.type];
202
+ return (index.h(index.Host, { key: '1365e7c6c52a218e419f94dc741a70e74b954bc6', style: {
203
+ '--sd-guide-color': GUIDE_ICON[this.type].color,
204
+ } }, index.h("sd-button", { key: '23cab4f2354f889012d0eb39ff04daf5a469c24a', ref: el => (this.guideRef = el), class: this.guideClass, variant: this.popupShow ? 'primary' : 'outline', label: GUIDE_LABEL[this.type], size: "sm", color: this.popupShow ? GUIDE_ICON[this.type].color : 'grey_45', icon: iconName, iconColor: this.popupShow ? 'white' : iconColor, iconSize: iconSize, noHover: this.popupShow, onSdClick: this.handleClickGuide }), this.type === 'help' && this.popupShow && (index.h("sd-portal", { key: '7d9c7a40a1f1d0a49388b207882ebe3510a0797c', open: this.popupShow, parentRef: this.guideRef, onSdClose: this.closeDropdown, offset: [0, 4] }, index.h("div", { key: '4e61879615a5e4466cc572df02b571b4bbf6b604', class: "sd-guide__popup", style: { width: this.popupWidth ? this.popupWidth + 'px' : '426px' } }, index.h("sd-button", { key: 'e365cd7b185f194871d5780b892683b84a1f97c5', class: "sd-guide__popup__close", icon: "close", color: resolveColor.colors.grey_65, size: "md", variant: "ghost", noHover: true,
205
+ // buttonStyle={{ padding: '0px', minHeight: '0px' }}
206
+ onSdClick: this.closeDropdown }), index.h("div", { key: '1198a0d6a84321395501a7afe9f003c627c1c2bc', class: "sd-guide__popup__header" }, index.h("sd-icon", { key: 'b4aee8ab7a237c9ae6475291cd5c51997b8505e9', name: "helpOutline", size: 24, color: resolveColor.colors.green_65 }), index.h("h3", { key: '9bc0f5ef484f950d6659c9bc8a27ce42bc315048', class: "sd-guide__popup__title" }, this.label || GUIDE_LABEL[this.type])), index.h("ul", { key: 'bb2d3ec6369dd464410771af81343735963b4a9c', class: "sd-guide__popup__list" }, this.renderListItem(this.message)))))));
207
+ }
208
+ // 현재 2depth까지만 스타일 적용
209
+ renderListItem(message, depth = 0) {
210
+ const listItems = [];
211
+ if (Array.isArray(message)) {
212
+ const depthMsg = message.map(msg => this.renderListItem(msg, depth + 1));
213
+ listItems.push(...depthMsg.flat());
214
+ }
215
+ else {
216
+ listItems.push(this.renderLi(message, depth));
217
+ }
218
+ return listItems;
219
+ }
220
+ renderLi = (message, depth) => {
221
+ const listContent = message.replace(/ /gi, ' ');
222
+ return (index.h("li", { class: `sd-guide__popup__list__item sd-guide__popup__list__item--depth-${depth}` }, index.h("p", { innerHTML: listContent })));
223
+ };
224
+ };
225
+ SdGuide.style = sdGuideCss;
226
+
89
227
  const Check12 = (props) => {
90
228
  return (index.h("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props }, index.h("g", { "clip-path": "url(#clip0_8697_9693)" }, index.h("path", { d: "M10.5962 3.19745L5.02773 8.76591C4.97891 8.81473 4.89977 8.81473 4.85095 8.76591L1.40381 5.31877", stroke: "currentColor", "stroke-width": "0.75", "stroke-linecap": "round" })), index.h("defs", null, index.h("clipPath", { id: "clip0_8697_9693" }, index.h("rect", { width: "12", height: "12", fill: "none" })))));
91
229
  };
@@ -447,7 +585,7 @@ const SdIcon = class {
447
585
  }
448
586
  render() {
449
587
  const IconComponent = Icons[this.name]?.[this.size];
450
- return (index.h("i", { key: '20f187a90566d35f7c459480b6917061cd26c734', class: this.getIconClasses(), style: this.iconStyle }, index.h(IconComponent, { key: '9db914748d948a695b248d04e5008e726ac6e4d2', color: this.resolvedColor })));
588
+ return (index.h("i", { key: 'c0d4a3993efc47345406ba9b30e49cefaa14f8da', class: this.getIconClasses(), style: this.iconStyle }, index.h(IconComponent, { key: '47476081ac11dd8ef1b04d9372d05f4afe72b323', color: this.resolvedColor })));
451
589
  }
452
590
  };
453
591
  SdIcon.style = sdIconCss;
@@ -552,11 +690,11 @@ const SdInput = class {
552
690
  '--input-width': typeof this.width === 'number' ? `${this.width}px` : this.width,
553
691
  }
554
692
  : {};
555
- return (index.h(index.Host, { key: '099f819c08b8eb4627f7857d10877d2a9bbeac51', style: inputWidth }, this.label && index.h("div", { key: 'ef1dffa2707e2f2844efee6646e14b750ea7c319', class: "sd-input__label" }, this.label), index.h("label", { key: '89e8a0ea5a02ecd114b9e1a7cb9fdcdce0130849', class: {
693
+ return (index.h(index.Host, { key: '9a0b975f20b4b8bbc8bff2aef4ee9036450921d4', style: inputWidth }, this.label && index.h("div", { key: 'ec6c840dcdaa7b9788c32ecbd03dc5daee74c748', class: "sd-input__label" }, this.label), index.h("label", { key: '4c11c34fd26897b50e0cfbb569de476c9e06884c', class: {
556
694
  'sd-input': true,
557
695
  [this.getInputStatus()]: true,
558
696
  'sd-input--barcode': !!this.barcode,
559
- }, onMouseEnter: () => (this.hovered = true), onMouseLeave: () => (this.hovered = false), style: this.inputStyle }, index.h("slot", { key: 'b1c64655ea940ae454bac4aed58df8944ed579a3', name: "prefix" }), index.h("input", { key: '1bb32efb0c46d3e1b91ac90c64e60943ac59ee41', ref: el => (this.nativeEl = el), class: `sd-input__native_element ${this.inputClass}`, type: "text", value: this.internalValue || '', placeholder: this.placeholder, disabled: this.disabled, readonly: this.readonly, autofocus: this.autoFocus, onInput: this.handleInput, onChange: this.handleChange, onFocus: event => this.handleFocus('focus', event), onBlur: event => this.handleFocus('blur', event) }), index.h("slot", { key: 'bcdc6e6780b6eba56e788665669abcfe04406e64', name: "suffix" }), this.clearable && this.internalValue && (index.h("sd-icon", { key: '3f8d9fe950d5313f0df807b06ffd5872dc4b1835', name: "close", color: "#888", class: "sd-input__clear-icon", onClick: () => {
697
+ }, onMouseEnter: () => (this.hovered = true), onMouseLeave: () => (this.hovered = false), style: this.inputStyle }, index.h("slot", { key: '0d7df02ed548b12f415bd72f84ea411fde5ef549', name: "prefix" }), index.h("input", { key: '6203dcb95fd486d263e0fe33495243e95c332e1a', ref: el => (this.nativeEl = el), class: `sd-input__native_element ${this.inputClass}`, type: "text", value: this.internalValue || '', placeholder: this.placeholder, disabled: this.disabled, readonly: this.readonly, autofocus: this.autoFocus, onInput: this.handleInput, onChange: this.handleChange, onFocus: event => this.handleFocus('focus', event), onBlur: event => this.handleFocus('blur', event) }), index.h("slot", { key: '21544173b390be5607c50faf84f1d47fa703e8bf', name: "suffix" }), this.clearable && this.internalValue && (index.h("sd-icon", { key: 'af486def3d146c4638d1f6fecf95a6de61e8d528', name: "close", color: "#888", class: "sd-input__clear-icon", onClick: () => {
560
698
  this.internalValue = '';
561
699
  this.sdChange?.emit(this.internalValue);
562
700
  this.sdInput?.emit(this.internalValue);
@@ -569,6 +707,100 @@ const SdInput = class {
569
707
  };
570
708
  SdInput.style = sdInputCss;
571
709
 
710
+ const sdPaginationCss = ".sd-pagination{display:flex;flex-flow:row nowrap;align-items:center;justify-content:center;gap:8px;color:#555555;width:100%;font-size:12px}.sd-pagination .prepend-btns{display:flex;flex-flow:row nowrap;align-items:center;gap:8px;width:60px}.sd-pagination .prepend-btns button{width:26px;height:26px;border:0;background:none}.sd-pagination .prepend-btns button:hover{border:1px solid #006ac1;border-radius:14px}.sd-pagination .append-btns{display:flex;flex-flow:row nowrap;align-items:center;gap:8px;width:60px}.sd-pagination .append-btns button{width:26px;height:26px;border:0;background:none}.sd-pagination .append-btns button:hover{border:1px solid #006ac1;border-radius:14px}.sd-pagination .pagination-btn{display:flex;align-items:center;justify-content:center;border-radius:14px;outline:none;border:none;cursor:pointer;height:26px;color:#555555;width:var(--pagination-btn-width, 26px)}.sd-pagination .pagination-btn--selected{background-color:#006ac1;color:white}.sd-pagination .pagination-btn:hover{border:1px solid #006ac1}.sd-pagination--simple .pagination-info{line-height:26px;display:flex;flex-flow:row nowrap;align-items:center;gap:8px}.sd-pagination--simple .pagination-info .current-page,.sd-pagination--simple .pagination-info .last-page{padding:0 2px}";
711
+
712
+ const BUTTON_WIDTH = {
713
+ 1: 26,
714
+ 2: 36,
715
+ 3: 42,
716
+ 4: 50,
717
+ 5: 58,
718
+ };
719
+ const PER_PAGE = 10;
720
+ const SdPagination = class {
721
+ constructor(hostRef) {
722
+ index.registerInstance(this, hostRef);
723
+ this.pageChange = index.createEvent(this, "pageChange");
724
+ }
725
+ currentPage = 1;
726
+ lastPage = 1;
727
+ simple = false;
728
+ pageChange;
729
+ onPropChange() {
730
+ console.log('Pagination props changed', {
731
+ currentPage: this.currentPage,
732
+ lastPage: this.lastPage,
733
+ });
734
+ }
735
+ get paginationClasses() {
736
+ const classes = ['sd-pagination'];
737
+ if (this.simple) {
738
+ classes.push('sd-pagination--simple');
739
+ }
740
+ return classes.join(' ');
741
+ }
742
+ get pageNumbers() {
743
+ const start = Math.floor((this.currentPage - 1) / PER_PAGE) * PER_PAGE + 1;
744
+ const end = Math.min(start + PER_PAGE - 1, this.lastPage);
745
+ return Array.from({ length: end - start + 1 }, (_, i) => start + i);
746
+ }
747
+ get buttonWidth() {
748
+ const lastPageNum = this.pageNumbers.at(-1) ?? 1;
749
+ const maxPageLength = lastPageNum.toString().length;
750
+ return BUTTON_WIDTH[maxPageLength] || BUTTON_WIDTH[1];
751
+ }
752
+ handlePageChange(page) {
753
+ if (page < 1 || page > this.lastPage)
754
+ return;
755
+ this.pageChange.emit(page);
756
+ }
757
+ handleGroupChange(direction) {
758
+ const delta = direction === 'forward' ? PER_PAGE : -10;
759
+ const newPage = Math.min(Math.max(this.currentPage + delta, 1), this.lastPage);
760
+ this.handlePageChange(newPage);
761
+ }
762
+ get isFirstGroup() {
763
+ return this.currentPage <= PER_PAGE;
764
+ }
765
+ get isLastGroup() {
766
+ const startPageGroup = Math.floor((this.currentPage - 1) / PER_PAGE) * PER_PAGE + 1;
767
+ return startPageGroup + PER_PAGE - 1 >= this.lastPage;
768
+ }
769
+ renderPrevButtons() {
770
+ if (this.simple) {
771
+ if (this.currentPage <= 1)
772
+ return null;
773
+ return (index.h(index.Fragment, null, index.h("button", { "aria-label": "Go to first page", onClick: () => this.handlePageChange(1) }, index.h("sd-icon", { name: "arrowLeftEnd", size: "12", color: "#222222" })), index.h("button", { "aria-label": "Go to previous page", onClick: () => this.handlePageChange(this.currentPage - 1) }, index.h("sd-icon", { name: "arrowLeft", size: "12", color: "#222222" }))));
774
+ }
775
+ if (!this.isFirstGroup) {
776
+ return (index.h(index.Fragment, null, index.h("button", { "aria-label": "Go to first page", onClick: () => this.handlePageChange(1) }, index.h("sd-icon", { name: "arrowLeftEnd", size: "12", color: "#222222" })), index.h("button", { "aria-label": "Go to previous page group", onClick: () => this.handleGroupChange('backward') }, index.h("sd-icon", { name: "arrowLeft", size: "12", color: "#222222" }))));
777
+ }
778
+ }
779
+ renderNextButtons() {
780
+ if (this.simple) {
781
+ if (this.currentPage >= this.lastPage)
782
+ return null;
783
+ return (index.h(index.Fragment, null, index.h("button", { "aria-label": "Go to next page", onClick: () => this.handlePageChange(this.currentPage + 1) }, index.h("sd-icon", { name: "arrowRight", size: "12", color: "#222222" })), index.h("button", { "aria-label": "Go to last page", onClick: () => this.handlePageChange(this.lastPage) }, index.h("sd-icon", { name: "arrowRightEnd", size: "12", color: "#222222" }))));
784
+ }
785
+ if (!this.isLastGroup) {
786
+ return (index.h(index.Fragment, null, index.h("button", { "aria-label": "Go to next page group", onClick: () => this.handleGroupChange('forward') }, index.h("sd-icon", { name: "arrowRight", size: "12", color: "#222222" })), index.h("button", { "aria-label": "Go to last page", onClick: () => this.handlePageChange(this.lastPage) }, index.h("sd-icon", { name: "arrowRightEnd", size: "12", color: "#222222" }))));
787
+ }
788
+ }
789
+ render() {
790
+ return (index.h("div", { key: '2707331958e2c375b570590a8742655bacb1aa4d', class: this.paginationClasses }, index.h("div", { key: 'e98573b80c04454ea0b30f6cb7fe1974028a0464', class: "prepend-btns" }, this.renderPrevButtons()), this.simple ? (index.h("div", { class: "pagination-info" }, index.h("span", { class: "current-page" }, this.currentPage), index.h("span", null, "/"), index.h("span", { class: "last-page" }, this.lastPage))) : (this.pageNumbers.map(n => (index.h("button", { type: "button", "aria-current": this.currentPage === n ? 'page' : undefined, class: {
791
+ 'pagination-btn': true,
792
+ 'pagination-btn--selected': this.currentPage === n,
793
+ }, disabled: this.currentPage === n, style: {
794
+ '--pagination-btn-width': `${this.buttonWidth}px`,
795
+ }, onClick: () => this.handlePageChange(n) }, n)))), index.h("div", { key: 'ccb867eccaece5ecbdcef7abe0e4d333fb169d11', class: "append-btns" }, this.renderNextButtons())));
796
+ }
797
+ static get watchers() { return {
798
+ "currentPage": ["onPropChange"],
799
+ "lastPage": ["onPropChange"]
800
+ }; }
801
+ };
802
+ SdPagination.style = sdPaginationCss;
803
+
572
804
  const SdPortal = class {
573
805
  constructor(hostRef) {
574
806
  index.registerInstance(this, hostRef);
@@ -631,9 +863,30 @@ const SdPortal = class {
631
863
  this.rafId = requestAnimationFrame(() => {
632
864
  if (!this.parentRef || !this.wrapper)
633
865
  return;
634
- const rect = this.parentRef.getBoundingClientRect();
635
- this.wrapper.style.top = `${rect.bottom + window.scrollY + this.offset[1]}px`;
636
- this.wrapper.style.left = `${rect.left + window.scrollX + this.offset[0]}px`;
866
+ const parentRect = this.parentRef.getBoundingClientRect();
867
+ const wrapperRect = this.wrapper.getBoundingClientRect();
868
+ const viewport = {
869
+ width: window.innerWidth,
870
+ height: window.innerHeight,
871
+ };
872
+ let top = parentRect.bottom + window.scrollY + this.offset[1];
873
+ let left = parentRect.left + window.scrollX + this.offset[0];
874
+ // 화면 상하단 넘어갈 시 반전
875
+ if (parentRect.bottom + wrapperRect.height + this.offset[1] > viewport.height) {
876
+ top = parentRect.top + window.scrollY - wrapperRect.height - this.offset[1];
877
+ }
878
+ if (top < window.scrollY) {
879
+ top = parentRect.bottom + window.scrollY + this.offset[1];
880
+ }
881
+ // 화면 좌우측 넘어갈 시 반전
882
+ if (parentRect.left + wrapperRect.width + this.offset[0] > viewport.width) {
883
+ left = parentRect.right + window.scrollX - wrapperRect.width - this.offset[0];
884
+ }
885
+ if (left < 0) {
886
+ left = this.offset[0];
887
+ }
888
+ this.wrapper.style.top = `${top}px`;
889
+ this.wrapper.style.left = `${left}px`;
637
890
  });
638
891
  }
639
892
  // parentRef의 이동 / 크기변경 감지
@@ -666,125 +919,13 @@ const SdPortal = class {
666
919
  this.sdClose.emit();
667
920
  }
668
921
  render() {
669
- return index.h("slot", { key: '9ccb84d877ac49b85e64a12c1f1ff4b3105b2213' });
922
+ return index.h("slot", { key: '4f344b083ff3a2d32d1a23f99e90687aeeb676b1' });
670
923
  }
671
924
  };
672
925
 
673
- class DropdownManager {
674
- static instance;
675
- activeDropdowns = new Set();
676
- static getInstance() {
677
- if (!DropdownManager.instance) {
678
- DropdownManager.instance = new DropdownManager();
679
- }
680
- return DropdownManager.instance;
681
- }
682
- register(component) {
683
- this.activeDropdowns.add(component);
684
- }
685
- unregister(component) {
686
- this.activeDropdowns.delete(component);
687
- }
688
- openDropdown(targetComponent) {
689
- // 다른 모든 드롭다운 닫기
690
- this.activeDropdowns.forEach(component => {
691
- if (component !== targetComponent && component.isOpen) {
692
- component.closeDropdown();
693
- }
694
- });
695
- }
696
- closeAllDropdowns() {
697
- this.activeDropdowns.forEach(component => {
698
- if (component.isOpen) {
699
- component.closeDropdown();
700
- }
701
- });
702
- }
703
- }
704
- const dropdownManager = DropdownManager.getInstance();
705
-
706
- // 여러 select를 동시에 사용할때에 이벤트 리스너의 등록이 충돌나는 문제를 해결하기 위한 Base class
707
- // 각 드롭다운 컴포넌트는 이 클래스를 상속 및 구현 필요
708
- // 기본적으로 click, keydown 추상 이벤트를 구현해야하고
709
- // isOpen가 true일때에만 이벤트 등록 그외에는 이벤트 클리닝을 수행
710
- // 추후 필요한 이벤트는 이곳에 추가하여 추가 구현 후 사용
711
- // 별도로 드롭다운 전용의 Base class가 아닌 공통적으로 사용할 수 있는 Base class가 필요할지 검토 필요
712
- class BaseDropdownEvent {
713
- documentClickHandler;
714
- documentKeydownHandler;
715
- // 컴포넌트 생명주기에서 호출할 메서드들
716
- initializeEvent() {
717
- dropdownManager.register(this);
718
- this.initializeEventHandlers();
719
- }
720
- cleanupEvent() {
721
- dropdownManager.unregister(this);
722
- this.cleanup();
723
- }
724
- initializeEventHandlers() {
725
- this.documentClickHandler = (event) => this.handleDocumentClick(event);
726
- this.documentKeydownHandler = (event) => this.handleDocumentKeydown(event);
727
- }
728
- addGlobalEventListeners() {
729
- if (this.documentClickHandler) {
730
- document.addEventListener('click', this.documentClickHandler);
731
- }
732
- if (this.documentKeydownHandler) {
733
- document.addEventListener('keydown', this.documentKeydownHandler);
734
- }
735
- }
736
- removeGlobalEventListeners() {
737
- if (this.documentClickHandler) {
738
- document.removeEventListener('click', this.documentClickHandler);
739
- }
740
- if (this.documentKeydownHandler) {
741
- document.removeEventListener('keydown', this.documentKeydownHandler);
742
- }
743
- }
744
- onDropdownToggle(isOpen) {
745
- if (isOpen && !this.disabled) {
746
- dropdownManager.openDropdown(this);
747
- this.addGlobalEventListeners();
748
- }
749
- else {
750
- this.removeGlobalEventListeners();
751
- }
752
- }
753
- cleanup() {
754
- this.removeGlobalEventListeners();
755
- }
756
- closeDropdown() {
757
- this.isOpen = false;
758
- }
759
- }
760
-
761
- class SelectKeyboardNavigation {
762
- isSearchable;
763
- filteredOptions;
764
- constructor(isSearchable, filteredOptions) {
765
- this.isSearchable = isSearchable;
766
- this.filteredOptions = filteredOptions;
767
- }
768
- getNavigationBounds() {
769
- return {
770
- minIndex: this.isSearchable ? -1 : 0,
771
- maxIndex: this.filteredOptions.length - 1,
772
- };
773
- }
774
- getNextIndex(currentIndex, direction) {
775
- const { minIndex, maxIndex } = this.getNavigationBounds();
776
- if (direction === 'ArrowUp') {
777
- return currentIndex > minIndex ? currentIndex - 1 : maxIndex;
778
- }
779
- else {
780
- return currentIndex < maxIndex ? currentIndex + 1 : minIndex;
781
- }
782
- }
783
- }
784
-
785
- const sdSelectCss = ".sd-select__dropdown{overflow-y:auto;overflow-x:hidden;scroll-behavior:smooth}.sd-select__dropdown::-webkit-scrollbar{opacity:0;background:#e5e5e5}.sd-select__dropdown::-webkit-scrollbar:horizontal{height:8px}.sd-select__dropdown::-webkit-scrollbar:vertical{width:8px}.sd-select__dropdown::-webkit-scrollbar-thumb{height:80px;background-color:#cccccc;border-radius:4px}.sd-select__dropdown::-webkit-scrollbar-thumb:hover{background:#e5e5e5}.sd-select__dropdown::-webkit-scrollbar-thumb:active{background:#e5e5e5}.sd-select__dropdown::-webkit-scrollbar-track{background-color:transparent}.sd-select{display:flex;width:var(--select-width, 200px);height:28px;position:relative;color:#333333;cursor:pointer;user-select:none;border:1px solid #aaaaaa;border-radius:4px;background-color:white}.sd-select:hover:not(.sd-select--disabled){background:#f6f6f6}.sd-select.sd-select--disabled{cursor:not-allowed;background-color:#eeeeee;border-color:#cccccc}.sd-select.sd-select--disabled .sd-select__label{border-right:1px solid #cccccc}.sd-select.sd-select--disabled .sd-select__trigger{color:#888888}.sd-select.sd-select--disabled .sd-select__trigger:focus,.sd-select.sd-select--disabled .sd-select__trigger:focus-visible,.sd-select.sd-select--disabled .sd-select__trigger:focus-within{outline:none !important}.sd-select__label{font-size:12px;line-height:20px;font-weight:500;color:#333333;padding:4px 12px;border-right:1px solid #cccccc;border-radius:4px 0 0 4px;background-color:#f6f6f6;display:inline-block;white-space:nowrap}.sd-select__container{position:relative;width:100%;display:flex}.sd-select__container .sd-select__trigger{padding:4px 20px 4px 12px;display:flex;width:100%;align-items:center}.sd-select__container .sd-select__trigger .sd-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:20px;font-size:12px;font-weight:400;text-align:left}.sd-select__container .sd-select__trigger .sd-select__clear{margin:0 4px;width:8px;height:8px;background-color:transparent;outline:none;border:none}.sd-select__container .sd-select__arrow{position:absolute;top:8px;right:8px;width:12px;height:12px;color:#888888;transition:transform 0.3s ease}.sd-select__container .sd-select__arrow--open{transform:rotate(180deg)}.sd-select__dropdown{width:var(--select-dropdown-width, 200px);max-height:var(--select-dropdown-height, 260px);padding-bottom:2px;background-color:white;box-shadow:2px 2px 12px 2px rgba(0, 0, 0, 0.1);border-radius:4px;overflow-y:auto;color:#333333;display:flex;flex-direction:column}.sd-select__dropdown .sd-select__search-container{position:sticky;top:0;display:flex;width:100%;background-color:white;align-items:center;padding:4px 8px}.sd-select__dropdown .sd-select__search-container--scrolled{box-shadow:2px 2px 8px 2px rgba(0, 0, 0, 0.2)}.sd-select__dropdown .sd-select__option-placeholder{padding:4px 12px;font-size:12px;line-height:20px;text-align:left}";
926
+ const sdSelectCss = ".sd-select__dropdown{overflow-y:auto;overflow-x:hidden;scroll-behavior:smooth}.sd-select__dropdown::-webkit-scrollbar{opacity:0;background:#e5e5e5}.sd-select__dropdown::-webkit-scrollbar:horizontal{height:8px}.sd-select__dropdown::-webkit-scrollbar:vertical{width:8px}.sd-select__dropdown::-webkit-scrollbar-thumb{height:80px;background-color:#cccccc;border-radius:4px}.sd-select__dropdown::-webkit-scrollbar-track{background-color:transparent}.sd-select{display:flex;width:var(--select-width, 200px);height:28px;position:relative;color:#333333;cursor:pointer;user-select:none;border:1px solid #aaaaaa;border-radius:4px;background-color:white}.sd-select:hover:not(.sd-select--disabled){background:#f6f6f6}.sd-select.sd-select--disabled{cursor:not-allowed;background-color:#eeeeee;border-color:#cccccc}.sd-select.sd-select--disabled .sd-select__label{border-right:1px solid #cccccc}.sd-select.sd-select--disabled .sd-select__trigger{color:#888888}.sd-select.sd-select--disabled .sd-select__trigger:focus,.sd-select.sd-select--disabled .sd-select__trigger:focus-visible,.sd-select.sd-select--disabled .sd-select__trigger:focus-within{outline:none !important}.sd-select__label{font-size:12px;line-height:20px;font-weight:500;color:#333333;padding:4px 12px;border-right:1px solid #cccccc;border-radius:4px 0 0 4px;background-color:#f6f6f6;display:inline-block;white-space:nowrap}.sd-select__container{position:relative;width:100%;display:flex}.sd-select__container .sd-select__trigger{padding:4px 20px 4px 12px;display:flex;width:100%;align-items:center}.sd-select__container .sd-select__trigger .sd-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:20px;font-size:12px;font-weight:400;text-align:left}.sd-select__container .sd-select__trigger .sd-select__clear{margin:0 4px;width:8px;height:8px;background-color:transparent;outline:none;border:none}.sd-select__container .sd-select__arrow{position:absolute;top:8px;right:8px;width:12px;height:12px;color:#888888;transition:transform 0.3s ease}.sd-select__container .sd-select__arrow--open{transform:rotate(180deg)}.sd-select__dropdown{width:var(--select-dropdown-width, 200px);max-height:var(--select-dropdown-height, 260px);padding-bottom:2px;background-color:white;box-shadow:2px 2px 12px 2px rgba(0, 0, 0, 0.1);border-radius:4px;overflow-y:auto;color:#333333;display:flex;flex-direction:column}.sd-select__dropdown .sd-select__search-container{position:sticky;top:0;display:flex;width:100%;background-color:white;align-items:center;padding:4px 8px}.sd-select__dropdown .sd-select__search-container--scrolled{box-shadow:2px 2px 8px 2px rgba(0, 0, 0, 0.2)}.sd-select__dropdown .sd-select__option-placeholder{padding:4px 12px;font-size:12px;line-height:20px;text-align:left}";
786
927
 
787
- const SdSelect = class extends BaseDropdownEvent {
928
+ const SdSelect = class extends selectKeyboardNavigation.BaseDropdownEvent {
788
929
  constructor(hostRef) {
789
930
  super();
790
931
  index.registerInstance(this, hostRef);
@@ -899,7 +1040,7 @@ const SdSelect = class extends BaseDropdownEvent {
899
1040
  switch (keyboardEvent.key) {
900
1041
  case 'ArrowDown':
901
1042
  case 'ArrowUp':
902
- const keyboardNavigation = new SelectKeyboardNavigation(this.searchable, this.filteredOptions);
1043
+ const keyboardNavigation = new selectKeyboardNavigation.SelectKeyboardNavigation(this.searchable, this.filteredOptions);
903
1044
  const nextIndex = keyboardNavigation.getNextIndex(this.itemIndex, keyboardEvent.key);
904
1045
  this.itemIndex = nextIndex;
905
1046
  break;
@@ -1030,758 +1171,539 @@ const SdSelect = class extends BaseDropdownEvent {
1030
1171
  };
1031
1172
  SdSelect.style = sdSelectCss;
1032
1173
 
1033
- const sdSelectMultipleCss = ".sd-select-multiple__dropdown{overflow-y:auto;overflow-x:hidden;scroll-behavior:smooth}.sd-select-multiple__dropdown::-webkit-scrollbar{opacity:0;background:#e5e5e5}.sd-select-multiple__dropdown::-webkit-scrollbar:horizontal{height:8px}.sd-select-multiple__dropdown::-webkit-scrollbar:vertical{width:8px}.sd-select-multiple__dropdown::-webkit-scrollbar-thumb{height:80px;background-color:#cccccc;border-radius:4px}.sd-select-multiple__dropdown::-webkit-scrollbar-thumb:hover{background:#e5e5e5}.sd-select-multiple__dropdown::-webkit-scrollbar-thumb:active{background:#e5e5e5}.sd-select-multiple__dropdown::-webkit-scrollbar-track{background-color:transparent}:host{display:inline-block;height:fit-content;position:relative}.sd-select-multiple{display:flex;flex-wrap:nowrap;width:var(--select-width, 200px);height:28px;cursor:pointer;user-select:none;border:1px solid #aaaaaa;border-radius:4px;background-color:white}.sd-select-multiple:hover:not(.sd-select-multiple--disabled){background:#f6f6f6}.sd-select-multiple.sd-select-multiple--disabled{cursor:not-allowed;background-color:#eeeeee;border-color:#cccccc}.sd-select-multiple.sd-select-multiple--disabled .sd-select-multiple__label{border-right:1px solid #cccccc}.sd-select-multiple.sd-select-multiple--disabled .sd-select-multiple__trigger{color:#888888}.sd-select-multiple.sd-select-multiple--disabled .sd-select-multiple__trigger:focus,.sd-select-multiple.sd-select-multiple--disabled .sd-select-multiple__trigger:focus-visible,.sd-select-multiple.sd-select-multiple--disabled .sd-select-multiple__trigger:focus-within{outline:none !important}.sd-select-multiple__label{font-size:12px;font-weight:500;color:#333333;padding:4px 12px;border-right:1px solid #cccccc;border-radius:4px 0 0 4px;background-color:#f6f6f6}.sd-select-multiple__container{position:relative;width:100%;display:flex}.sd-select-multiple__container .sd-select-multiple__trigger{padding:4px 20px 4px 12px;display:flex;width:100%;align-items:center}.sd-select-multiple__container .sd-select-multiple__trigger .sd-select-multiple__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:20px;font-size:12px;font-weight:400}.sd-select-multiple__container .sd-select-multiple__trigger .sd-select-multiple__clear{margin:0 4px;width:8px;height:8px;background-color:transparent;outline:none;border:none}.sd-select-multiple__container .sd-select-multiple__arrow{position:absolute;top:8px;right:8px;width:12px;height:12px;color:#888888;transition:transform 0.3s ease}.sd-select-multiple__container .sd-select-multiple__arrow--open{transform:rotate(180deg)}.sd-select-multiple__dropdown{width:var(--select-dropdown-width, 200px);max-height:var(--select-dropdown-height, 260px);padding-bottom:2px;background-color:white;box-shadow:2px 2px 12px 2px rgba(0, 0, 0, 0.1);border-radius:4px;overflow-y:auto;color:#333333}.sd-select-multiple__dropdown .sd-select-multiple__search-container{position:sticky;top:0;display:flex;width:100%;background-color:white;align-items:center;padding:4px 8px;z-index:1}.sd-select-multiple__dropdown .sd-select-multiple__search-container--scrolled{box-shadow:2px 2px 8px 2px rgba(0, 0, 0, 0.2)}.sd-select-multiple__dropdown .sd-select-multiple__option-placeholder{padding:4px 12px;font-size:12px;line-height:20px;text-align:left}";
1174
+ const sdSelectOptionCss = "sd-select-option{display:block;height:fit-content;line-height:0}sd-select-option .sd-select__option{display:flex;padding:4px 12px;font-size:12px;line-height:20px;cursor:pointer}sd-select-option .sd-select__option__checkbox-wrapper{display:flex;width:100%;column-gap:8px;align-items:center;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}sd-select-option .sd-select__option--focused{background-color:#e6f1ff}sd-select-option .sd-select__option--selected:not(:hover):not(.sd-select__option--use-checkbox),sd-select-option .sd-select__option--focused:not(:hover):not(.sd-select__option--use-checkbox){color:#0075ff;font-weight:700}sd-select-option .sd-select__option--disabled{color:#aaaaaa;cursor:not-allowed}sd-select-option .sd-select__option:hover:not(.sd-select__option--disabled){background-color:#0075ff;color:white}";
1034
1175
 
1035
- const SdSelectMultiple = class extends BaseDropdownEvent {
1176
+ const SdSelectOption = class {
1036
1177
  constructor(hostRef) {
1037
- super();
1038
1178
  index.registerInstance(this, hostRef);
1039
- this.sdChange = index.createEvent(this, "sdChange");
1040
- this.dropDownShow = index.createEvent(this, "dropDownShow");
1179
+ this.optionClick = index.createEvent(this, "optionClick");
1041
1180
  }
1042
1181
  get el() { return index.getElement(this); }
1043
- // props
1044
- value = null;
1045
- label = '';
1046
- options = [];
1047
- placeholder = '선택';
1048
- optionPlaceholder = '옵션이 없습니다.';
1049
- width = '200px';
1050
- dropdownHeight = '260px';
1182
+ option;
1183
+ index;
1184
+ isSelected = false;
1185
+ isFocused = false;
1186
+ optionStyle;
1051
1187
  disabled = false;
1052
- clearable = false;
1053
- searchable = false;
1054
1188
  useCheckbox = false;
1055
- // props - custom slots
1056
- optionRenderer;
1057
- // states
1058
- filteredOptions = this.options;
1059
- isOpen = false;
1060
- searchText = null;
1061
- itemIndex = -1;
1062
- isScrolled = false;
1063
- // events
1064
- sdChange;
1065
- dropDownShow;
1066
- selectRef;
1067
- searchRef;
1068
- optionRef;
1069
- dropdownRef;
1070
- valueChanged() {
1071
- this.sdChange?.emit(this.value);
1189
+ isHovered = false;
1190
+ async isDisabled() {
1191
+ return !!this.option.disabled;
1072
1192
  }
1073
- optionsChanged() {
1074
- this.filteredOptions = this.options;
1075
- this.filterOptions();
1193
+ optionClick;
1194
+ handleClick = (event) => {
1195
+ event.stopPropagation();
1196
+ if (!this.option.disabled && !this.disabled) {
1197
+ this.optionClick.emit({
1198
+ option: this.option,
1199
+ index: this.index,
1200
+ event,
1201
+ });
1202
+ }
1203
+ };
1204
+ render() {
1205
+ return (index.h(index.Host, { key: '23d87df53fa083e6c9aceb1956de51800117df9f' }, index.h("div", { key: '569c5d35098350fa4d186ba838925de4f966c491', class: {
1206
+ 'sd-select__option': true,
1207
+ 'sd-select__option--selected': this.isSelected,
1208
+ 'sd-select__option--disabled': !!this.option.disabled,
1209
+ 'sd-select__option--focused': this.isFocused,
1210
+ 'sd-select__option--use-checkbox': this.useCheckbox,
1211
+ }, onMouseEnter: () => (this.isHovered = true), onMouseLeave: () => (this.isHovered = false), style: this.optionStyle, "data-index": this.index, onClick: this.handleClick }, this.useCheckbox ? (index.h("div", { class: "sd-select__option__checkbox-wrapper" }, index.h("sd-checkbox", { checked: this.isSelected, disabled: this.option.disabled,
1212
+ // checkboxStyle={
1213
+ // !this.isSelected
1214
+ // ? { borderColor: '#888' }
1215
+ // : this.isHovered
1216
+ // ? { borderColor: 'white' }
1217
+ // : { borderColor: '#0075ff' }
1218
+ // }
1219
+ onClick: e => {
1220
+ e.preventDefault();
1221
+ this.handleClick(e);
1222
+ } }), index.h("span", { class: "sd-select__option-label" }, this.option.label))) : (this.option.label))));
1076
1223
  }
1077
- searchTextChanged() {
1078
- this.filterOptions();
1224
+ };
1225
+ SdSelectOption.style = sdSelectOptionCss;
1226
+
1227
+ const sdTableCss = ".sd-table__wrapper .sd-table__container .sd-table__middle{overflow-y:auto;overflow-x:hidden;scroll-behavior:smooth}.sd-table__wrapper .sd-table__container .sd-table__middle::-webkit-scrollbar{opacity:0;background:#e5e5e5}.sd-table__wrapper .sd-table__container .sd-table__middle::-webkit-scrollbar:horizontal{height:8px}.sd-table__wrapper .sd-table__container .sd-table__middle::-webkit-scrollbar:vertical{width:8px}.sd-table__wrapper .sd-table__container .sd-table__middle::-webkit-scrollbar-thumb{height:80px;background-color:#cccccc;border-radius:4px}.sd-table__wrapper .sd-table__container .sd-table__middle::-webkit-scrollbar-track{background-color:transparent}.sd-table__wrapper{height:var(--table-height, auto);width:var(--table-width, 100%);color:#222222}.sd-table__wrapper .sd-table__container{width:100%;height:auto;border:1px solid #e1e1e1;border-radius:8px;font-size:12px;overflow:hidden}.sd-table__wrapper .sd-table__container .sd-table__middle{overflow:auto;will-change:scroll-position;height:var(--table-height, auto)}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--selectable td.sd-td--selected,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--selectable th.sd-th--selected{width:52px !important;max-width:52px !important;min-width:52px !important;padding:0 10px 0 24px;text-align:left}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-header thead{position:sticky;top:0;z-index:120}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-column th.sticky-left,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-column th.sticky-right{position:sticky;background-color:#f5faff;z-index:110 !important}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-column td.sticky-left,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-column td.sticky-right{position:sticky;background-color:white;z-index:100 !important}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-column .sticky-left{left:var(--sticky-left-offset, 0)}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-column .sticky-right{right:var(--sticky-right-offset, 0)}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-column th.sticky-cell{position:sticky;z-index:102;background-color:#f5faff}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--sticky-column td.sticky-cell{position:sticky;z-index:101;background-color:white}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--scrolled-left th.sticky-left-edge,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--scrolled-left td.sticky-left-edge{overflow:visible}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--scrolled-left th.sticky-left-edge:after,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--scrolled-left td.sticky-left-edge:after{content:\"\";position:absolute;top:0;left:100%;right:-20px;width:20px;height:100%;z-index:101 !important;box-shadow:inset 12px 0 20px -25px;opacity:1;pointer-events:none}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--scrolled-right th.sticky-right-edge,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--scrolled-right td.sticky-right-edge{overflow:visible}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--scrolled-right th.sticky-right-edge:after,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--scrolled-right td.sticky-right-edge:after{content:\"\";position:absolute;top:0;left:-20px;width:20px;height:100%;z-index:101 !important;box-shadow:inset -12px 0 20px -25px;opacity:1;pointer-events:none}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--no-data thead{opacity:0.4}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table--no-data thead tr th.sd-th{border-bottom:1px solid rgba(225, 225, 225, 0.4) !important}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table td,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table th,.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table .sd-th__content--label{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;word-break:keep-all}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table thead{height:36px}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table thead tr{width:100%}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table thead tr th{background:#f5faff;height:36px;padding:0 16px;font-weight:500;vertical-align:middle;border-bottom:1px solid #e1e1e1;-webkit-user-select:none;user-select:none;position:relative}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table thead tr th.sd-th .sd-th__content{display:flex;flex-flow:row nowrap;align-items:center;gap:4px}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table thead tr th.sd-th .sd-th__content--left{justify-content:flex-start}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table thead tr th.sd-th .sd-th__content--center{justify-content:center}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table thead tr th.sd-th .sd-th__content--right{justify-content:flex-end}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table thead tr th.sd-th .sd-th__resizer{position:absolute;top:50%;right:0;transform:translateY(-50%);width:4px;height:16px;cursor:col-resize;z-index:3;border-left:1px solid #cccccc;border-right:1px solid #cccccc}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table tbody tr:last-of-type td{border-bottom:none}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table tbody tr td{height:44px;padding:0 16px;border-bottom:1px solid #e1e1e1;background:white;vertical-align:middle}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table tbody tr td.sd-td--left{text-align:left}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table tbody tr td.sd-td--center{text-align:center}.sd-table__wrapper .sd-table__container .sd-table__middle .sd-table tbody tr td.sd-td--right{text-align:right}.sd-table__wrapper .sd-table__container .sd-table__bottom{background:white;text-align:center}.sd-table__wrapper .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:8px}.sd-table__wrapper .sd-table__pagination sd-select{position:absolute;right:10px;top:50%;transform:translateY(-50%)}";
1228
+
1229
+ const SdTable = class {
1230
+ constructor(hostRef) {
1231
+ index.registerInstance(this, hostRef);
1232
+ this.sdSelectChange = index.createEvent(this, "sdSelectChange");
1233
+ this.sdPageChange = index.createEvent(this, "sdPageChange");
1079
1234
  }
1080
- async itemIndexChanged(newIndex, oldIndex) {
1081
- if (this.searchable) {
1082
- const searchInput = await this.getNativeInputElement();
1083
- if (this.itemIndex === -1) {
1084
- searchInput?.focus();
1085
- return;
1086
- }
1087
- else if (searchInput?.matches(':focus')) {
1088
- searchInput?.blur();
1089
- }
1090
- }
1091
- const optionElements = Array.from(this.dropdownRef?.querySelectorAll('.sd-select-multiple__dropdown sd-select-option') || []);
1092
- const currentItem = optionElements?.[this.itemIndex];
1093
- if (!currentItem || !this.isOpen)
1235
+ get el() { return index.getElement(this); }
1236
+ columns;
1237
+ rows;
1238
+ selected = new Set();
1239
+ rowKey = 'id';
1240
+ selectable = false;
1241
+ resizable = false;
1242
+ width;
1243
+ height;
1244
+ stickyHeader = false;
1245
+ stickyColumn = { left: 0, right: 0 };
1246
+ noDataLabel = '데이터가 없습니다.';
1247
+ pagination;
1248
+ bodyCellRenderer;
1249
+ useInternalPagination = false;
1250
+ useRowsPerPageSelect = false;
1251
+ rowsPerPageOption = [
1252
+ { label: '10개씩 보기', value: 10 },
1253
+ { label: '25개씩 보기', value: 25 },
1254
+ { label: '50개씩 보기', value: 50 },
1255
+ { label: '100개씩 보기', value: 100 },
1256
+ ];
1257
+ sdSelectChange;
1258
+ sdPageChange;
1259
+ currentPage = this.pagination?.page || 1;
1260
+ innerRows = [];
1261
+ innerSelected = new Set();
1262
+ columnWidths = [];
1263
+ scrolledLeft = false;
1264
+ scrolledRight = false;
1265
+ handleColumnsChange(newCols) {
1266
+ this.columnWidths = newCols.map(c => parseInt(c.width || '120', 10));
1267
+ }
1268
+ handleRowsChange(newRows) {
1269
+ this.innerRows = [...newRows];
1270
+ }
1271
+ handleSelectedChange(newSelected) {
1272
+ this.innerSelected = new Set(newSelected);
1273
+ }
1274
+ handlePaginationChange(newVal) {
1275
+ if (newVal?.page && newVal.page !== this.currentPage)
1276
+ this.currentPage = newVal.page;
1277
+ }
1278
+ componentWillLoad() {
1279
+ this.innerRows = [...(this.rows || [])];
1280
+ this.innerSelected = new Set(this.selected);
1281
+ this.columnWidths = (this.columns || []).map(c => parseInt(c.width || '120', 10));
1282
+ }
1283
+ componentDidLoad() {
1284
+ // SSR 환경 체크
1285
+ if (typeof window === 'undefined')
1094
1286
  return;
1095
- this.optionRef = currentItem;
1096
- const isOptionDisabled = await this.optionRef.isDisabled();
1097
- if (isOptionDisabled) {
1098
- newIndex > oldIndex ? this.itemIndex++ : this.itemIndex--;
1287
+ const middle = this.el.querySelector('.sd-table__middle');
1288
+ if (!middle)
1099
1289
  return;
1100
- }
1101
- this.scrollToOption(currentItem);
1290
+ const onScroll = () => {
1291
+ const { scrollLeft, scrollWidth, clientWidth } = middle;
1292
+ this.scrolledLeft = scrollLeft > 0;
1293
+ this.scrolledRight = scrollLeft + clientWidth < scrollWidth;
1294
+ };
1295
+ middle.addEventListener('scroll', onScroll, { passive: true });
1296
+ onScroll();
1297
+ }
1298
+ // ----- Derived getters -----
1299
+ get visibleColumns() {
1300
+ return this.columns.filter(col => col.visible !== false);
1301
+ }
1302
+ get paginatedRows() {
1303
+ if (!this.pagination || !this.useInternalPagination)
1304
+ return this.innerRows;
1305
+ const { rowsPerPage = this.rows.length } = this.pagination || {};
1306
+ const result = this.innerRows.slice((this.currentPage - 1) * rowsPerPage, this.currentPage * rowsPerPage);
1307
+ return result;
1308
+ }
1309
+ get lastPageNumber() {
1310
+ const { lastPage, rowsPerPage = this.rows.length } = this.pagination || {};
1311
+ return lastPage ?? Math.max(1, Math.ceil(this.rows.length / rowsPerPage));
1312
+ }
1313
+ get sdTableClasses() {
1314
+ return [
1315
+ 'sd-table',
1316
+ this.stickyHeader && 'sd-table--sticky-header',
1317
+ this.selectable && 'sd-table--selectable',
1318
+ this.resizable && 'sd-table--resizable',
1319
+ !this.innerRows.length && 'sd-table--no-data',
1320
+ ((this.stickyColumn?.left ?? 0) > 0 || (this.stickyColumn?.right ?? 0) > 0) &&
1321
+ 'sd-table--sticky-column',
1322
+ this.scrolledLeft && 'sd-table--scrolled-left',
1323
+ this.scrolledRight && 'sd-table--scrolled-right',
1324
+ ]
1325
+ .filter(Boolean)
1326
+ .join(' ');
1327
+ }
1328
+ // ----- Selection -----
1329
+ isRowSelected(row) {
1330
+ return Array.from(this.innerSelected).some(r => r[this.rowKey] === row[this.rowKey]);
1331
+ }
1332
+ updateRowSelect(row) {
1333
+ const selectedArray = Array.from(this.innerSelected);
1334
+ const exists = this.isRowSelected(row);
1335
+ const newSelected = exists
1336
+ ? selectedArray.filter(r => r[this.rowKey] !== row[this.rowKey])
1337
+ : [...selectedArray, row];
1338
+ // 동일 상태면 set하지 않음 → 불필요 렌더 방지
1339
+ if (newSelected.length === selectedArray.length)
1340
+ return;
1341
+ this.innerSelected = new Set(newSelected);
1342
+ this.sdSelectChange.emit(Array.from(this.innerSelected));
1102
1343
  }
1103
- async isOpenChanged() {
1104
- // Base class의 이벤트 관리 호출 - 다른 select와의 이벤트 충돌 방지
1105
- this.onDropdownToggle(this.isOpen);
1106
- const selectedOption = this.getSelectedOption();
1107
- if (!selectedOption) {
1108
- this.itemIndex = -1;
1344
+ toggleSelectAll(checked) {
1345
+ if (checked) {
1346
+ const pageRows = new Set([...this.paginatedRows]);
1347
+ this.innerSelected = new Set([...this.innerSelected, ...pageRows]);
1109
1348
  }
1110
1349
  else {
1111
- this.itemIndex = this.options.indexOf(selectedOption[0]);
1112
- }
1113
- this.dropDownShow?.emit({ isOpen: this.isOpen });
1114
- if (this.isOpen === false)
1115
- return;
1116
- await new Promise(resolve => setTimeout(resolve, 10));
1117
- const optionElements = Array.from(this.dropdownRef?.querySelectorAll('.sd-select-multiple__dropdown sd-select-item') || []);
1118
- const currentItem = optionElements?.[this.itemIndex];
1119
- // 드롭다운이 열릴 때 검색 입력에 포커스
1120
- if (this.searchable) {
1121
- const searchInput = await this.getNativeInputElement();
1122
- searchInput?.focus();
1123
- }
1124
- if (!currentItem)
1125
- return;
1126
- await new Promise(resolve => setTimeout(resolve, 10)); // 추가 딜레이
1127
- this.scrollToOption(currentItem);
1350
+ const currentPageKeys = this.paginatedRows.map(r => r[this.rowKey]);
1351
+ this.innerSelected = new Set([...this.innerSelected].filter(r => !currentPageKeys.includes(r[this.rowKey])));
1352
+ }
1353
+ this.sdSelectChange.emit(Array.from(this.innerSelected));
1354
+ }
1355
+ get isAllChecked() {
1356
+ const total = this.paginatedRows.length;
1357
+ const selectedCount = this.paginatedRows.filter(row => Array.from(this.innerSelected).some(selectedRow => selectedRow[this.rowKey] === row[this.rowKey])).length;
1358
+ if (selectedCount === 0)
1359
+ return false; // 아무것도 안 선택됨
1360
+ if (selectedCount === total)
1361
+ return true; // 전부 선택됨
1362
+ return null; // 일부만 선택됨
1363
+ }
1364
+ // ----- Helpers -----
1365
+ getStickyStyle(colIdx) {
1366
+ const leftOffset = this.columnWidths.slice(0, colIdx).reduce((a, b) => a + b, 0) + (this.selectable ? 52 : 0);
1367
+ const rightOffset = this.columnWidths
1368
+ .filter((_, i) => i >= this.visibleColumns.length - (this.stickyColumn.right || 0) && i > colIdx)
1369
+ .reduce((a, b) => a + b, 0);
1370
+ return {
1371
+ '--sticky-left-offset': `${leftOffset}px`,
1372
+ '--sticky-right-offset': `${rightOffset}px`,
1373
+ 'width': `${this.columnWidths[colIdx]}px`,
1374
+ 'minWidth': `${this.columnWidths[colIdx]}px`,
1375
+ 'maxWidth': `${this.columnWidths[colIdx]}px`,
1376
+ };
1128
1377
  }
1129
- connectedCallback() {
1130
- // props가 모두 설정된 후에 실행되므로 올바른 options 값을 가져올 수 있음
1131
- this.filteredOptions = this.options;
1132
- this.initializeEvent(); // global dropdown Manager에 등록 + 이벤트 핸들러 초기화
1378
+ handleResize(index, event) {
1379
+ // SSR 환경 체크
1380
+ if (typeof document === 'undefined')
1381
+ return;
1382
+ const startX = event.clientX;
1383
+ const startWidth = this.columnWidths[index];
1384
+ const handleMouseMove = (moveEvent) => {
1385
+ const newWidth = Math.max(startWidth + moveEvent.clientX - startX, 50);
1386
+ this.columnWidths = this.columnWidths.map((width, idx) => (idx === index ? newWidth : width));
1387
+ };
1388
+ const handleMouseUp = () => {
1389
+ document.removeEventListener('mousemove', handleMouseMove);
1390
+ document.removeEventListener('mouseup', handleMouseUp);
1391
+ };
1392
+ document.addEventListener('mousemove', handleMouseMove);
1393
+ document.addEventListener('mouseup', handleMouseUp);
1394
+ }
1395
+ getCellValue(column, row) {
1396
+ const { field, format, name } = column;
1397
+ const value = typeof field === 'function' ? field(row) : field ? row[field] : row[name];
1398
+ return format ? format(value, row) : value;
1399
+ }
1400
+ // ----- Render -----
1401
+ renderHeader() {
1402
+ return (index.h("thead", null, index.h("tr", null, this.selectable && (index.h("th", { class: {
1403
+ 'sd-th': true,
1404
+ 'sd-th--selected': true,
1405
+ 'sticky-left': Boolean(this.stickyColumn.left && this.stickyColumn.left > 0),
1406
+ }, style: {
1407
+ '--sticky-left-offset': '0px',
1408
+ } }, index.h("sd-checkbox", { checked: this.isAllChecked, disabled: !this.paginatedRows.length, onSdChange: (e) => this.toggleSelectAll(e.detail) }))), this.visibleColumns.map((col, colIdx) => (index.h("th", { key: col.name, class: {
1409
+ 'sd-th': true,
1410
+ [`${col.thClass}`]: Boolean(col.thClass),
1411
+ 'sticky-left': Boolean(this.stickyColumn.left && colIdx < this.stickyColumn.left),
1412
+ 'sticky-right': Boolean(this.stickyColumn.right && colIdx >= this.visibleColumns.length - this.stickyColumn.right),
1413
+ 'sticky-left-edge': Boolean(this.stickyColumn.left && colIdx === this.stickyColumn.left - 1),
1414
+ 'sticky-right-edge': Boolean(this.stickyColumn.right &&
1415
+ colIdx === this.visibleColumns.length - this.stickyColumn.right),
1416
+ }, style: this.getStickyStyle(colIdx) }, index.h("div", { class: `sd-th__content sd-th__content--${col.align || 'left'}` }, index.h("slot", { name: `header-cell-${col.name}` }, index.h("div", { class: "sd-th__content--label" }, col.label)), col.usePageMoveIcon && index.h("sd-icon", { name: "pageMove", size: "12", color: "#006AC1" }), col.tooltip && (index.h("sd-tooltip", { ...col.tooltipOptions }, index.h("div", { slot: "content" }, col.tooltip.map(text => (index.h("p", null, text))))))), this.resizable && typeof window !== 'undefined' && (index.h("div", { class: "sd-th__resizer", onMouseDown: (evt) => this.handleResize(colIdx, evt) }))))))));
1417
+ }
1418
+ renderBody() {
1419
+ if (!this.paginatedRows.length)
1420
+ return (index.h("tbody", { part: "tbody-empty" }, index.h("tr", null, index.h("td", { colSpan: this.visibleColumns.length + (this.selectable ? 1 : 0) }, this.noDataLabel))));
1421
+ return (index.h("tbody", null, this.paginatedRows.map((row, rowIdx) => (index.h("tr", { key: row[this.rowKey], class: "hover:bg-Grey_Lighten-6" }, this.selectable && (index.h("td", { class: {
1422
+ 'sd-td': true,
1423
+ 'sd-td--selected': true,
1424
+ 'sticky-left': Boolean(this.stickyColumn.left && this.stickyColumn.left > 0),
1425
+ }, style: {
1426
+ '--sticky-left-offset': '0px',
1427
+ } }, index.h("sd-checkbox", { checked: this.isRowSelected(row), disabled: !this.paginatedRows.length, onSdChange: () => this.updateRowSelect(row) }))), this.visibleColumns.map((column, colIdx) => {
1428
+ const rendered = this.bodyCellRenderer?.(column, row);
1429
+ return (index.h("td", { key: column.name, part: `td-${column.name}`, class: {
1430
+ 'sd-td': true,
1431
+ [`sd-td--${column.align || 'left'}`]: true,
1432
+ 'sticky-left': Boolean(this.stickyColumn.left && colIdx < this.stickyColumn.left),
1433
+ 'sticky-right': Boolean(this.stickyColumn.right &&
1434
+ colIdx >= this.visibleColumns.length - this.stickyColumn.right),
1435
+ 'sticky-left-edge': Boolean(this.stickyColumn.left && colIdx === this.stickyColumn.left - 1),
1436
+ 'sticky-right-edge': Boolean(this.stickyColumn.right &&
1437
+ colIdx === this.visibleColumns.length - this.stickyColumn.right),
1438
+ [`${column.tdClass}`]: Boolean(column.tdClass),
1439
+ }, style: this.getStickyStyle(colIdx) }, index.h("slot", { name: `body-cell-${column.name}-${rowIdx}` }, rendered ? (typeof rendered === 'string' ? (index.h("span", { innerHTML: rendered })) : (rendered)) : (this.getCellValue(column, row)))));
1440
+ }))))));
1133
1441
  }
1134
- disconnectedCallback() {
1135
- this.cleanupEvent(); // global dropdown Manager에서 제거 + 이벤트 정리
1136
- }
1137
- handleDocumentClick(event) {
1138
- if (!this.selectRef?.contains(event.target)) {
1139
- this.isOpen = false;
1140
- }
1141
- }
1142
- handleDocumentKeydown(keyboardEvent) {
1143
- keyboardEvent.stopPropagation();
1144
- const targetKey = ['ArrowDown', 'ArrowUp', 'Enter', 'Escape'];
1145
- if (!targetKey.includes(keyboardEvent.key))
1146
- return;
1147
- keyboardEvent.preventDefault();
1148
- switch (keyboardEvent.key) {
1149
- case 'ArrowDown':
1150
- case 'ArrowUp':
1151
- const keyboardNavigation = new SelectKeyboardNavigation(this.searchable, this.filteredOptions);
1152
- const nextIndex = keyboardNavigation.getNextIndex(this.itemIndex, keyboardEvent.key);
1153
- this.itemIndex = nextIndex;
1154
- break;
1155
- case 'Enter':
1156
- const selectedOption = this.filteredOptions[this.itemIndex];
1157
- if (selectedOption && !selectedOption.disabled) {
1158
- this.handleOptionSelection(selectedOption);
1159
- }
1160
- break;
1161
- case 'Escape':
1162
- this.isOpen = false;
1163
- break;
1164
- }
1165
- }
1166
- // event handlers
1167
- handleTriggerClick = (event) => {
1168
- event.stopPropagation();
1169
- if (!this.disabled) {
1170
- this.isOpen = !this.isOpen;
1171
- this.dropDownShow?.emit({ isOpen: this.isOpen });
1172
- }
1173
- };
1174
- handleOptionClick = (detail) => {
1175
- const { option, event } = detail;
1176
- event.stopPropagation();
1177
- this.handleOptionSelection(option);
1178
- };
1179
- filterOptions() {
1180
- if (!this.searchText || this.searchText.trim() === '') {
1181
- // 검색어가 없으면 전체 옵션 표시
1182
- this.filteredOptions = this.options;
1183
- }
1184
- else {
1185
- // 검색어가 있으면 필터링
1186
- this.filteredOptions = this.options.filter(option => option.label.toLowerCase().includes(this.searchText.toLowerCase()));
1187
- }
1188
- }
1189
- getSelectedOption() {
1190
- return this.options.filter(option => this.value?.includes(option));
1191
- }
1192
- handleDropdownScroll = (event) => {
1193
- const target = event.target;
1194
- const scrollTop = target.scrollTop;
1195
- // 스크롤이 조금이라도 되면 그림자 표시
1196
- this.isScrolled = scrollTop > 0;
1197
- };
1198
- async getNativeInputElement() {
1199
- if (this.searchRef) {
1200
- return this.searchRef.getNativeElement();
1201
- }
1202
- return null;
1203
- }
1204
- handleOptionSelection = (option) => {
1205
- if (!option || option.disabled)
1206
- return;
1207
- const isAlreadySelected = this.value?.some(opt => opt.value === option.value);
1208
- if (isAlreadySelected) {
1209
- // 이미 선택된 옵션인 경우, 선택 해제
1210
- this.value = this.value?.filter(opt => opt.value !== option.value) || null;
1211
- }
1212
- else {
1213
- // 새로운 옵션 선택
1214
- this.value = [...(this.value || []), option];
1215
- }
1216
- };
1217
- closeDropdown() {
1218
- this.isOpen = false;
1219
- }
1220
- scrollToOption(optionElement) {
1221
- if (!this.dropdownRef || !optionElement)
1222
- return;
1223
- const dropdown = this.dropdownRef;
1224
- const optionTop = optionElement.offsetTop;
1225
- const optionHeight = optionElement.offsetHeight;
1226
- const dropdownScrollTop = dropdown.scrollTop;
1227
- const dropdownHeight = dropdown.clientHeight;
1228
- const searchContainer = dropdown.querySelector('.sd-select__search-container');
1229
- const searchOffset = searchContainer ? searchContainer.offsetHeight : 0;
1230
- const visibleTop = dropdownScrollTop + searchOffset;
1231
- const visibleBottom = dropdownScrollTop + dropdownHeight;
1232
- if (optionTop < visibleTop) {
1233
- dropdown.scrollTop = optionTop - searchOffset;
1234
- }
1235
- else if (optionTop + optionHeight > visibleBottom) {
1236
- dropdown.scrollTop = optionTop + optionHeight - dropdownHeight + searchOffset;
1237
- }
1238
- }
1239
- // render method
1240
- render() {
1241
- const style = {
1242
- '--select-width': this.width || '200px',
1243
- '--select-dropdown-height': this.dropdownHeight || '260px',
1244
- };
1245
- return (index.h(index.Host, { key: '7f8cd5ee5ccf46bf023b02439d1cc1dd331a2d03', style: style }, index.h("div", { key: 'c8789241b7ae42119b94c25740d314745b6b3b0b', class: {
1246
- 'sd-select-multiple': true,
1247
- 'sd-select-multiple--open': this.isOpen,
1248
- 'sd-select-multiple--disabled': this.disabled,
1249
- }, ref: el => (this.selectRef = el) }, this.renderLabel(this.label), index.h("div", { key: 'cf57263149b3cfbeada5699a66b11fbc237965c7', class: "sd-select-multiple__container" }, this.renderTrigger(), this.renderDropdown()))));
1250
- }
1251
- renderLabel(label) {
1252
- if (!label)
1253
- return null;
1254
- return index.h("label", { class: "sd-select-multiple__label" }, label);
1255
- }
1256
- renderTrigger() {
1257
- const selectedOption = this.getSelectedOption();
1258
- return (index.h("div", { class: "sd-select-multiple__trigger", tabindex: this.disabled ? -1 : 0, onClick: this.handleTriggerClick }, index.h("span", { class: "sd-select-multiple__value" }, !selectedOption
1259
- ? '선택'
1260
- : selectedOption.length
1261
- ? selectedOption.map(option => option.label).join(', ')
1262
- : this.placeholder), this.clearable && selectedOption?.length > 0 && !this.disabled && (index.h("sd-icon", { key: "close-icon", name: "close", size: 10, color: "#888", class: "sd-select-multiple__clear", onClick: event => {
1263
- event.stopPropagation();
1264
- this.value = null;
1265
- } })), index.h("sd-icon", { key: "arrow-icon", name: "arrowDown", color: "#888", class: { 'sd-select-multiple__arrow': true, 'sd-select-multiple__arrow--open': this.isOpen } })));
1266
- }
1267
- renderDropdown() {
1268
- if (this.isOpen === false)
1269
- return null;
1270
- return (index.h("sd-portal", { open: this.isOpen, parentRef: this.selectRef, onSdClose: this.closeDropdown }, index.h("div", { class: "sd-select-multiple__dropdown", onScroll: this.handleDropdownScroll, ref: el => (this.dropdownRef = el) }, this.searchable && (index.h("div", { class: {
1271
- 'sd-select-multiple__search-container': true,
1272
- 'sd-select-multiple__search-container--scrolled': this.isScrolled,
1273
- }, onClick: event => event.stopPropagation() }, index.h("sd-input", { ref: el => (this.searchRef = el), value: this.searchText, placeholder: "\uAC80\uC0C9", clearable: true, inputStyle: { 'padding-left': '8px' }, autofocus: true, onSdInput: event => {
1274
- this.searchText = String(event?.detail);
1275
- }, onSdFocus: () => {
1276
- this.itemIndex = -1;
1277
- } }, index.h("sd-icon", { name: "search", size: 16, color: "#737373", style: { marginRight: '4px' }, slot: "prefix" })))), this.filteredOptions.length > 0 ? (this.filteredOptions.map((option, index$1) => (index.h("slot", { name: `option-${option.value}` }, index.h("sd-select-option", { option: option, index: index$1, isSelected: this.value?.some(selected => selected.value === option.value), isFocused: index$1 === this.itemIndex, onOptionClick: ({ detail }) => this.handleOptionClick(detail), useCheckbox: this.useCheckbox }))))) : (index.h("slot", { name: "option-placeholder" }, index.h("div", { class: 'sd-select-multiple__option-placeholder' }, this.optionPlaceholder))))));
1442
+ render() {
1443
+ return (index.h(index.Host, { key: 'b73fefde2c99c864002a2e778b02a306d4c8c32d' }, index.h("div", { key: '4fbf588871e3b8cb92e087cbde59aa9280ba75cd', class: "sd-table__wrapper", style: {
1444
+ '--table-width': this.width,
1445
+ '--table-height': this.height,
1446
+ } }, index.h("div", { key: '92d69eaf8e499fd5b3a0ebb3d77353c8285949e5', class: "sd-table__container" }, index.h("div", { key: '590fd93058983bab3bc829e7c6ce4e058365287f', class: "sd-table__middle" }, index.h("table", { key: 'c1fd46586bd9429377dfff9df94550cb5437b05a', part: "table", class: this.sdTableClasses }, this.renderHeader(), this.renderBody())), index.h("div", { key: '89a48072c9f6b84d062e4e127b5858657003fc87', class: "sd-table__bottom" })), this.pagination && this.innerRows.length > 0 && (index.h("div", { key: '526c024bc5493b8a3abb4f7887ec221e38dd2937', class: "sd-table__pagination" }, index.h("sd-pagination", { key: 'f607579ff98e70f2c6975139a17c7fc48b940a19', currentPage: !this.useInternalPagination ? this.pagination.page : this.currentPage, lastPage: !this.useInternalPagination ? this.pagination.lastPage : this.lastPageNumber, onPageChange: (e) => {
1447
+ if (!this.useInternalPagination) {
1448
+ this.sdPageChange.emit(e.detail);
1449
+ }
1450
+ else {
1451
+ this.currentPage = e.detail;
1452
+ this.sdPageChange.emit(this.currentPage);
1453
+ }
1454
+ } }), this.useRowsPerPageSelect && (index.h("sd-select", { key: '683424acaf3961dcf681e8a04275cdba6bdf9928', value: this.pagination.rowsPerPage, options: this.rowsPerPageOption, width: "128px", onSdChange: (e) => {
1455
+ const newRowsPerPage = Number(e.detail.value || 0);
1456
+ let newLastPage = Math.max(1, Math.ceil(this.innerRows.length / newRowsPerPage));
1457
+ let newCurrentPage = this.currentPage;
1458
+ if (newCurrentPage > newLastPage) {
1459
+ newCurrentPage = newLastPage;
1460
+ }
1461
+ this.pagination = {
1462
+ page: newCurrentPage,
1463
+ rowsPerPage: newRowsPerPage,
1464
+ lastPage: newLastPage,
1465
+ };
1466
+ this.currentPage = newCurrentPage;
1467
+ this.sdPageChange.emit(this.currentPage);
1468
+ } })))))));
1278
1469
  }
1279
1470
  static get watchers() { return {
1280
- "value": ["valueChanged"],
1281
- "options": ["optionsChanged"],
1282
- "searchText": ["searchTextChanged"],
1283
- "itemIndex": ["itemIndexChanged"],
1284
- "isOpen": ["isOpenChanged"]
1471
+ "columns": ["handleColumnsChange"],
1472
+ "rows": ["handleRowsChange"],
1473
+ "selected": ["handleSelectedChange"],
1474
+ "pagination": ["handlePaginationChange"]
1285
1475
  }; }
1286
1476
  };
1287
- SdSelectMultiple.style = sdSelectMultipleCss;
1477
+ SdTable.style = sdTableCss;
1288
1478
 
1289
- const sdSelectMultipleGroupCss = ".sd-select-multiple-group__dropdown{overflow-y:auto;overflow-x:hidden;scroll-behavior:smooth}.sd-select-multiple-group__dropdown::-webkit-scrollbar{opacity:0;background:#e5e5e5}.sd-select-multiple-group__dropdown::-webkit-scrollbar:horizontal{height:8px}.sd-select-multiple-group__dropdown::-webkit-scrollbar:vertical{width:8px}.sd-select-multiple-group__dropdown::-webkit-scrollbar-thumb{height:80px;background-color:#cccccc;border-radius:4px}.sd-select-multiple-group__dropdown::-webkit-scrollbar-thumb:hover{background:#e5e5e5}.sd-select-multiple-group__dropdown::-webkit-scrollbar-thumb:active{background:#e5e5e5}.sd-select-multiple-group__dropdown::-webkit-scrollbar-track{background-color:transparent}sd-select-multiple-group{display:inline-block;height:fit-content}sd-select-multiple-group .sd-select-multiple-group{display:flex;flex-wrap:nowrap;width:var(--select-width, 200px);cursor:pointer;user-select:none;border:1px solid #aaaaaa;border-radius:4px;background-color:white;color:#333333}sd-select-multiple-group .sd-select-multiple-group:hover:not(.sd-select-multiple-group--disabled){background:#f6f6f6}sd-select-multiple-group .sd-select-multiple-group.sd-select-multiple-group--disabled{cursor:not-allowed;background-color:#eeeeee;border-color:#cccccc}sd-select-multiple-group .sd-select-multiple-group.sd-select-multiple-group--disabled .sd-select-multiple-group__label{border-right:1px solid #cccccc}sd-select-multiple-group .sd-select-multiple-group.sd-select-multiple-group--disabled .sd-select-multiple-group__trigger{color:#888888}sd-select-multiple-group .sd-select-multiple-group.sd-select-multiple-group--disabled .sd-select-multiple-group__trigger:focus,sd-select-multiple-group .sd-select-multiple-group.sd-select-multiple-group--disabled .sd-select-multiple-group__trigger:focus-visible,sd-select-multiple-group .sd-select-multiple-group.sd-select-multiple-group--disabled .sd-select-multiple-group__trigger:focus-within{outline:none !important}sd-select-multiple-group .sd-select-multiple-group__label{font-size:12px;font-weight:500;color:#333333;padding:4px 12px;border-right:1px solid #cccccc;border-radius:4px 0 0 4px;background-color:#f6f6f6}sd-select-multiple-group .sd-select-multiple-group__container{position:relative;width:100%;display:flex}sd-select-multiple-group .sd-select-multiple-group__container .sd-select-multiple-group__trigger{padding:4px 20px 4px 12px;display:flex;width:100%;align-items:center}sd-select-multiple-group .sd-select-multiple-group__container .sd-select-multiple-group__trigger .sd-select-multiple-group__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:20px;font-size:12px;font-weight:400}sd-select-multiple-group .sd-select-multiple-group__container .sd-select-multiple-group__trigger .sd-select-multiple-group__clear{margin:0 4px;width:8px;height:8px;background-color:transparent;outline:none;border:none}sd-select-multiple-group .sd-select-multiple-group__container .sd-select-multiple-group__arrow{position:absolute;top:8px;right:8px;width:12px;height:12px;color:#888888;transition:transform 0.3s ease}sd-select-multiple-group .sd-select-multiple-group__container .sd-select-multiple-group__arrow--open{transform:rotate(180deg)}.sd-select-multiple-group__dropdown{width:var(--select-width, 200px);max-height:var(--select-dropdown-height, 260px);padding-bottom:2px;background-color:white;box-shadow:2px 2px 12px 2px rgba(0, 0, 0, 0.1);border-radius:4px;overflow-y:auto;color:#333333}.sd-select-multiple-group__dropdown .sd-select-multiple-group__search-container{position:sticky;top:0;display:flex;width:100%;background-color:white;align-items:center;padding:4px 8px}.sd-select-multiple-group__dropdown .sd-select-multiple-group__search-container sd-input{width:100%}.sd-select-multiple-group__dropdown .sd-select-multiple-group__search-container--scrolled{box-shadow:2px 2px 8px 2px rgba(0, 0, 0, 0.2)}.sd-select-multiple-group__dropdown .sd-select-multiple-group__option-placeholder{padding:4px 12px;font-size:12px;line-height:20px}";
1479
+ const sdTooltipCss = ".sd-tooltip{position:relative;cursor:pointer;display:inline-block}";
1290
1480
 
1291
- const SdSelectMultipleGroup = class extends BaseDropdownEvent {
1481
+ const SdTooltip = class {
1292
1482
  constructor(hostRef) {
1293
- super();
1294
1483
  index.registerInstance(this, hostRef);
1295
- this.sdChange = index.createEvent(this, "sdChange");
1296
- this.dropDownShow = index.createEvent(this, "dropDownShow");
1297
1484
  }
1298
1485
  get el() { return index.getElement(this); }
1299
- // props
1300
- value = null;
1486
+ trigger = 'hover';
1487
+ placement = 'top';
1488
+ color = '#01BB4B';
1489
+ type = 'default';
1490
+ icon = 'helpOutline';
1491
+ iconSize = 12;
1301
1492
  label = '';
1302
- options = [];
1303
- placeholder = '선택';
1304
- optionPlaceholder = '옵션이 없습니다.';
1305
- width = '200px';
1306
- dropdownHeight = '260px';
1307
- disabled = false;
1308
- clearable = false;
1309
- searchable = false;
1310
- useCheckbox = false;
1311
- // props - custom styles
1312
- containerStyle = {};
1313
- triggerStyle = {};
1314
- dropdownStyle = {};
1315
- optionStyle = {};
1316
- labelStyle = {};
1317
- // props - custom slots
1318
- optionRenderer;
1319
- // states
1320
- filteredOptions = this.options;
1321
- isOpen = false;
1322
- searchText = null;
1323
- itemIndex = -1;
1324
- isScrolled = false;
1325
- // events
1326
- sdChange;
1327
- dropDownShow;
1328
- selectRef;
1329
- searchRef;
1330
- optionRef;
1331
- dropdownRef;
1332
- valueChanged() {
1333
- this.sdChange?.emit(this.value);
1493
+ buttonSize = 'sm';
1494
+ buttonVariant = 'primary';
1495
+ noHover = true;
1496
+ useClose = false;
1497
+ showTooltip = false;
1498
+ slotContent = null;
1499
+ static COLOR_OF_TYPE = {
1500
+ default: { background: 'oceanblue_85', text: 'white' },
1501
+ caution: { background: 'red_20', text: 'red_70' },
1502
+ notice: { background: 'orange_10', text: 'orange_65' },
1503
+ accent: { background: 'brilliantblue_20', text: 'brilliantblue_75' },
1504
+ };
1505
+ buttonEl;
1506
+ handleClose = () => {
1507
+ this.showTooltip = false;
1508
+ };
1509
+ // 현재 tooltip popover가 조건부 렌더링이여서 초기 slot이 렌더링 되지 않은 시점에
1510
+ // 데이터 매핑에 실패 (light dom에 저장된 slot내용을 shadow dom을 찾지못해 매핑 실패)
1511
+ // 따라서 slot내용을 받은 후에 복제하여 state에 저장
1512
+ componentWillLoad() {
1513
+ const contentEl = this.el.querySelector('[slot="content"]');
1514
+ if (contentEl) {
1515
+ this.slotContent = contentEl.cloneNode(true);
1516
+ }
1334
1517
  }
1335
- optionsChanged() {
1336
- this.filteredOptions = this.options;
1337
- this.filterOptions();
1518
+ render() {
1519
+ const handleTrigger = this.trigger === 'hover'
1520
+ ? {
1521
+ onMouseEnter: () => (this.showTooltip = true),
1522
+ onMouseLeave: () => (this.showTooltip = false),
1523
+ }
1524
+ : {
1525
+ onClick: () => (this.showTooltip = !this.showTooltip),
1526
+ };
1527
+ return (index.h(index.Fragment, { key: '7d527b3422496e0bfa729f2ca983a11ef998eb26' }, this.label ? (index.h("sd-button", { ref: el => (this.buttonEl = el), label: this.label, icon: this.icon, size: this.buttonSize, color: this.color, variant: this.buttonVariant, class: "sd-tooltip", ...handleTrigger })) : (index.h("sd-icon", { ref: el => (this.buttonEl = el), name: this.icon, size: this.iconSize, color: this.color, class: "sd-tooltip", ...handleTrigger })), this.showTooltip && (index.h("sd-tooltip-portal", { key: 'b07ccad73334de2c9780b810dc3f8a5f214aee9a', parentRef: this.buttonEl, onSdClose: () => this.handleClose(), placement: this.placement }, index.h("div", { key: 'e97fe4a6135e3373b5f989c1cde95a222437c355', class: {
1528
+ 'sd-tooltip-menu': true,
1529
+ [`sd-tooltip-menu--${this.type}`]: true,
1530
+ [`sd-tooltip-menu--${this.placement}`]: true,
1531
+ 'sd-tooltip-menu--with-close': this.useClose,
1532
+ [`bg-${SdTooltip.COLOR_OF_TYPE[this.type].background}`]: true,
1533
+ [`text-${SdTooltip.COLOR_OF_TYPE[this.type].text}`]: true,
1534
+ } }, index.h("i", { key: '3ffa50df1b15c24670ce1c6199093b451df9ad93', class: `sd-tooltip-menu__arrow sd-tooltip-menu__arrow--${this.placement}` }, index.h(tooltipArrow.TooltipArrow, { key: 'fe1eb76008e4575b2d640f7e1269041e5e67e113', class: {
1535
+ [`text-${SdTooltip.COLOR_OF_TYPE[this.type].background}`]: true,
1536
+ } })), index.h("div", { key: 'e2dd1a1f895f114a393b44ee67518d2af74db891', class: "sd-tooltip-menu__content", ref: el => {
1537
+ if (el && this.slotContent && !el.hasChildNodes()) {
1538
+ el.appendChild(this.slotContent.cloneNode(true));
1539
+ }
1540
+ } }, !this.slotContent && index.h("span", { key: '0e45a93818843314bb407f95bced59249c7adbc1' }, this.el.textContent)), this.useClose && (index.h("div", { key: 'd55fad487b1a25c02acf95f8bb672001b68bc923', class: "sd-tooltip-menu__close-button" }, index.h("button", { key: 'bec4556571948b6ece4bb61ea3314c4a859feb4d', type: "button", "aria-label": "Close tooltip", title: "Close tooltip", onClick: () => this.handleClose() }, index.h("sd-icon", { key: '0e916c99996d6032f90f888151abcfec1fd85091', name: "close", size: "12", color: "#AAAAAA" })))))))));
1338
1541
  }
1339
- searchTextChanged() {
1340
- this.filterOptions();
1542
+ };
1543
+ SdTooltip.style = sdTooltipCss;
1544
+
1545
+ const SdTooltipPortal = class {
1546
+ constructor(hostRef) {
1547
+ index.registerInstance(this, hostRef);
1548
+ this.sdClose = index.createEvent(this, "sdClose");
1341
1549
  }
1342
- async itemIndexChanged(newIndex, oldIndex) {
1343
- if (this.searchable) {
1344
- const searchInput = await this.getNativeInputElement();
1345
- if (this.itemIndex === -1) {
1346
- searchInput?.focus();
1347
- return;
1348
- }
1349
- else if (searchInput?.matches(':focus')) {
1350
- searchInput?.blur();
1550
+ get el() { return index.getElement(this); }
1551
+ to = 'body';
1552
+ parentRef = null;
1553
+ offset = [0, 0];
1554
+ zIndex = 9999;
1555
+ placement = 'bottom';
1556
+ open = false;
1557
+ sdClose;
1558
+ container;
1559
+ wrapper;
1560
+ rafId;
1561
+ isInsideClick = false;
1562
+ resizeObserver;
1563
+ mutationObserver;
1564
+ static ARROW_SIZE = 11.2;
1565
+ componentDidLoad() {
1566
+ this.container = this.resolveContainer();
1567
+ this.createWrapper();
1568
+ this.moveSlotContent();
1569
+ // DOM이 완전히 렌더링된 후 위치 계산
1570
+ requestAnimationFrame(() => {
1571
+ this.updatePosition();
1572
+ if (this.wrapper) {
1573
+ this.wrapper.style.visibility = 'visible'; // 위치 계산 후 표시
1351
1574
  }
1352
- }
1353
- const optionElements = Array.from(this.dropdownRef?.querySelectorAll('.sd-select-multiple-group__dropdown sd-select-option-group') || []);
1354
- const currentItem = optionElements?.[this.itemIndex];
1355
- if (!currentItem || !this.isOpen)
1356
- return;
1357
- this.optionRef = currentItem;
1358
- const isOptionDisabled = await this.optionRef.isDisabled();
1359
- if (isOptionDisabled) {
1360
- newIndex > oldIndex ? this.itemIndex++ : this.itemIndex--;
1361
- return;
1362
- }
1363
- this.scrollToOption(currentItem);
1575
+ });
1576
+ this.observeParent();
1364
1577
  }
1365
- async isOpenChanged() {
1366
- // Base class의 이벤트 관리 호출 - 다른 select와의 이벤트 충돌 방지
1367
- this.onDropdownToggle(this.isOpen);
1368
- const selectedOption = this.getSelectedOption();
1369
- if (!selectedOption) {
1370
- this.itemIndex = -1;
1578
+ componentDidRender() {
1579
+ if (!this.wrapper)
1580
+ return;
1581
+ // this.wrapper.style.display = this.open ? 'block' : 'none';
1582
+ // if (this.open) this.updatePosition();
1583
+ if (this.open) {
1584
+ this.wrapper.style.display = 'block';
1585
+ // RAF를 사용해서 다음 프레임에 위치 업데이트
1586
+ requestAnimationFrame(() => {
1587
+ this.updatePosition();
1588
+ if (this.wrapper) {
1589
+ this.wrapper.style.visibility = 'visible';
1590
+ }
1591
+ });
1371
1592
  }
1372
1593
  else {
1373
- this.itemIndex = this.options.indexOf(selectedOption[0]);
1374
- }
1375
- this.dropDownShow?.emit({ isOpen: this.isOpen });
1376
- if (this.isOpen === false)
1377
- return;
1378
- await new Promise(resolve => setTimeout(resolve, 10));
1379
- const optionElements = Array.from(this.dropdownRef?.querySelectorAll('.sd-select-multiple__dropdown sd-select-item') || []);
1380
- const currentItem = optionElements?.[this.itemIndex];
1381
- // 드롭다운이 열릴 때 검색 입력에 포커스
1382
- if (this.searchable) {
1383
- const searchInput = await this.getNativeInputElement();
1384
- searchInput?.focus();
1594
+ this.wrapper.style.display = 'none';
1595
+ this.wrapper.style.visibility = 'hidden';
1385
1596
  }
1386
- if (!currentItem)
1387
- return;
1388
- await new Promise(resolve => setTimeout(resolve, 10)); // 추가 딜레이
1389
- this.scrollToOption(currentItem);
1390
- }
1391
- componentWillLoad() {
1392
- // props가 모두 설정된 후에 실행되므로 올바른 options 값을 가져올 수 있음
1393
- this.filteredOptions = this.options;
1394
- this.initializeEvent(); // global dropdown Manager에 등록 + 이벤트 핸들러 초기화
1395
1597
  }
1396
1598
  disconnectedCallback() {
1397
- this.cleanupEvent(); // global dropdown Manager에서 제거 + 이벤트 정리
1398
- }
1399
- handleDocumentClick(event) {
1400
- if (!this.selectRef?.contains(event.target)) {
1401
- this.isOpen = false;
1402
- }
1599
+ if (this.rafId)
1600
+ cancelAnimationFrame(this.rafId);
1601
+ this.unobserveParent();
1602
+ this.wrapper?.remove();
1403
1603
  }
1404
- handleDocumentKeydown(keyboardEvent) {
1405
- keyboardEvent.stopPropagation();
1406
- const targetKey = ['ArrowDown', 'ArrowUp', 'Enter', 'Escape'];
1407
- if (!targetKey.includes(keyboardEvent.key))
1408
- return;
1409
- keyboardEvent.preventDefault();
1410
- switch (keyboardEvent.key) {
1411
- case 'ArrowDown':
1412
- case 'ArrowUp':
1413
- const keyboardNavigation = new SelectKeyboardNavigation(this.searchable, this.filteredOptions);
1414
- const nextIndex = keyboardNavigation.getNextIndex(this.itemIndex, keyboardEvent.key);
1415
- this.itemIndex = nextIndex;
1416
- break;
1417
- case 'Enter':
1418
- const selectedOption = this.filteredOptions[this.itemIndex];
1419
- if (selectedOption && !selectedOption.disabled) {
1420
- this.handleOptionSelection(selectedOption);
1421
- }
1422
- break;
1423
- case 'Escape':
1424
- this.isOpen = false;
1425
- break;
1426
- }
1604
+ resolveContainer() {
1605
+ const el = typeof this.to === 'string' ? document.querySelector(this.to) : this.to;
1606
+ return el instanceof HTMLElement ? el : document.body;
1427
1607
  }
1428
- // event handlers
1429
- handleTriggerClick = (event) => {
1430
- event.stopPropagation();
1431
- if (!this.disabled) {
1432
- this.isOpen = !this.isOpen;
1433
- this.dropDownShow?.emit({ isOpen: this.isOpen });
1434
- }
1435
- };
1436
- handleOptionClick = (detail) => {
1437
- const { option, event } = detail;
1438
- event.stopPropagation();
1439
- if (option.type === 'group')
1440
- this.handleGroupOptionClick(detail);
1441
- if (option.type === 'subgroup')
1442
- this.handleSubGroupOptionClick(detail);
1443
- if (option.type === 'item')
1444
- this.handleOptionSelection(option);
1445
- };
1446
- handleGroupOptionClick = (detail) => {
1447
- const { option, isSelected } = detail;
1448
- const childOptions = this.filteredOptions.filter(opt => opt.parent === option.value && !opt.disabled);
1449
- childOptions.forEach(subgroup => {
1450
- this.handleSubGroupOptionClick({
1451
- option: subgroup,
1452
- isSelected: isSelected || isSelected === null,
1453
- });
1608
+ createWrapper() {
1609
+ this.wrapper = document.createElement('div');
1610
+ Object.assign(this.wrapper.style, {
1611
+ position: 'absolute',
1612
+ zIndex: this.zIndex.toString(),
1613
+ transition: 'opacity 0.4s',
1614
+ top: '-9999px',
1615
+ left: '-9999px',
1454
1616
  });
1455
- };
1456
- handleSubGroupOptionClick = (detail) => {
1457
- const { option, isSelected } = detail;
1458
- const childOptions = this.filteredOptions.filter(opt => opt.parent === option.value && !opt.disabled);
1459
- if (isSelected || isSelected === null) {
1460
- // 모든 자식 옵션이 선택된 경우, 모두 선택 해제
1461
- this.value =
1462
- this.value?.filter(selected => !childOptions.some(child => child.value === selected.value)) ||
1463
- null;
1464
- }
1465
- else {
1466
- // 일부 또는 전체 자식 옵션이 선택되지 않은 경우, 모두 선택
1467
- const newSelections = childOptions.filter(child => !this.value?.some(selected => selected.value === child.value));
1468
- this.value = [...(this.value || []), ...newSelections];
1469
- }
1470
- };
1471
- filterOptions() {
1472
- if (!this.searchText || this.searchText.trim() === '') {
1473
- // 검색어가 없으면 전체 옵션 표시
1474
- this.filteredOptions = this.options;
1617
+ this.container.appendChild(this.wrapper);
1618
+ }
1619
+ moveSlotContent() {
1620
+ if (!this.wrapper)
1475
1621
  return;
1476
- }
1477
- const searchTerm = this.searchText.toLowerCase();
1478
- const matchedOptions = new Set();
1479
- // 1. 직접 매칭되는 옵션들 찾기
1480
- this.options.forEach(option => {
1481
- if (option.label.toLowerCase().includes(searchTerm)) {
1482
- matchedOptions.add(option);
1483
- // 매칭된 옵션의 상위 그룹들도 포함
1484
- this.addParentGroups(option, matchedOptions);
1622
+ const nodes = Array.from(this.el.childNodes).filter(n => n.nodeType !== Node.COMMENT_NODE);
1623
+ nodes.forEach(n => this.wrapper.appendChild(n));
1624
+ }
1625
+ // 위치 갱신 (scroll / resize)
1626
+ updatePosition() {
1627
+ if (this.rafId)
1628
+ cancelAnimationFrame(this.rafId);
1629
+ this.rafId = requestAnimationFrame(() => {
1630
+ if (!this.parentRef || !this.wrapper)
1631
+ return;
1632
+ const rect = this.parentRef.getBoundingClientRect();
1633
+ if (!rect.width && !rect.height)
1634
+ return; // 요소가 보이지 않는 경우
1635
+ const [offsetX, offsetY] = this.offset;
1636
+ const ARROW_SIZE = SdTooltipPortal.ARROW_SIZE;
1637
+ let top = 0;
1638
+ let left = 0;
1639
+ switch (this.placement) {
1640
+ case 'top':
1641
+ top = rect.top + window.scrollY - this.wrapper.offsetHeight + offsetY - ARROW_SIZE;
1642
+ left = rect.left + window.scrollX + rect.width / 2 - this.wrapper.offsetWidth / 2 + offsetX;
1643
+ break;
1644
+ case 'bottom':
1645
+ top = rect.bottom + window.scrollY + offsetY + ARROW_SIZE;
1646
+ left = rect.left + window.scrollX + rect.width / 2 - this.wrapper.offsetWidth / 2 + offsetX;
1647
+ break;
1648
+ case 'left':
1649
+ top = rect.top + window.scrollY + rect.height / 2 - this.wrapper.offsetHeight / 2 + offsetY;
1650
+ left = rect.left + window.scrollX - this.wrapper.offsetWidth - offsetX - ARROW_SIZE;
1651
+ break;
1652
+ case 'right':
1653
+ top = rect.top + window.scrollY + rect.height / 2 - this.wrapper.offsetHeight / 2 + offsetY;
1654
+ left = rect.right + window.scrollX + offsetX + ARROW_SIZE;
1655
+ break;
1485
1656
  }
1657
+ Object.assign(this.wrapper.style, {
1658
+ top: `${top}px`,
1659
+ left: `${left}px`,
1660
+ });
1486
1661
  });
1487
- // 2. Set을 배열로 변환하고 원본 순서 유지
1488
- this.filteredOptions = this.options.filter(option => matchedOptions.has(option));
1489
1662
  }
1490
- addParentGroups(option, matchedSet) {
1491
- if (!option.parent)
1663
+ // parentRef의 이동 / 크기변경 감지
1664
+ observeParent() {
1665
+ if (!this.parentRef)
1492
1666
  return;
1493
- const parentOption = this.options.find(opt => opt.value === option.parent);
1494
- if (parentOption && !matchedSet.has(parentOption)) {
1495
- matchedSet.add(parentOption);
1496
- // 재귀적으로 상위 그룹들도 추가
1497
- this.addParentGroups(parentOption, matchedSet);
1498
- }
1667
+ this.resizeObserver = new ResizeObserver(() => this.updatePosition());
1668
+ this.resizeObserver.observe(this.parentRef);
1669
+ this.mutationObserver = new MutationObserver(() => this.updatePosition());
1670
+ this.mutationObserver.observe(document.body, {
1671
+ childList: true,
1672
+ subtree: true,
1673
+ });
1499
1674
  }
1500
- getSelectedOption() {
1501
- return this.options.filter(option => this.value?.includes(option));
1675
+ unobserveParent() {
1676
+ this.resizeObserver?.disconnect();
1677
+ this.mutationObserver?.disconnect();
1502
1678
  }
1503
- handleDropdownScroll = (event) => {
1504
- const target = event.target;
1505
- const scrollTop = target.scrollTop;
1506
- // 스크롤이 조금이라도 되면 그림자 표시
1507
- this.isScrolled = scrollTop > 0;
1508
- };
1509
- async getNativeInputElement() {
1510
- if (this.searchRef) {
1511
- return this.searchRef.getNativeElement();
1512
- }
1513
- return null;
1679
+ // 외부 클릭 감지
1680
+ handleMouseDown(e) {
1681
+ this.isInsideClick = !!(this.wrapper && this.wrapper.contains(e.target));
1514
1682
  }
1515
- handleOptionSelection = (option) => {
1516
- if (!option || option.disabled)
1683
+ handleWindowClick(e) {
1684
+ if (this.isInsideClick) {
1685
+ this.isInsideClick = false;
1517
1686
  return;
1518
- const isAlreadySelected = this.value?.some(opt => opt.value === option.value);
1519
- if (isAlreadySelected) {
1520
- // 이미 선택된 옵션인 경우, 선택 해제
1521
- this.value = this.value?.filter(opt => opt.value !== option.value) || null;
1522
- }
1523
- else {
1524
- // 새로운 옵션 선택
1525
- this.value = [...(this.value || []), option];
1526
- }
1527
- };
1528
- getAllItemsUnderOption(parentOption) {
1529
- const childOptions = this.filteredOptions.filter(option => option.parent === parentOption.value && !option.disabled);
1530
- if (parentOption.type === 'group') {
1531
- // Group - 모든 하위 item들을 수집
1532
- const subgroupOptions = childOptions.filter(option => option.type === 'subgroup');
1533
- const allItemsUnderGroup = [];
1534
- // subgroup 하위의 모든 item
1535
- subgroupOptions.forEach(subgroup => {
1536
- const itemsUnderSubgroup = this.filteredOptions.filter(option => option.parent === subgroup.value && option.type === 'item' && !option.disabled);
1537
- allItemsUnderGroup.push(...itemsUnderSubgroup);
1538
- });
1539
- // Group 바로 하위 item
1540
- const directItems = childOptions.filter(option => option.type === 'item');
1541
- allItemsUnderGroup.push(...directItems);
1542
- return allItemsUnderGroup;
1543
1687
  }
1544
- return childOptions.filter(option => option.type === 'item');
1545
- }
1546
- isAllChildrenSelected(groupOption) {
1547
- const allItems = this.getAllItemsUnderOption(groupOption);
1548
- if (allItems.length === 0)
1549
- return false;
1550
- const selectedItems = allItems.filter(item => this.value?.some(selected => selected.value === item.value));
1551
- if (selectedItems.length === allItems.length)
1552
- return true;
1553
- if (selectedItems.length > 0)
1554
- return null;
1555
- return false;
1556
- }
1557
- getChildrenOptions(parentOption) {
1558
- if (parentOption.type === 'group') {
1559
- const allItems = this.getAllItemsUnderOption(parentOption);
1560
- const selectedItems = allItems.filter(item => this.value?.some(selected => selected.value === item.value));
1561
- return {
1562
- selectedCount: selectedItems.length,
1563
- totalCount: allItems.length,
1564
- };
1565
- }
1566
- // Subgroup의 경우
1567
- const children = this.filteredOptions.filter(option => option.parent === parentOption.value);
1568
- return {
1569
- selectedCount: children.filter(child => this.value?.some(val => val.value === child.value))
1570
- .length,
1571
- totalCount: children.length,
1572
- };
1573
- }
1574
- closeDropdown() {
1575
- this.isOpen = false;
1576
- }
1577
- scrollToOption(optionElement) {
1578
- if (!this.dropdownRef || !optionElement)
1688
+ if (this.wrapper?.contains(e.target))
1579
1689
  return;
1580
- const dropdown = this.dropdownRef;
1581
- const optionTop = optionElement.offsetTop;
1582
- const optionHeight = optionElement.offsetHeight;
1583
- const dropdownScrollTop = dropdown.scrollTop;
1584
- const dropdownHeight = dropdown.clientHeight;
1585
- const searchContainer = dropdown.querySelector('.sd-select__search-container');
1586
- const searchOffset = searchContainer ? searchContainer.offsetHeight : 0;
1587
- const visibleTop = dropdownScrollTop + searchOffset;
1588
- const visibleBottom = dropdownScrollTop + dropdownHeight;
1589
- if (optionTop < visibleTop) {
1590
- dropdown.scrollTop = optionTop - searchOffset;
1591
- }
1592
- else if (optionTop + optionHeight > visibleBottom) {
1593
- dropdown.scrollTop = optionTop + optionHeight - dropdownHeight + searchOffset;
1594
- }
1595
- }
1596
- render() {
1597
- const style = {
1598
- '--select-width': this.width || '200px',
1599
- '--select-dropdown-height': this.dropdownHeight || '260px',
1600
- };
1601
- return (index.h(index.Host, { key: 'bb06ec5405f0d97d3f970c49370249f7a05e1996', style: style }, index.h("div", { key: '325998f7e153d28ecce995f836d4192dc4adfe65', class: {
1602
- 'sd-select-multiple-group': true,
1603
- 'sd-select-multiple-group--open': this.isOpen,
1604
- 'sd-select-multiple-group--disabled': this.disabled,
1605
- }, style: this.containerStyle, ref: el => (this.selectRef = el) }, this.renderLabel(this.label, this.labelStyle), index.h("div", { key: 'c228f012628ffb7dd4346789c356eff8f256c2da', class: "sd-select-multiple-group__container" }, this.renderTrigger(), this.renderDropdown()))));
1606
- }
1607
- renderLabel(label, labelStyle) {
1608
- if (!label)
1609
- return null;
1610
- return (index.h("label", { class: "sd-select-multiple-group__label", style: labelStyle }, label));
1611
- }
1612
- renderTrigger() {
1613
- const selectedOption = this.getSelectedOption();
1614
- return (index.h("div", { class: "sd-select-multiple-group__trigger", tabindex: this.disabled ? -1 : 0, onClick: this.handleTriggerClick, style: this.triggerStyle }, index.h("span", { class: "sd-select-multiple-group__value" }, !selectedOption
1615
- ? '선택'
1616
- : selectedOption.length
1617
- ? selectedOption.map(option => option.label).join(', ')
1618
- : this.placeholder), this.clearable && selectedOption?.length > 0 && !this.disabled && (index.h("sd-icon", { key: "close-icon", name: "close", size: 10, color: "#888", class: "sd-select-multiple-group__clear", onClick: event => {
1619
- event.stopPropagation();
1620
- this.value = null;
1621
- } })), index.h("sd-icon", { key: "arrow-icon", name: "arrowDown", color: "#888", class: {
1622
- 'sd-select-multiple-group__arrow': true,
1623
- 'sd-select-multiple-group__arrow--open': this.isOpen,
1624
- } })));
1625
- }
1626
- renderDropdown() {
1627
- const style = {
1628
- '--select-width': this.width || '200px',
1629
- '--select-dropdown-height': this.dropdownHeight || '260px',
1630
- };
1631
- if (this.isOpen === false)
1632
- return null;
1633
- return (index.h("sd-portal", { open: this.isOpen, parentRef: this.selectRef, onSdClose: this.closeDropdown }, index.h("div", { class: "sd-select-multiple-group__dropdown", style: { ...style, ...this.dropdownStyle }, onScroll: this.handleDropdownScroll, ref: el => (this.dropdownRef = el) }, this.searchable && (index.h("div", { class: {
1634
- 'sd-select-multiple-group__search-container': true,
1635
- 'sd-select-multiple-group__search-container--scrolled': this.isScrolled,
1636
- }, onClick: event => event.stopPropagation() }, index.h("sd-input", { ref: el => (this.searchRef = el), value: this.searchText, placeholder: "\uAC80\uC0C9", clearable: true, inputStyle: { 'padding-left': '8px' }, autofocus: true, onSdInput: event => {
1637
- this.searchText = String(event?.detail);
1638
- }, onSdFocus: () => {
1639
- this.itemIndex = -1;
1640
- }, onKeyDown: e => {
1641
- if (e.code === 'Enter')
1642
- e.stopPropagation();
1643
- } }, index.h("sd-icon", { name: "search", size: 16, color: "#737373", slot: "prefix" })))), this.filteredOptions.length > 0 ? (this.filteredOptions.map((option, index$1) => (index.h("slot", { name: `option-${option.value}` }, index.h("sd-select-option-group", { option: option, index: index$1, isSelected: option.type === 'item'
1644
- ? this.value?.some(selected => selected.value === option.value)
1645
- : this.isAllChildrenSelected(option), isFocused: index$1 === this.itemIndex, optionStyle: this.optionStyle, onOptionClick: ({ detail, }) => {
1646
- if (option.type !== 'item' && !this.useCheckbox) {
1647
- return;
1648
- }
1649
- this.handleOptionClick(detail);
1650
- }, useCheckbox: this.useCheckbox, ...(option.type !== 'item' && { countInfo: this.getChildrenOptions(option) }) }))))) : (index.h("slot", { name: "option-placeholder" }, index.h("div", { class: 'sd-select-multiple-group__option-placeholder', style: this.optionStyle }, this.optionPlaceholder))))));
1651
- }
1652
- static get watchers() { return {
1653
- "value": ["valueChanged"],
1654
- "options": ["optionsChanged"],
1655
- "searchText": ["searchTextChanged"],
1656
- "itemIndex": ["itemIndexChanged"],
1657
- "isOpen": ["isOpenChanged"]
1658
- }; }
1659
- };
1660
- SdSelectMultipleGroup.style = sdSelectMultipleGroupCss;
1661
-
1662
- const sdSelectOptionCss = "sd-select-option{display:block;height:fit-content;line-height:0}sd-select-option .sd-select__option{display:flex;padding:4px 12px;font-size:12px;line-height:20px;cursor:pointer}sd-select-option .sd-select__option__checkbox-wrapper{display:flex;width:100%;column-gap:8px;align-items:center;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}sd-select-option .sd-select__option--focused{background-color:#e6f1ff}sd-select-option .sd-select__option--selected:not(:hover):not(.sd-select__option--use-checkbox),sd-select-option .sd-select__option--focused:not(:hover):not(.sd-select__option--use-checkbox){color:#0075ff;font-weight:700}sd-select-option .sd-select__option--disabled{color:#aaaaaa;cursor:not-allowed}sd-select-option .sd-select__option:hover:not(.sd-select__option--disabled){background-color:#0075ff;color:white}";
1663
-
1664
- const SdSelectOption = class {
1665
- constructor(hostRef) {
1666
- index.registerInstance(this, hostRef);
1667
- this.optionClick = index.createEvent(this, "optionClick");
1668
- }
1669
- get el() { return index.getElement(this); }
1670
- option;
1671
- index;
1672
- isSelected = false;
1673
- isFocused = false;
1674
- optionStyle;
1675
- disabled = false;
1676
- useCheckbox = false;
1677
- isHovered = false;
1678
- async isDisabled() {
1679
- return !!this.option.disabled;
1680
- }
1681
- optionClick;
1682
- handleClick = (event) => {
1683
- event.stopPropagation();
1684
- if (!this.option.disabled && !this.disabled) {
1685
- this.optionClick.emit({
1686
- option: this.option,
1687
- index: this.index,
1688
- event,
1689
- });
1690
- }
1691
- };
1692
- render() {
1693
- return (index.h(index.Host, { key: 'cb2d7b25a778f3ea56dd6aaa880dde5b3f109d92' }, index.h("div", { key: '5b954062fdfc0466bcbbad7c86eeb9ed62655cf9', class: {
1694
- 'sd-select__option': true,
1695
- 'sd-select__option--selected': this.isSelected,
1696
- 'sd-select__option--disabled': !!this.option.disabled,
1697
- 'sd-select__option--focused': this.isFocused,
1698
- 'sd-select__option--use-checkbox': this.useCheckbox,
1699
- }, onMouseEnter: () => (this.isHovered = true), onMouseLeave: () => (this.isHovered = false), style: this.optionStyle, "data-index": this.index, onClick: this.handleClick }, this.useCheckbox ? (index.h("div", { class: "sd-select__option__checkbox-wrapper" }, index.h("sd-checkbox", { checked: this.isSelected, disabled: this.option.disabled,
1700
- // checkboxStyle={
1701
- // !this.isSelected
1702
- // ? { borderColor: '#888' }
1703
- // : this.isHovered
1704
- // ? { borderColor: 'white' }
1705
- // : { borderColor: '#0075ff' }
1706
- // }
1707
- onClick: e => {
1708
- e.preventDefault();
1709
- this.handleClick(e);
1710
- } }), index.h("span", { class: "sd-select__option-label" }, this.option.label))) : (this.option.label))));
1711
- }
1712
- };
1713
- SdSelectOption.style = sdSelectOptionCss;
1714
-
1715
- const sdSelectOptionGroupCss = "sd-select-option-group{display:block;height:fit-content}sd-select-option-group .sd-select__option-group{display:flex;padding:4px 12px;padding-left:28px;font-size:12px;line-height:20px}sd-select-option-group .sd-select__option-group.sd-select__option-group--group:not(.sd-select__option-group--use-checkbox),sd-select-option-group .sd-select__option-group.sd-select__option-group--subgroup:not(.sd-select__option-group--use-checkbox){cursor:default}sd-select-option-group .sd-select__option-group.sd-select__option-group--group{padding-left:12px;background-color:#f5faff !important;color:#333333 !important;font-weight:700}sd-select-option-group .sd-select__option-group.sd-select__option-group--subgroup{padding-left:20px;background-color:#f9f9f9 !important;color:#333333 !important;font-weight:500}sd-select-option-group .sd-select__option-group sd-checkbox__bg{border-color:#888888}sd-select-option-group .sd-select__option-group__label-wrapper{display:flex;width:100%;column-gap:8px;align-items:center;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}sd-select-option-group .sd-select__option-group__label-wrapper sd-checkbox{flex-shrink:0}sd-select-option-group .sd-select__option-group__label-wrapper .sd-select__option-group-label{flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sd-select-option-group .sd-select__option-group__label-wrapper .sd-select__option-group__count-indicator{width:fit-content;flex-shrink:0;font-size:12px;font-weight:500;color:#888888}sd-select-option-group .sd-select__option-group--focused{background-color:#e6f1ff}sd-select-option-group .sd-select__option-group--selected.sd-select__option-group--item:not(:hover):not(.sd-select__option-group--use-checkbox),sd-select-option-group .sd-select__option-group--focused.sd-select__option-group--item:not(:hover):not(.sd-select__option-group--use-checkbox){color:#0075ff;font-weight:700}sd-select-option-group .sd-select__option-group--disabled{color:#aaaaaa;cursor:not-allowed}sd-select-option-group .sd-select__option-group:hover:not(.sd-select__option-group--disabled){background-color:#0075ff;color:white}sd-select-option-group .sd-select__option-group:hover.sd-select__option-group--selected.sd-select__option-group--item sd-checkbox .sd-checkbox__bg{border-color:white !important}";
1716
-
1717
- const SdSelectOptionGroup = class {
1718
- constructor(hostRef) {
1719
- index.registerInstance(this, hostRef);
1720
- this.optionClick = index.createEvent(this, "optionClick");
1721
- }
1722
- get el() { return index.getElement(this); }
1723
- option;
1724
- index;
1725
- isSelected = false;
1726
- isFocused = false;
1727
- optionStyle;
1728
- disabled = false;
1729
- useCheckbox = false;
1730
- useIndicator = true;
1731
- countInfo = {
1732
- selectedCount: 0,
1733
- totalCount: 0,
1734
- };
1735
- isHovered = false;
1736
- async isDisabled() {
1737
- return !!this.option.disabled || this.option.type === 'group' || this.option.type === 'subgroup';
1690
+ this.sdClose.emit();
1738
1691
  }
1739
- optionClick;
1740
- handleClick = (option, isSelected, event) => {
1741
- event.stopPropagation();
1742
- if (option.type === 'group' || option.type === 'subgroup') {
1743
- this.optionClick.emit({
1744
- option: this.option,
1745
- isSelected,
1746
- index: this.index,
1747
- event,
1748
- });
1749
- return;
1750
- }
1751
- if (!this.option.disabled && !this.disabled) {
1752
- this.optionClick.emit({
1753
- option: this.option,
1754
- isSelected,
1755
- index: this.index,
1756
- event,
1757
- });
1758
- }
1759
- };
1760
1692
  render() {
1761
- return (index.h("div", { key: '2761283354fd179a42c719d5e67a10b44c0c11bb', class: {
1762
- 'sd-select__option-group': true,
1763
- 'sd-select__option-group--selected': !!this.isSelected,
1764
- 'sd-select__option-group--disabled': !!this.option.disabled,
1765
- 'sd-select__option-group--focused': this.isFocused,
1766
- 'sd-select__option-group--use-checkbox': this.useCheckbox,
1767
- 'sd-select__option-group--group': this.option.type === 'group',
1768
- 'sd-select__option-group--subgroup': this.option.type === 'subgroup',
1769
- 'sd-select__option-group--item': this.option.type === 'item',
1770
- }, onMouseEnter: () => (this.isHovered = true), onMouseLeave: () => (this.isHovered = false), style: this.optionStyle, "data-index": this.index, onClick: event => this.handleClick(this.option, this.isSelected, event) }, index.h("div", { key: '5cd6f320711e866a18076040fb4de57b1626784f', class: "sd-select__option-group__label-wrapper" }, this.useCheckbox && (index.h("sd-checkbox", { key: 'bc76cef83da27c879dcd05bb5dbb370e10b18957', checked: this.isSelected, disabled: this.option.disabled, onClick: e => {
1771
- e.preventDefault();
1772
- this.handleClick(this.option, this.isSelected, e);
1773
- } })), index.h("span", { key: 'b768ea0c0a3385f00823b9743e7256c29d6d58fd', class: "sd-select__option-group-label" }, this.option.label), this.useIndicator && this.option.type !== 'item' && (index.h("span", { key: '63cf4fd18f904441f5d4b27d8e6e32fdeb1aba5a', class: "sd-select__option-group__count-indicator" }, `(${this.countInfo?.selectedCount}/${this.countInfo?.totalCount})`)))));
1693
+ return index.h("slot", { key: '641dacdeceb023695ced987731591783daa6b88e' });
1774
1694
  }
1775
1695
  };
1776
- SdSelectOptionGroup.style = sdSelectOptionGroupCss;
1777
1696
 
1697
+ exports.sd_button = SdButton;
1778
1698
  exports.sd_checkbox = SdCheckbox;
1699
+ exports.sd_guide = SdGuide;
1779
1700
  exports.sd_icon = SdIcon;
1780
1701
  exports.sd_input = SdInput;
1702
+ exports.sd_pagination = SdPagination;
1781
1703
  exports.sd_portal = SdPortal;
1782
1704
  exports.sd_select = SdSelect;
1783
- exports.sd_select_multiple = SdSelectMultiple;
1784
- exports.sd_select_multiple_group = SdSelectMultipleGroup;
1785
1705
  exports.sd_select_option = SdSelectOption;
1786
- exports.sd_select_option_group = SdSelectOptionGroup;
1787
- //# sourceMappingURL=sd-checkbox.sd-icon.sd-input.sd-portal.sd-select.sd-select-multiple.sd-select-multiple-group.sd-select-option.sd-select-option-group.entry.cjs.js.map
1706
+ exports.sd_table = SdTable;
1707
+ exports.sd_tooltip = SdTooltip;
1708
+ exports.sd_tooltip_portal = SdTooltipPortal;
1709
+ //# sourceMappingURL=sd-button.sd-checkbox.sd-guide.sd-icon.sd-input.sd-pagination.sd-portal.sd-select.sd-select-option.sd-table.sd-tooltip.sd-tooltip-portal.entry.cjs.js.map