@kupola/kupola 1.2.0 → 1.3.1

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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +330 -286
  3. package/adapters/axios.d.ts +34 -0
  4. package/adapters/axios.js +122 -0
  5. package/adapters/navios-http.d.ts +110 -0
  6. package/adapters/navios-http.js +151 -0
  7. package/dist/css/accessibility.css +119 -0
  8. package/dist/css/animations.css +224 -0
  9. package/dist/css/brand-themes.css +300 -0
  10. package/dist/css/colors_and_type.css +441 -0
  11. package/dist/css/components-ext.css +4165 -0
  12. package/dist/css/components.css +1483 -0
  13. package/dist/css/responsive.css +697 -0
  14. package/dist/css/scaffold.css +145 -0
  15. package/dist/css/states.css +316 -0
  16. package/dist/css/theme-dark.css +296 -0
  17. package/dist/css/theme-light.css +296 -0
  18. package/dist/css/utilities.css +171 -0
  19. package/dist/kupola.cjs.js +219 -161
  20. package/dist/kupola.cjs.js.map +1 -1
  21. package/dist/kupola.esm.js +6643 -5709
  22. package/dist/kupola.esm.js.map +1 -1
  23. package/dist/kupola.umd.js +219 -161
  24. package/dist/kupola.umd.js.map +1 -1
  25. package/dist/plugins/vite-plugin-kupola.js +120 -0
  26. package/dist/types/kupola.d.ts +421 -323
  27. package/js/calendar.js +334 -25
  28. package/js/carousel.js +182 -48
  29. package/js/collapse.js +148 -34
  30. package/js/color-picker.js +416 -108
  31. package/js/component.js +8 -19
  32. package/js/countdown.js +9 -8
  33. package/js/data-bind.js +73 -16
  34. package/js/datepicker.js +488 -110
  35. package/js/depends.js +710 -0
  36. package/js/dialog.js +4 -2
  37. package/js/drawer.js +172 -8
  38. package/js/dropdown.js +272 -17
  39. package/js/dynamic-tags.js +156 -40
  40. package/js/fileupload.js +9 -8
  41. package/js/form.js +280 -254
  42. package/js/global-events.js +281 -188
  43. package/js/heatmap.js +10 -7
  44. package/js/i18n.js +18 -10
  45. package/js/icons.js +141 -161
  46. package/js/image-preview.js +146 -2
  47. package/js/initializer.js +113 -71
  48. package/js/kupola-core.js +123 -45
  49. package/js/kupola-lifecycle.js +13 -11
  50. package/js/message.js +8 -1
  51. package/js/modal.js +207 -59
  52. package/js/notification.js +8 -1
  53. package/js/numberinput.js +9 -8
  54. package/js/pagination.js +263 -0
  55. package/js/registry.js +29 -12
  56. package/js/select.js +482 -27
  57. package/js/slide-captcha.js +11 -2
  58. package/js/slider.js +442 -25
  59. package/js/statcard.js +9 -7
  60. package/js/table.js +1210 -0
  61. package/js/tag.js +268 -14
  62. package/js/theme.js +14 -43
  63. package/js/timepicker.js +335 -66
  64. package/js/tooltip.js +317 -86
  65. package/js/utils.js +6 -2
  66. package/js/validation.js +6 -2
  67. package/js/virtual-list.js +11 -7
  68. package/js/web-components.js +288 -0
  69. package/package.json +77 -67
  70. package/plugins/vite-plugin-kupola.js +120 -0
  71. package/types/kupola.d.ts +421 -323
  72. package/CHANGELOG.md +0 -130
  73. package/INTEGRATION.md +0 -440
  74. package/PROJECT_SUMMARY.md +0 -312
  75. package/SKILL.md +0 -572
  76. package/dist/utils/utils/Kupola.cs +0 -77
  77. package/dist/utils/utils/Kupola.java +0 -104
  78. package/dist/utils/utils/kupola.go +0 -120
  79. package/dist/utils/utils/kupola.js +0 -63
  80. package/dist/utils/utils/kupola.py +0 -1392
  81. package/dist/utils/utils/kupola.rb +0 -69
  82. package/js/composition-api.js +0 -458
  83. package/js/error-handler.js +0 -181
  84. package/js/http.js +0 -419
  85. package/js/kupola-devtools.js +0 -598
  86. package/js/performance.js +0 -250
  87. package/js/router.js +0 -396
  88. package/js/security.js +0 -189
  89. package/js/test-utils.js +0 -251
  90. package/templates/base.html +0 -30
  91. package/templates/base_dashboard.html +0 -99
  92. package/utils/Kupola.cs +0 -77
  93. package/utils/Kupola.java +0 -104
  94. package/utils/kupola.go +0 -120
  95. package/utils/kupola.js +0 -63
  96. package/utils/kupola.py +0 -1392
  97. package/utils/kupola.rb +0 -69
@@ -1,4 +1,4 @@
1
- class KupolaLifecycle {
1
+ export class KupolaLifecycle {
2
2
  constructor(scope = 'app') {
3
3
  this.scope = scope;
4
4
  this.hooks = new Map();
@@ -345,7 +345,7 @@ class KupolaLifecycle {
345
345
  }
346
346
  }
347
347
 
348
- class KupolaPluginManager {
348
+ export class KupolaPluginManager {
349
349
  constructor() {
350
350
  this.plugins = new Map();
351
351
  this.enabledPlugins = new Set();
@@ -477,7 +477,7 @@ class KupolaPluginManager {
477
477
  const pluginHooks = this.pluginHooks.get(pluginName);
478
478
 
479
479
  Object.keys(hooks).forEach(phase => {
480
- const unsubscribe = window.kupolaLifecycle?.on(phase, hooks[phase], { name: `${pluginName}:${phase}` });
480
+ const unsubscribe = typeof window !== 'undefined' && window.kupolaLifecycle?.on(phase, hooks[phase], { name: `${pluginName}:${phase}` });
481
481
  if (unsubscribe) {
482
482
  pluginHooks.push({ phase, unsubscribe });
483
483
  }
@@ -496,15 +496,17 @@ class KupolaPluginManager {
496
496
  }
497
497
  }
498
498
 
499
- const kupolaLifecycle = new KupolaLifecycle('app');
500
- const kupolaPluginManager = new KupolaPluginManager();
499
+ export const kupolaLifecycle = new KupolaLifecycle('app');
500
+ export const kupolaPluginManager = new KupolaPluginManager();
501
501
 
502
- function createLifecycle(scope = 'app') {
502
+ export function createLifecycle(scope = 'app') {
503
503
  return new KupolaLifecycle(scope);
504
504
  }
505
505
 
506
- window.KupolaLifecycle = KupolaLifecycle;
507
- window.KupolaPluginManager = KupolaPluginManager;
508
- window.kupolaLifecycle = kupolaLifecycle;
509
- window.kupolaPluginManager = kupolaPluginManager;
510
- window.createLifecycle = createLifecycle;
506
+ if (typeof window !== 'undefined') {
507
+ window.KupolaLifecycle = KupolaLifecycle;
508
+ window.KupolaPluginManager = KupolaPluginManager;
509
+ window.kupolaLifecycle = kupolaLifecycle;
510
+ window.kupolaPluginManager = kupolaPluginManager;
511
+ window.createLifecycle = createLifecycle;
512
+ }
package/js/message.js CHANGED
@@ -57,4 +57,11 @@ const Message = {
57
57
  }
58
58
  };
59
59
 
60
- function initMessages() {}
60
+ function initMessages() {}
61
+
62
+ export { Message, initMessages };
63
+
64
+ if (typeof window !== 'undefined') {
65
+ window.Message = Message;
66
+ window.initMessages = initMessages;
67
+ }
package/js/modal.js CHANGED
@@ -1,12 +1,23 @@
1
1
  class Modal {
2
- constructor(element) {
2
+ constructor(element, options = {}) {
3
3
  this.element = element;
4
4
  this.mask = element.querySelector('.ds-modal-mask');
5
5
  this.modal = element.querySelector('.ds-modal');
6
6
  this.closeBtn = element.querySelector('.ds-modal__close');
7
7
 
8
+ // Options
9
+ this.fullscreen = options.fullscreen || element.hasAttribute('data-modal-fullscreen');
10
+ this.closableOnMask = options.closableOnMask !== false; // default true
11
+ this.escClose = options.escClose !== false;
12
+ this.width = options.width || element.getAttribute('data-modal-width') || '';
13
+ this.center = options.center !== false;
14
+ this.onBeforeOpen = options.onBeforeOpen || null;
15
+ this.onBeforeClose = options.onBeforeClose || null;
16
+ this.onOpened = options.onOpened || null;
17
+ this.onClosed = options.onClosed || null;
18
+
8
19
  this._keydownHandler = (e) => {
9
- if (e.key === 'Escape' && this.isVisible()) {
20
+ if (this.escClose && e.key === 'Escape' && this.isVisible()) {
10
21
  this.close();
11
22
  }
12
23
  };
@@ -14,7 +25,7 @@ class Modal {
14
25
  this._closeBtnClickHandler = () => this.close();
15
26
 
16
27
  this._maskClickHandler = (e) => {
17
- if (e.target === this.mask) {
28
+ if (this.closableOnMask && e.target === this.mask) {
18
29
  this.close();
19
30
  }
20
31
  };
@@ -32,24 +43,93 @@ class Modal {
32
43
  }
33
44
 
34
45
  document.addEventListener('keydown', this._keydownHandler);
46
+
47
+ // Apply fullscreen
48
+ if (this.fullscreen && this.modal) {
49
+ this.modal.classList.add('ds-modal--fullscreen');
50
+ }
51
+
52
+ // Apply custom width
53
+ if (this.width && this.modal) {
54
+ this.modal.style.maxWidth = this.width;
55
+ }
35
56
  }
36
57
 
37
58
  open() {
38
- this.mask.classList.add('is-visible');
59
+ if (this.onBeforeOpen) {
60
+ const result = this.onBeforeOpen();
61
+ if (result === false) return;
62
+ }
63
+
64
+ if (this.mask) {
65
+ this.mask.classList.add('is-visible');
66
+ this.mask.classList.add('ds-modal-fade-enter');
67
+ requestAnimationFrame(() => {
68
+ this.mask.classList.add('ds-modal-fade-enter-active');
69
+ });
70
+ }
71
+ if (this.modal) {
72
+ this.modal.classList.add('ds-modal-zoom-enter');
73
+ requestAnimationFrame(() => {
74
+ this.modal.classList.add('ds-modal-zoom-enter-active');
75
+ });
76
+ }
77
+
39
78
  Modal._openCount = (Modal._openCount || 0) + 1;
40
79
  document.body.style.overflow = 'hidden';
80
+
81
+ if (this.onOpened) {
82
+ setTimeout(() => this.onOpened(), 300);
83
+ }
84
+
85
+ this.element.dispatchEvent(new CustomEvent('kupola:modal-open', { bubbles: true }));
41
86
  }
42
87
 
43
88
  close() {
44
- this.mask.classList.remove('is-visible');
89
+ if (this.onBeforeClose) {
90
+ const result = this.onBeforeClose();
91
+ if (result === false) return;
92
+ }
93
+
94
+ if (this.mask) {
95
+ this.mask.classList.remove('ds-modal-fade-enter-active');
96
+ this.mask.classList.add('ds-modal-fade-leave-active');
97
+ }
98
+ if (this.modal) {
99
+ this.modal.classList.remove('ds-modal-zoom-enter-active');
100
+ this.modal.classList.add('ds-modal-zoom-leave-active');
101
+ }
102
+
103
+ setTimeout(() => {
104
+ if (this.mask) {
105
+ this.mask.classList.remove('is-visible', 'ds-modal-fade-enter', 'ds-modal-fade-leave-active');
106
+ }
107
+ if (this.modal) {
108
+ this.modal.classList.remove('ds-modal-zoom-enter', 'ds-modal-zoom-leave-active');
109
+ }
110
+ }, 300);
111
+
45
112
  Modal._openCount = Math.max(0, (Modal._openCount || 0) - 1);
46
113
  if (Modal._openCount === 0) {
47
114
  document.body.style.overflow = '';
48
115
  }
116
+
117
+ if (this.onClosed) {
118
+ setTimeout(() => this.onClosed(), 300);
119
+ }
120
+
121
+ this.element.dispatchEvent(new CustomEvent('kupola:modal-close', { bubbles: true }));
122
+ }
123
+
124
+ toggleFullscreen() {
125
+ this.fullscreen = !this.fullscreen;
126
+ if (this.modal) {
127
+ this.modal.classList.toggle('ds-modal--fullscreen', this.fullscreen);
128
+ }
49
129
  }
50
130
 
51
131
  isVisible() {
52
- return this.mask.classList.contains('is-visible');
132
+ return this.mask && this.mask.classList.contains('is-visible');
53
133
  }
54
134
 
55
135
  destroy() {
@@ -72,89 +152,151 @@ function createModal(options = {}) {
72
152
  const {
73
153
  title = '',
74
154
  content = '',
155
+ html = false,
75
156
  width = '480px',
157
+ fullscreen = false,
158
+ showCancel = true,
159
+ showConfirm = true,
160
+ confirmText = 'OK',
161
+ cancelText = 'Cancel',
162
+ confirmClass = 'ds-btn--brand',
163
+ cancelClass = 'ds-btn--ghost',
164
+ closable = true,
165
+ maskClosable = true,
76
166
  onConfirm,
77
- onCancel
167
+ onCancel,
168
+ onOpen,
169
+ onClose,
170
+ footer = null
78
171
  } = options;
79
172
 
80
173
  const container = document.createElement('div');
81
174
  container.className = 'ds-modal-container';
175
+
176
+ let footerHTML = '';
177
+ if (footer !== null) {
178
+ if (typeof footer === 'string') {
179
+ footerHTML = `<div class="ds-modal__footer">${footer}</div>`;
180
+ } else if (showConfirm || showCancel) {
181
+ footerHTML = `<div class="ds-modal__footer">
182
+ ${showCancel ? `<button class="ds-btn ${cancelClass}" data-modal-cancel>${cancelText}</button>` : ''}
183
+ ${showConfirm ? `<button class="ds-btn ${confirmClass}" data-modal-confirm>${confirmText}</button>` : ''}
184
+ </div>`;
185
+ }
186
+ }
187
+
82
188
  container.innerHTML = `
83
189
  <div class="ds-modal-mask">
84
- <div class="ds-modal" style="max-width: ${width}">
190
+ <div class="ds-modal${fullscreen ? ' ds-modal--fullscreen' : ''}" style="${!fullscreen ? 'max-width: ' + width : ''}">
85
191
  <div class="ds-modal__header">
86
192
  <span class="ds-modal__title"></span>
87
- <button class="ds-modal__close" aria-label="Close">
193
+ ${closable ? `<button class="ds-modal__close" aria-label="Close">
88
194
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
89
195
  <path d="M18 6L6 18M6 6l12 12"/>
90
196
  </svg>
91
- </button>
197
+ </button>` : ''}
92
198
  </div>
93
199
  <div class="ds-modal__body"></div>
94
- ${onConfirm || onCancel ? `
95
- <div class="ds-modal__footer">
96
- ${onCancel ? `<button class="ds-btn ds-btn--ghost" data-modal-cancel>Cancel</button>` : ''}
97
- ${onConfirm ? `<button class="ds-btn ds-btn--brand" data-modal-confirm>OK</button>` : ''}
98
- </div>
99
- ` : ''}
200
+ ${footerHTML}
100
201
  </div>
101
202
  </div>
102
203
  `;
103
204
 
104
205
  document.body.appendChild(container);
105
206
 
106
- const modal = new Modal(container);
207
+ const modal = new Modal(container, { fullscreen, closableOnMask: maskClosable });
107
208
 
108
209
  const titleEl = container.querySelector('.ds-modal__title');
109
210
  if (titleEl) titleEl.textContent = title;
110
211
  const bodyEl = container.querySelector('.ds-modal__body');
111
- if (bodyEl) bodyEl.textContent = content;
212
+ if (bodyEl) {
213
+ if (html) {
214
+ bodyEl.innerHTML = content;
215
+ } else {
216
+ bodyEl.textContent = content;
217
+ }
218
+ }
112
219
 
113
220
  const confirmBtn = container.querySelector('[data-modal-confirm]');
114
221
  const cancelBtn = container.querySelector('[data-modal-cancel]');
115
222
 
116
- const confirmHandler = () => {
117
- if (onConfirm) onConfirm();
118
- modal.close();
119
- };
120
-
121
- const cancelHandler = () => {
122
- if (onCancel) onCancel();
123
- modal.close();
124
- };
125
-
126
- if (confirmBtn) {
127
- confirmBtn.addEventListener('click', confirmHandler);
128
- }
129
-
130
- if (cancelBtn) {
131
- cancelBtn.addEventListener('click', cancelHandler);
132
- }
133
-
134
- const closeAndDestroy = () => {
135
- setTimeout(() => {
136
- if (confirmBtn) {
137
- confirmBtn.removeEventListener('click', confirmHandler);
138
- }
139
- if (cancelBtn) {
140
- cancelBtn.removeEventListener('click', cancelHandler);
223
+ let isConfirming = false;
224
+
225
+ const confirmHandler = async () => {
226
+ if (onConfirm) {
227
+ // Support async onConfirm
228
+ confirmBtn.disabled = true;
229
+ confirmBtn.classList.add('is-loading');
230
+ try {
231
+ const result = await onConfirm();
232
+ if (result === false) {
233
+ confirmBtn.disabled = false;
234
+ confirmBtn.classList.remove('is-loading');
235
+ return;
141
236
  }
142
- modal.destroy();
143
- container.remove();
144
- }, 300);
145
- };
146
-
147
- const originalClose = modal.close.bind(modal);
148
- modal.close = () => {
149
- originalClose();
150
- closeAndDestroy();
151
- };
237
+ } catch(e) {
238
+ confirmBtn.disabled = false;
239
+ confirmBtn.classList.remove('is-loading');
240
+ return;
241
+ }
242
+ }
243
+ isConfirming = true;
244
+ modal.close();
245
+ };
246
+
247
+ const cancelHandler = () => {
248
+ if (onCancel) onCancel();
249
+ modal.close();
250
+ };
251
+
252
+ if (confirmBtn) confirmBtn.addEventListener('click', confirmHandler);
253
+ if (cancelBtn) cancelBtn.addEventListener('click', cancelHandler);
254
+
255
+ const closeAndDestroy = () => {
256
+ setTimeout(() => {
257
+ if (confirmBtn) confirmBtn.removeEventListener('click', confirmHandler);
258
+ if (cancelBtn) cancelBtn.removeEventListener('click', cancelHandler);
259
+ modal.destroy();
260
+ container.remove();
261
+ if (onClose) onClose(isConfirming);
262
+ }, 300);
263
+ };
264
+
265
+ const originalClose = modal.close.bind(modal);
266
+ modal.close = () => {
267
+ originalClose();
268
+ closeAndDestroy();
269
+ };
152
270
 
153
271
  modal.open();
272
+ if (onOpen) setTimeout(() => onOpen(), 50);
154
273
 
155
274
  return modal;
156
275
  }
157
276
 
277
+ // Convenience methods
278
+ function confirmModal(options) {
279
+ if (typeof options === 'string') {
280
+ options = { content: options };
281
+ }
282
+ return createModal({
283
+ ...options,
284
+ showCancel: true,
285
+ showConfirm: true
286
+ });
287
+ }
288
+
289
+ function alertModal(options) {
290
+ if (typeof options === 'string') {
291
+ options = { content: options };
292
+ }
293
+ return createModal({
294
+ ...options,
295
+ showCancel: false,
296
+ showConfirm: true
297
+ });
298
+ }
299
+
158
300
  function initModal(element) {
159
301
  if (element.__kupolaInitialized) return;
160
302
 
@@ -179,13 +321,19 @@ function initModals() {
179
321
  });
180
322
  }
181
323
 
182
- if (typeof module !== 'undefined' && module.exports) {
183
- module.exports = { Modal, initModals, initModal, cleanupModal, createModal };
184
- } else {
324
+ export { Modal, initModals, initModal, cleanupModal, createModal, confirmModal, alertModal };
325
+
326
+ if (typeof window !== 'undefined') {
327
+ window.Modal = Modal;
185
328
  window.initModal = initModal;
186
329
  window.cleanupModal = cleanupModal;
330
+ window.initModals = initModals;
331
+ window.createModal = createModal;
332
+ window.confirmModal = confirmModal;
333
+ window.alertModal = alertModal;
334
+
335
+ if (window.kupolaInitializer) {
336
+ window.kupolaInitializer.register('modal', initModal, cleanupModal);
337
+ }
187
338
  }
188
339
 
189
- if (window.kupolaInitializer) {
190
- window.kupolaInitializer.register('modal', initModal, cleanupModal);
191
- }
@@ -70,4 +70,11 @@ const Notification = {
70
70
  }
71
71
  };
72
72
 
73
- function initNotifications() {}
73
+ function initNotifications() {}
74
+
75
+ export { Notification, initNotifications };
76
+
77
+ if (typeof window !== 'undefined') {
78
+ window.Notification = Notification;
79
+ window.initNotifications = initNotifications;
80
+ }
package/js/numberinput.js CHANGED
@@ -86,7 +86,7 @@ class NumberInput {
86
86
  }
87
87
 
88
88
  dispatchChange() {
89
- this.element.dispatchEvent(new CustomEvent('ds-number-input-change', {
89
+ this.element.dispatchEvent(new CustomEvent('kupola:number-input-change', {
90
90
  detail: {
91
91
  value: this.getValue()
92
92
  }
@@ -133,14 +133,15 @@ function initNumberInputs() {
133
133
  });
134
134
  }
135
135
 
136
- if (typeof module !== 'undefined' && module.exports) {
137
- module.exports = { NumberInput, initNumberInputs, initNumberInput, cleanupNumberInput };
138
- } else {
136
+ export { NumberInput, initNumberInputs, initNumberInput, cleanupNumberInput };
137
+
138
+ if (typeof window !== 'undefined') {
139
139
  window.NumberInput = NumberInput;
140
140
  window.initNumberInput = initNumberInput;
141
141
  window.cleanupNumberInput = cleanupNumberInput;
142
- }
143
-
144
- if (window.kupolaInitializer) {
145
- window.kupolaInitializer.register('number-input', initNumberInput, cleanupNumberInput);
142
+ window.initNumberInputs = initNumberInputs;
143
+
144
+ if (window.kupolaInitializer) {
145
+ window.kupolaInitializer.register('number-input', initNumberInput, cleanupNumberInput);
146
+ }
146
147
  }