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
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "1.2.21",
7
+ "version": "1.2.22",
8
8
  "type": "module",
9
9
  "main": "dist/js/gnui.js",
10
10
  "types": "@types/gnui.d.ts",
@@ -342,6 +342,68 @@ const components = {
342
342
  { value: '5', cols: ['항목5', '카테고리B', '5000'] }
343
343
  ]
344
344
  });
345
+ Gn.create('dropdown', {
346
+ target: '.new-dropdown6',
347
+ width: '200px',
348
+ data: [
349
+ { value: 'win', text: 'Windows' },
350
+ { value: 'mac', text: 'macOS' },
351
+ { value: 'linux', text: 'Linux' },
352
+ { value: 'android', text: 'Android' },
353
+ { value: 'ios', text: 'iOS' }
354
+ ],
355
+ optionTooltip: {
356
+ direction: 'right',
357
+ content: function (option) {
358
+ var descriptions = {
359
+ win: '마이크로소프트의 데스크톱 운영체제',
360
+ mac: '애플의 데스크톱 운영체제',
361
+ linux: '오픈소스 기반 운영체제',
362
+ android: '구글의 모바일 운영체제',
363
+ ios: '애플의 모바일 운영체제'
364
+ };
365
+ var desc = descriptions[option.value] || '';
366
+ return '<div style="min-width:160px"><strong>' + option.text + '</strong><p style="margin:4px 0 0">' + desc + '</p></div>';
367
+ }
368
+ }
369
+ });
370
+ Gn.create('dropdown', {
371
+ target: '.new-dropdown7',
372
+ width: '200px',
373
+ data: [
374
+ { value: 'host1', text: '192.168.0.1' },
375
+ { value: 'host2', text: '192.168.0.2' },
376
+ { value: 'host3', text: '10.0.0.1' },
377
+ { value: 'host4', text: '10.0.0.2' }
378
+ ],
379
+ optionTooltip: {
380
+ direction: 'right',
381
+ fetch: function (option) {
382
+ return new Promise(function (resolve) {
383
+ setTimeout(function () {
384
+ var mockData = {
385
+ host1: { name: 'Server-A', os: 'Windows Server 2022', status: 'online' },
386
+ host2: { name: 'Server-B', os: 'Ubuntu 22.04', status: 'online' },
387
+ host3: { name: 'Router-1', os: 'Cisco IOS', status: 'online' },
388
+ host4: { name: 'Switch-1', os: 'Cisco NX-OS', status: 'offline' }
389
+ };
390
+ var d = mockData[option.value];
391
+ var statusColor = d.status === 'online' ? 'success' : 'danger';
392
+ resolve(
393
+ '<div style="min-width:180px">' +
394
+ '<strong>' + d.name + '</strong>' +
395
+ '<ul style="margin:6px 0 0;padding:0;list-style:none">' +
396
+ '<li>IP: ' + option.text + '</li>' +
397
+ '<li>OS: ' + d.os + '</li>' +
398
+ '<li>상태: <span class="gn-tag is-' + statusColor + ' is-small">' + d.status + '</span></li>' +
399
+ '</ul>' +
400
+ '</div>'
401
+ );
402
+ }, 500);
403
+ });
404
+ }
405
+ }
406
+ });
345
407
  },
346
408
  Datagrid: function () {
347
409
  Gn.create('datagrid', {
@@ -1659,6 +1721,26 @@ const components = {
1659
1721
  width: '500px',
1660
1722
  height: 150
1661
1723
  });
1724
+ Gn.create('picklist', {
1725
+ target: '.new-picklist-tooltip',
1726
+ data: {
1727
+ source: [
1728
+ { value: '항목1', text: 'item1' },
1729
+ { value: '항목2', text: 'item2' },
1730
+ { value: '항목3', text: 'item3' }
1731
+ ],
1732
+ target: []
1733
+ },
1734
+ optionTooltip: {
1735
+ direction: 'right',
1736
+ content: function(option) {
1737
+ return '<div style="padding: 10px; max-width: 200px;">' + option.text + '에 대한 추가 정보입니다.</div>';
1738
+ }
1739
+ },
1740
+ direction: 'horizontal',
1741
+ width: '500px',
1742
+ height: 150
1743
+ });
1662
1744
  },
1663
1745
  SortableList: function () {
1664
1746
  Gn.create('sortablelist', {
@@ -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 };