gnui 1.2.21 → 1.2.22

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 (66) hide show
  1. package/dist/js/gnui.esm.js +184 -4
  2. package/dist/js/gnui.js +184 -4
  3. package/dist/js/gnui.min.js +6 -6
  4. package/package.json +1 -1
  5. package/styleguide/assets/components.js +82 -0
  6. package/styleguide/assets/js/gnui.js +184 -4
  7. package/styleguide/assets/js/gnui.min.js +6 -6
  8. package/styleguide/category/COLOR/index.html +1 -1
  9. package/styleguide/category/COMPONENT/Alert(js)/index.html +1 -1
  10. package/styleguide/category/COMPONENT/Bignumber/index.html +1 -1
  11. package/styleguide/category/COMPONENT/Breadcrumb/index.html +1 -1
  12. package/styleguide/category/COMPONENT/Calendar(js)/index.html +1 -1
  13. package/styleguide/category/COMPONENT/Card/index.html +1 -1
  14. package/styleguide/category/COMPONENT/Chart(js)/index.html +1 -1
  15. package/styleguide/category/COMPONENT/Datagrid(js)/index.html +1 -1
  16. package/styleguide/category/COMPONENT/Datalist(js)/index.html +1 -1
  17. package/styleguide/category/COMPONENT/Growl(js)/index.html +1 -1
  18. package/styleguide/category/COMPONENT/JsonView(js)/index.html +1 -1
  19. package/styleguide/category/COMPONENT/Loader(js)/index.html +1 -1
  20. package/styleguide/category/COMPONENT/MenuButton(js)/index.html +1 -1
  21. package/styleguide/category/COMPONENT/Message(js)/index.html +1 -1
  22. package/styleguide/category/COMPONENT/Modal(js)/index.html +1 -1
  23. package/styleguide/category/COMPONENT/Pagination(js)/index.html +1 -1
  24. package/styleguide/category/COMPONENT/Panel/index.html +1 -1
  25. package/styleguide/category/COMPONENT/Progressbar(js)/index.html +1 -1
  26. package/styleguide/category/COMPONENT/Tab(js)/index.html +1 -1
  27. package/styleguide/category/COMPONENT/Tagcloud(js)/index.html +1 -1
  28. package/styleguide/category/COMPONENT/Tooltip(js)/index.html +1 -1
  29. package/styleguide/category/COMPONENT/Tree(js)/index.html +1 -1
  30. package/styleguide/category/CONTROLS/Button(js)/index.html +1 -1
  31. package/styleguide/category/CONTROLS/Checkbox/index.html +1 -1
  32. package/styleguide/category/CONTROLS/Colorpicker(js)/index.html +1 -1
  33. package/styleguide/category/CONTROLS/Datepicker(js)/index.html +1 -1
  34. package/styleguide/category/CONTROLS/Dropdown(js)/index.html +83 -1
  35. package/styleguide/category/CONTROLS/File/index.html +1 -1
  36. package/styleguide/category/CONTROLS/Form/Control/index.html +1 -1
  37. package/styleguide/category/CONTROLS/Form/Field/index.html +1 -1
  38. package/styleguide/category/CONTROLS/Form/Plain/index.html +1 -1
  39. package/styleguide/category/CONTROLS/Input/index.html +1 -1
  40. package/styleguide/category/CONTROLS/MultiText(js)/index.html +1 -1
  41. package/styleguide/category/CONTROLS/Picklist(js)/index.html +35 -1
  42. package/styleguide/category/CONTROLS/Radio/index.html +1 -1
  43. package/styleguide/category/CONTROLS/Select/index.html +1 -1
  44. package/styleguide/category/CONTROLS/SelectButton(js)/index.html +1 -1
  45. package/styleguide/category/CONTROLS/Slider/index.html +1 -1
  46. package/styleguide/category/CONTROLS/SortableList(js)/index.html +1 -1
  47. package/styleguide/category/CONTROLS/Switch(js)/index.html +1 -1
  48. package/styleguide/category/CONTROLS/SyntaxInput(js)/index.html +1 -1
  49. package/styleguide/category/CONTROLS/Textarea/index.html +1 -1
  50. package/styleguide/category/CONTROLS/Time(js)/index.html +1 -1
  51. package/styleguide/category/ELEMENTS/Box/index.html +1 -1
  52. package/styleguide/category/ELEMENTS/Icon/index.html +1 -1
  53. package/styleguide/category/ELEMENTS/Image/index.html +1 -1
  54. package/styleguide/category/ELEMENTS/List/index.html +1 -1
  55. package/styleguide/category/ELEMENTS/Table/index.html +1 -1
  56. package/styleguide/category/ELEMENTS/Tag/index.html +1 -1
  57. package/styleguide/category/ELEMENTS/Title/index.html +1 -1
  58. package/styleguide/category/LAYOUT/Container/index.html +1 -1
  59. package/styleguide/category/LAYOUT/Grid/index.html +1 -1
  60. package/styleguide/category/LAYOUT/Splitter(js)/index.html +1 -1
  61. package/styleguide/category/UTILITY/index.html +1 -1
  62. package/styleguide/category/Utils/index.html +1 -1
  63. package/styleguide/color.html +1 -1
  64. package/styleguide/index.html +1 -1
  65. package/styleguide/tag/javascript/index.html +117 -1
  66. package/styleguide/tag/v.0.1.0/index.html +117 -1
@@ -33521,11 +33521,13 @@ class Dropdown extends GNCoreInstance {
33521
33521
  : find('select', this.$el).value;
33522
33522
  },
33523
33523
  changeData: (data) => {
33524
+ var _a;
33524
33525
  this.$options.data = data;
33525
33526
  this._hidden.flatData();
33526
33527
  this.$options.hasSearch && this._hidden.resetSearch();
33527
33528
  this.$template.reRender(find('.dropdown-text', this.$el), this._hidden.renderLabel());
33528
33529
  this.$template.reRender(find('.dropdown-items > div:not(.dropdown-search)', this.$el), this._hidden.renderSub(data));
33530
+ (_a = this.$options._tooltipCache) === null || _a === void 0 ? void 0 : _a.clear();
33529
33531
  },
33530
33532
  search: (e) => {
33531
33533
  clearTimeout(this.$options.timer);
@@ -33641,7 +33643,7 @@ class Dropdown extends GNCoreInstance {
33641
33643
  (isArray$1(this.$options.value) ? this.$options.value.find((v) => v.value === option.value) : option.value === this.$options.value.value)
33642
33644
  ? ' is-active'
33643
33645
  : '') +
33644
- (this.$options.multiple ? ' has-checkbox' : ''), "on-click": isArray$1(option.value) || !displayText ? null : this._hidden.select.bind(this, option), "data-value": isArray$1(option.value) ? '' : option.value, title: displayText ? escapeEntity(String(displayText)) : '' },
33646
+ (this.$options.multiple ? ' has-checkbox' : ''), "on-click": isArray$1(option.value) || !displayText ? null : this._hidden.select.bind(this, option), "on-mouseenter": this.$options.optionTooltip && displayText && !isArray$1(option.value) ? this._hidden.showOptionTooltip.bind(this, option) : null, "on-mouseleave": this.$options.optionTooltip ? this._hidden.hideOptionTooltip : null, "data-value": isArray$1(option.value) ? '' : option.value, title: displayText ? escapeEntity(String(displayText)) : '' },
33645
33647
  createElement$1("span", { className: "dropdown-text", innerHTML: option.html ? option.html : '' },
33646
33648
  option.html ? ('') : renderAsCols ? (createElement$1("div", { className: "gn-checks dropdown-cols" },
33647
33649
  this.$options.multiple && (createElement$1("div", { className: "is-small is-no-padding" },
@@ -33718,6 +33720,76 @@ class Dropdown extends GNCoreInstance {
33718
33720
  enable: () => {
33719
33721
  this.$options.disabled = false;
33720
33722
  removeClass(this.$el, 'is-disabled');
33723
+ },
33724
+ showOptionTooltip: (option, e) => {
33725
+ var _a;
33726
+ if (!this.$options.optionTooltip || !this.$options._tooltipPanel)
33727
+ return;
33728
+ const panel = this.$options._tooltipPanel;
33729
+ const direction = this.$options.optionTooltip.direction || 'right';
33730
+ const rect = e.currentTarget.getBoundingClientRect();
33731
+ panel.className = `gn-tooltip is-${direction}`;
33732
+ panel.style.position = 'fixed';
33733
+ panel.style.zIndex = '9999';
33734
+ switch (direction) {
33735
+ case 'left':
33736
+ panel.style.top = (rect.top + rect.height / 2) + 'px';
33737
+ panel.style.left = rect.left + 'px';
33738
+ break;
33739
+ case 'top':
33740
+ panel.style.top = rect.top + 'px';
33741
+ panel.style.left = (rect.left + rect.width / 2) + 'px';
33742
+ break;
33743
+ case 'bottom':
33744
+ panel.style.top = rect.bottom + 'px';
33745
+ panel.style.left = (rect.left + rect.width / 2) + 'px';
33746
+ break;
33747
+ default:
33748
+ panel.style.top = (rect.top + rect.height / 2) + 'px';
33749
+ panel.style.left = (rect.right + 10) + 'px';
33750
+ }
33751
+ addClass(panel, 'is-active');
33752
+ const cacheKey = String(option.value);
33753
+ const cache = this.$options._tooltipCache;
33754
+ if (cache.has(cacheKey)) {
33755
+ panel.innerHTML = (_a = cache.get(cacheKey)) !== null && _a !== void 0 ? _a : '';
33756
+ return;
33757
+ }
33758
+ const { content, fetch: fetchFn } = this.$options.optionTooltip;
33759
+ if (content) {
33760
+ // content()는 개발자가 제공하는 함수 — XSS 방지는 호출자 책임
33761
+ const html = content(option);
33762
+ cache.set(cacheKey, html);
33763
+ panel.innerHTML = html;
33764
+ }
33765
+ else if (fetchFn) {
33766
+ const requestId = ++this.$options._tooltipRequestId;
33767
+ panel.innerHTML = '<div class="gn-loader is-inline"></div>';
33768
+ try {
33769
+ fetchFn(option)
33770
+ .then((html) => {
33771
+ if (requestId !== this.$options._tooltipRequestId)
33772
+ return;
33773
+ cache.set(cacheKey, html);
33774
+ if (panel.classList.contains('is-active')) {
33775
+ panel.innerHTML = html;
33776
+ }
33777
+ })
33778
+ .catch(() => {
33779
+ if (requestId === this.$options._tooltipRequestId) {
33780
+ removeClass(panel, 'is-active');
33781
+ }
33782
+ });
33783
+ }
33784
+ catch (_b) {
33785
+ removeClass(panel, 'is-active');
33786
+ }
33787
+ }
33788
+ },
33789
+ hideOptionTooltip: () => {
33790
+ if (!this.$options._tooltipPanel)
33791
+ return;
33792
+ removeClass(this.$options._tooltipPanel, 'is-active');
33721
33793
  }
33722
33794
  };
33723
33795
  this.config = {
@@ -33734,7 +33806,8 @@ class Dropdown extends GNCoreInstance {
33734
33806
  scrollHeight: 0,
33735
33807
  timer: 0,
33736
33808
  disabled: false,
33737
- multiple: false
33809
+ multiple: false,
33810
+ optionTooltip: undefined
33738
33811
  };
33739
33812
  this.events = {
33740
33813
  onChange: true
@@ -33818,6 +33891,22 @@ class Dropdown extends GNCoreInstance {
33818
33891
  setValue(this.$options.value, options);
33819
33892
  }
33820
33893
  }
33894
+ if (this.$options.optionTooltip) {
33895
+ this.$options._tooltipCache = new Map();
33896
+ this.$options._tooltipRequestId = 0;
33897
+ const direction = this.$options.optionTooltip.direction || 'right';
33898
+ const panel = document.createElement('div');
33899
+ panel.className = `gn-tooltip is-${direction}`;
33900
+ panel.style.position = 'fixed';
33901
+ panel.style.zIndex = '9999';
33902
+ document.body.appendChild(panel);
33903
+ this.$options._tooltipPanel = panel;
33904
+ this.$options._destroy = () => {
33905
+ if (panel.parentElement) {
33906
+ panel.parentElement.removeChild(panel);
33907
+ }
33908
+ };
33909
+ }
33821
33910
  }
33822
33911
  isBrandIcon(iconName) {
33823
33912
  const iconLookup = { prefix: 'fab', iconName: iconName };
@@ -40137,7 +40226,7 @@ class Picklist extends GNCoreInstance {
40137
40226
  : renderAsCols
40138
40227
  ? (option.cols && option.cols.length ? String(option.cols[0]) : '')
40139
40228
  : (option.text || option.value);
40140
- return (createElement$1("li", { key: index, id: this._uid + '_opt_' + index, className: 'dropdown-item' + (renderAsCols ? ' picklist-row' : '') + (option.selected ? ' is-active' : ''), "data-value": option.value, "on-click": !displayText ? null : this._hidden.toggle.bind(this), "on-dblclick": !displayText
40229
+ return (createElement$1("li", { key: index, id: this._uid + '_opt_' + index, className: 'dropdown-item' + (renderAsCols ? ' picklist-row' : '') + (option.selected ? ' is-active' : ''), "data-value": option.value, "on-click": !displayText ? null : this._hidden.toggle.bind(this), "on-mouseenter": this.$options.optionTooltip && displayText ? this._hidden.showOptionTooltip.bind(this, option) : null, "on-mouseleave": this.$options.optionTooltip ? this._hidden.hideOptionTooltip : null, "on-dblclick": !displayText
40141
40230
  ? null
40142
40231
  : this._hidden.move.bind(this, item === 'source' ? 'add' : 'remove', [
40143
40232
  {
@@ -40170,12 +40259,86 @@ class Picklist extends GNCoreInstance {
40170
40259
  removeClass(this.$el, 'is-disabled');
40171
40260
  },
40172
40261
  setSource: (data) => {
40262
+ var _a;
40173
40263
  this.$options.data.source = data;
40174
40264
  this._hidden.reRender('source');
40265
+ (_a = this.$options._tooltipCache) === null || _a === void 0 ? void 0 : _a.clear();
40175
40266
  },
40176
40267
  setTarget: (data) => {
40268
+ var _a;
40177
40269
  this.$options.data.target = data;
40178
40270
  this._hidden.reRender('target');
40271
+ (_a = this.$options._tooltipCache) === null || _a === void 0 ? void 0 : _a.clear();
40272
+ },
40273
+ showOptionTooltip: (option, e) => {
40274
+ var _a;
40275
+ if (!this.$options.optionTooltip || !this.$options._tooltipPanel)
40276
+ return;
40277
+ const panel = this.$options._tooltipPanel;
40278
+ const direction = this.$options.optionTooltip.direction || 'right';
40279
+ const rect = e.currentTarget.getBoundingClientRect();
40280
+ panel.className = `gn-tooltip is-${direction}`;
40281
+ panel.style.position = 'fixed';
40282
+ panel.style.zIndex = '9999';
40283
+ switch (direction) {
40284
+ case 'left':
40285
+ panel.style.top = (rect.top + rect.height / 2) + 'px';
40286
+ panel.style.left = rect.left + 'px';
40287
+ break;
40288
+ case 'top':
40289
+ panel.style.top = rect.top + 'px';
40290
+ panel.style.left = (rect.left + rect.width / 2) + 'px';
40291
+ break;
40292
+ case 'bottom':
40293
+ panel.style.top = rect.bottom + 'px';
40294
+ panel.style.left = (rect.left + rect.width / 2) + 'px';
40295
+ break;
40296
+ default:
40297
+ panel.style.top = (rect.top + rect.height / 2) + 'px';
40298
+ panel.style.left = (rect.right + 10) + 'px';
40299
+ }
40300
+ addClass(panel, 'is-active');
40301
+ const cacheKey = option.value;
40302
+ const cache = this.$options._tooltipCache;
40303
+ if (cache.has(cacheKey)) {
40304
+ panel.innerHTML = (_a = cache.get(cacheKey)) !== null && _a !== void 0 ? _a : '';
40305
+ return;
40306
+ }
40307
+ const { content, fetch: fetchFn } = this.$options.optionTooltip;
40308
+ if (content) {
40309
+ // content()는 개발자가 제공하는 함수 — XSS 방지는 호출자 책임
40310
+ const html = content(option);
40311
+ cache.set(cacheKey, html);
40312
+ panel.innerHTML = html;
40313
+ }
40314
+ else if (fetchFn) {
40315
+ const requestId = ++this.$options._tooltipRequestId;
40316
+ panel.innerHTML = '<div class="gn-loader is-inline"></div>';
40317
+ try {
40318
+ fetchFn(option)
40319
+ .then((html) => {
40320
+ if (requestId !== this.$options._tooltipRequestId)
40321
+ return;
40322
+ cache.set(cacheKey, html);
40323
+ if (panel.classList.contains('is-active')) {
40324
+ panel.innerHTML = html;
40325
+ }
40326
+ })
40327
+ .catch(() => {
40328
+ if (requestId === this.$options._tooltipRequestId) {
40329
+ removeClass(panel, 'is-active');
40330
+ }
40331
+ });
40332
+ }
40333
+ catch (_b) {
40334
+ removeClass(panel, 'is-active');
40335
+ }
40336
+ }
40337
+ },
40338
+ hideOptionTooltip: () => {
40339
+ if (!this.$options._tooltipPanel)
40340
+ return;
40341
+ removeClass(this.$options._tooltipPanel, 'is-active');
40179
40342
  }
40180
40343
  };
40181
40344
  this.config = {
@@ -40204,7 +40367,8 @@ class Picklist extends GNCoreInstance {
40204
40367
  hasSourceSearch: false,
40205
40368
  hasTargetSearch: false,
40206
40369
  orderable: true,
40207
- height: 150
40370
+ height: 150,
40371
+ optionTooltip: undefined
40208
40372
  };
40209
40373
  this.events = {
40210
40374
  onChange: true,
@@ -40313,6 +40477,22 @@ class Picklist extends GNCoreInstance {
40313
40477
  if (this.$options.textSets.targetCaption.length > 0) {
40314
40478
  style(find('.picklist-target .dropdown-items', this.$el), 'height', getUnit('height', getNumber(this.$options.height) - getNumber(style(find('.picklist-target .picklist-caption', this.$el), 'height'))));
40315
40479
  }
40480
+ if (this.$options.optionTooltip) {
40481
+ this.$options._tooltipCache = new Map();
40482
+ this.$options._tooltipRequestId = 0;
40483
+ const direction = this.$options.optionTooltip.direction || 'right';
40484
+ const panel = document.createElement('div');
40485
+ panel.className = `gn-tooltip is-${direction}`;
40486
+ panel.style.position = 'fixed';
40487
+ panel.style.zIndex = '9999';
40488
+ document.body.appendChild(panel);
40489
+ this.$options._tooltipPanel = panel;
40490
+ this.$options._destroy = () => {
40491
+ if (panel.parentElement) {
40492
+ panel.parentElement.removeChild(panel);
40493
+ }
40494
+ };
40495
+ }
40316
40496
  }
40317
40497
  isBrandIcon(iconName) {
40318
40498
  const iconLookup = { prefix: 'fab', iconName: iconName };
package/dist/js/gnui.js CHANGED
@@ -33527,11 +33527,13 @@
33527
33527
  : find('select', this.$el).value;
33528
33528
  },
33529
33529
  changeData: (data) => {
33530
+ var _a;
33530
33531
  this.$options.data = data;
33531
33532
  this._hidden.flatData();
33532
33533
  this.$options.hasSearch && this._hidden.resetSearch();
33533
33534
  this.$template.reRender(find('.dropdown-text', this.$el), this._hidden.renderLabel());
33534
33535
  this.$template.reRender(find('.dropdown-items > div:not(.dropdown-search)', this.$el), this._hidden.renderSub(data));
33536
+ (_a = this.$options._tooltipCache) === null || _a === void 0 ? void 0 : _a.clear();
33535
33537
  },
33536
33538
  search: (e) => {
33537
33539
  clearTimeout(this.$options.timer);
@@ -33647,7 +33649,7 @@
33647
33649
  (isArray$1(this.$options.value) ? this.$options.value.find((v) => v.value === option.value) : option.value === this.$options.value.value)
33648
33650
  ? ' is-active'
33649
33651
  : '') +
33650
- (this.$options.multiple ? ' has-checkbox' : ''), "on-click": isArray$1(option.value) || !displayText ? null : this._hidden.select.bind(this, option), "data-value": isArray$1(option.value) ? '' : option.value, title: displayText ? escapeEntity(String(displayText)) : '' },
33652
+ (this.$options.multiple ? ' has-checkbox' : ''), "on-click": isArray$1(option.value) || !displayText ? null : this._hidden.select.bind(this, option), "on-mouseenter": this.$options.optionTooltip && displayText && !isArray$1(option.value) ? this._hidden.showOptionTooltip.bind(this, option) : null, "on-mouseleave": this.$options.optionTooltip ? this._hidden.hideOptionTooltip : null, "data-value": isArray$1(option.value) ? '' : option.value, title: displayText ? escapeEntity(String(displayText)) : '' },
33651
33653
  createElement$1("span", { className: "dropdown-text", innerHTML: option.html ? option.html : '' },
33652
33654
  option.html ? ('') : renderAsCols ? (createElement$1("div", { className: "gn-checks dropdown-cols" },
33653
33655
  this.$options.multiple && (createElement$1("div", { className: "is-small is-no-padding" },
@@ -33724,6 +33726,76 @@
33724
33726
  enable: () => {
33725
33727
  this.$options.disabled = false;
33726
33728
  removeClass(this.$el, 'is-disabled');
33729
+ },
33730
+ showOptionTooltip: (option, e) => {
33731
+ var _a;
33732
+ if (!this.$options.optionTooltip || !this.$options._tooltipPanel)
33733
+ return;
33734
+ const panel = this.$options._tooltipPanel;
33735
+ const direction = this.$options.optionTooltip.direction || 'right';
33736
+ const rect = e.currentTarget.getBoundingClientRect();
33737
+ panel.className = `gn-tooltip is-${direction}`;
33738
+ panel.style.position = 'fixed';
33739
+ panel.style.zIndex = '9999';
33740
+ switch (direction) {
33741
+ case 'left':
33742
+ panel.style.top = (rect.top + rect.height / 2) + 'px';
33743
+ panel.style.left = rect.left + 'px';
33744
+ break;
33745
+ case 'top':
33746
+ panel.style.top = rect.top + 'px';
33747
+ panel.style.left = (rect.left + rect.width / 2) + 'px';
33748
+ break;
33749
+ case 'bottom':
33750
+ panel.style.top = rect.bottom + 'px';
33751
+ panel.style.left = (rect.left + rect.width / 2) + 'px';
33752
+ break;
33753
+ default:
33754
+ panel.style.top = (rect.top + rect.height / 2) + 'px';
33755
+ panel.style.left = (rect.right + 10) + 'px';
33756
+ }
33757
+ addClass(panel, 'is-active');
33758
+ const cacheKey = String(option.value);
33759
+ const cache = this.$options._tooltipCache;
33760
+ if (cache.has(cacheKey)) {
33761
+ panel.innerHTML = (_a = cache.get(cacheKey)) !== null && _a !== void 0 ? _a : '';
33762
+ return;
33763
+ }
33764
+ const { content, fetch: fetchFn } = this.$options.optionTooltip;
33765
+ if (content) {
33766
+ // content()는 개발자가 제공하는 함수 — XSS 방지는 호출자 책임
33767
+ const html = content(option);
33768
+ cache.set(cacheKey, html);
33769
+ panel.innerHTML = html;
33770
+ }
33771
+ else if (fetchFn) {
33772
+ const requestId = ++this.$options._tooltipRequestId;
33773
+ panel.innerHTML = '<div class="gn-loader is-inline"></div>';
33774
+ try {
33775
+ fetchFn(option)
33776
+ .then((html) => {
33777
+ if (requestId !== this.$options._tooltipRequestId)
33778
+ return;
33779
+ cache.set(cacheKey, html);
33780
+ if (panel.classList.contains('is-active')) {
33781
+ panel.innerHTML = html;
33782
+ }
33783
+ })
33784
+ .catch(() => {
33785
+ if (requestId === this.$options._tooltipRequestId) {
33786
+ removeClass(panel, 'is-active');
33787
+ }
33788
+ });
33789
+ }
33790
+ catch (_b) {
33791
+ removeClass(panel, 'is-active');
33792
+ }
33793
+ }
33794
+ },
33795
+ hideOptionTooltip: () => {
33796
+ if (!this.$options._tooltipPanel)
33797
+ return;
33798
+ removeClass(this.$options._tooltipPanel, 'is-active');
33727
33799
  }
33728
33800
  };
33729
33801
  this.config = {
@@ -33740,7 +33812,8 @@
33740
33812
  scrollHeight: 0,
33741
33813
  timer: 0,
33742
33814
  disabled: false,
33743
- multiple: false
33815
+ multiple: false,
33816
+ optionTooltip: undefined
33744
33817
  };
33745
33818
  this.events = {
33746
33819
  onChange: true
@@ -33824,6 +33897,22 @@
33824
33897
  setValue(this.$options.value, options);
33825
33898
  }
33826
33899
  }
33900
+ if (this.$options.optionTooltip) {
33901
+ this.$options._tooltipCache = new Map();
33902
+ this.$options._tooltipRequestId = 0;
33903
+ const direction = this.$options.optionTooltip.direction || 'right';
33904
+ const panel = document.createElement('div');
33905
+ panel.className = `gn-tooltip is-${direction}`;
33906
+ panel.style.position = 'fixed';
33907
+ panel.style.zIndex = '9999';
33908
+ document.body.appendChild(panel);
33909
+ this.$options._tooltipPanel = panel;
33910
+ this.$options._destroy = () => {
33911
+ if (panel.parentElement) {
33912
+ panel.parentElement.removeChild(panel);
33913
+ }
33914
+ };
33915
+ }
33827
33916
  }
33828
33917
  isBrandIcon(iconName) {
33829
33918
  const iconLookup = { prefix: 'fab', iconName: iconName };
@@ -40143,7 +40232,7 @@
40143
40232
  : renderAsCols
40144
40233
  ? (option.cols && option.cols.length ? String(option.cols[0]) : '')
40145
40234
  : (option.text || option.value);
40146
- return (createElement$1("li", { key: index, id: this._uid + '_opt_' + index, className: 'dropdown-item' + (renderAsCols ? ' picklist-row' : '') + (option.selected ? ' is-active' : ''), "data-value": option.value, "on-click": !displayText ? null : this._hidden.toggle.bind(this), "on-dblclick": !displayText
40235
+ return (createElement$1("li", { key: index, id: this._uid + '_opt_' + index, className: 'dropdown-item' + (renderAsCols ? ' picklist-row' : '') + (option.selected ? ' is-active' : ''), "data-value": option.value, "on-click": !displayText ? null : this._hidden.toggle.bind(this), "on-mouseenter": this.$options.optionTooltip && displayText ? this._hidden.showOptionTooltip.bind(this, option) : null, "on-mouseleave": this.$options.optionTooltip ? this._hidden.hideOptionTooltip : null, "on-dblclick": !displayText
40147
40236
  ? null
40148
40237
  : this._hidden.move.bind(this, item === 'source' ? 'add' : 'remove', [
40149
40238
  {
@@ -40176,12 +40265,86 @@
40176
40265
  removeClass(this.$el, 'is-disabled');
40177
40266
  },
40178
40267
  setSource: (data) => {
40268
+ var _a;
40179
40269
  this.$options.data.source = data;
40180
40270
  this._hidden.reRender('source');
40271
+ (_a = this.$options._tooltipCache) === null || _a === void 0 ? void 0 : _a.clear();
40181
40272
  },
40182
40273
  setTarget: (data) => {
40274
+ var _a;
40183
40275
  this.$options.data.target = data;
40184
40276
  this._hidden.reRender('target');
40277
+ (_a = this.$options._tooltipCache) === null || _a === void 0 ? void 0 : _a.clear();
40278
+ },
40279
+ showOptionTooltip: (option, e) => {
40280
+ var _a;
40281
+ if (!this.$options.optionTooltip || !this.$options._tooltipPanel)
40282
+ return;
40283
+ const panel = this.$options._tooltipPanel;
40284
+ const direction = this.$options.optionTooltip.direction || 'right';
40285
+ const rect = e.currentTarget.getBoundingClientRect();
40286
+ panel.className = `gn-tooltip is-${direction}`;
40287
+ panel.style.position = 'fixed';
40288
+ panel.style.zIndex = '9999';
40289
+ switch (direction) {
40290
+ case 'left':
40291
+ panel.style.top = (rect.top + rect.height / 2) + 'px';
40292
+ panel.style.left = rect.left + 'px';
40293
+ break;
40294
+ case 'top':
40295
+ panel.style.top = rect.top + 'px';
40296
+ panel.style.left = (rect.left + rect.width / 2) + 'px';
40297
+ break;
40298
+ case 'bottom':
40299
+ panel.style.top = rect.bottom + 'px';
40300
+ panel.style.left = (rect.left + rect.width / 2) + 'px';
40301
+ break;
40302
+ default:
40303
+ panel.style.top = (rect.top + rect.height / 2) + 'px';
40304
+ panel.style.left = (rect.right + 10) + 'px';
40305
+ }
40306
+ addClass(panel, 'is-active');
40307
+ const cacheKey = option.value;
40308
+ const cache = this.$options._tooltipCache;
40309
+ if (cache.has(cacheKey)) {
40310
+ panel.innerHTML = (_a = cache.get(cacheKey)) !== null && _a !== void 0 ? _a : '';
40311
+ return;
40312
+ }
40313
+ const { content, fetch: fetchFn } = this.$options.optionTooltip;
40314
+ if (content) {
40315
+ // content()는 개발자가 제공하는 함수 — XSS 방지는 호출자 책임
40316
+ const html = content(option);
40317
+ cache.set(cacheKey, html);
40318
+ panel.innerHTML = html;
40319
+ }
40320
+ else if (fetchFn) {
40321
+ const requestId = ++this.$options._tooltipRequestId;
40322
+ panel.innerHTML = '<div class="gn-loader is-inline"></div>';
40323
+ try {
40324
+ fetchFn(option)
40325
+ .then((html) => {
40326
+ if (requestId !== this.$options._tooltipRequestId)
40327
+ return;
40328
+ cache.set(cacheKey, html);
40329
+ if (panel.classList.contains('is-active')) {
40330
+ panel.innerHTML = html;
40331
+ }
40332
+ })
40333
+ .catch(() => {
40334
+ if (requestId === this.$options._tooltipRequestId) {
40335
+ removeClass(panel, 'is-active');
40336
+ }
40337
+ });
40338
+ }
40339
+ catch (_b) {
40340
+ removeClass(panel, 'is-active');
40341
+ }
40342
+ }
40343
+ },
40344
+ hideOptionTooltip: () => {
40345
+ if (!this.$options._tooltipPanel)
40346
+ return;
40347
+ removeClass(this.$options._tooltipPanel, 'is-active');
40185
40348
  }
40186
40349
  };
40187
40350
  this.config = {
@@ -40210,7 +40373,8 @@
40210
40373
  hasSourceSearch: false,
40211
40374
  hasTargetSearch: false,
40212
40375
  orderable: true,
40213
- height: 150
40376
+ height: 150,
40377
+ optionTooltip: undefined
40214
40378
  };
40215
40379
  this.events = {
40216
40380
  onChange: true,
@@ -40319,6 +40483,22 @@
40319
40483
  if (this.$options.textSets.targetCaption.length > 0) {
40320
40484
  style(find('.picklist-target .dropdown-items', this.$el), 'height', getUnit('height', getNumber(this.$options.height) - getNumber(style(find('.picklist-target .picklist-caption', this.$el), 'height'))));
40321
40485
  }
40486
+ if (this.$options.optionTooltip) {
40487
+ this.$options._tooltipCache = new Map();
40488
+ this.$options._tooltipRequestId = 0;
40489
+ const direction = this.$options.optionTooltip.direction || 'right';
40490
+ const panel = document.createElement('div');
40491
+ panel.className = `gn-tooltip is-${direction}`;
40492
+ panel.style.position = 'fixed';
40493
+ panel.style.zIndex = '9999';
40494
+ document.body.appendChild(panel);
40495
+ this.$options._tooltipPanel = panel;
40496
+ this.$options._destroy = () => {
40497
+ if (panel.parentElement) {
40498
+ panel.parentElement.removeChild(panel);
40499
+ }
40500
+ };
40501
+ }
40322
40502
  }
40323
40503
  isBrandIcon(iconName) {
40324
40504
  const iconLookup = { prefix: 'fab', iconName: iconName };