@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
package/js/performance.js DELETED
@@ -1,250 +0,0 @@
1
- class KupolaPerformance {
2
- constructor() {
3
- this.metrics = new Map();
4
- this.timers = new Map();
5
- this.observers = [];
6
- this.enabled = false;
7
- this.thresholds = {
8
- render: 16,
9
- mount: 100,
10
- update: 50,
11
- http: 3000
12
- };
13
- }
14
-
15
- init() {
16
- this.enabled = true;
17
- this._setupObservers();
18
- this._measureNavigation();
19
- }
20
-
21
- _setupObservers() {
22
- if ('PerformanceObserver' in window) {
23
- const paintObserver = new PerformanceObserver((entryList) => {
24
- entryList.getEntries().forEach(entry => {
25
- this._recordMetric('paint', {
26
- name: entry.name,
27
- startTime: entry.startTime,
28
- duration: entry.duration
29
- });
30
- });
31
- });
32
- paintObserver.observe({ type: 'paint', buffered: true });
33
- this.observers.push(paintObserver);
34
-
35
- const resourceObserver = new PerformanceObserver((entryList) => {
36
- entryList.getEntries().forEach(entry => {
37
- this._recordMetric('resource', {
38
- name: entry.name,
39
- type: entry.initiatorType,
40
- duration: entry.duration,
41
- size: entry.transferSize,
42
- startTime: entry.startTime
43
- });
44
- });
45
- });
46
- resourceObserver.observe({ type: 'resource', buffered: true });
47
- this.observers.push(resourceObserver);
48
-
49
- const longTaskObserver = new PerformanceObserver((entryList) => {
50
- entryList.getEntries().forEach(entry => {
51
- this._recordMetric('longtask', {
52
- duration: entry.duration,
53
- startTime: entry.startTime
54
- });
55
- });
56
- });
57
- longTaskObserver.observe({ type: 'longtask', buffered: true });
58
- this.observers.push(longTaskObserver);
59
- }
60
- }
61
-
62
- _measureNavigation() {
63
- if ('performance' in window) {
64
- const nav = performance.getEntriesByType('navigation')[0];
65
- if (nav) {
66
- this._recordMetric('navigation', {
67
- domContentLoaded: nav.domContentLoadedEventEnd - nav.fetchStart,
68
- load: nav.loadEventEnd - nav.fetchStart,
69
- firstByte: nav.responseStart - nav.requestStart,
70
- redirectCount: nav.redirectCount
71
- });
72
- }
73
- }
74
- }
75
-
76
- startTimer(name, context = {}) {
77
- if (!this.enabled) return;
78
-
79
- this.timers.set(name, {
80
- startTime: performance.now(),
81
- context
82
- });
83
- }
84
-
85
- stopTimer(name) {
86
- if (!this.enabled) return null;
87
-
88
- const timer = this.timers.get(name);
89
- if (!timer) return null;
90
-
91
- const duration = performance.now() - timer.startTime;
92
- this.timers.delete(name);
93
-
94
- this._recordMetric('timer', {
95
- name,
96
- duration,
97
- ...timer.context
98
- });
99
-
100
- return duration;
101
- }
102
-
103
- _recordMetric(type, data) {
104
- if (!this.enabled) return;
105
-
106
- const metric = {
107
- type,
108
- timestamp: Date.now(),
109
- ...data
110
- };
111
-
112
- if (!this.metrics.has(type)) {
113
- this.metrics.set(type, []);
114
- }
115
- this.metrics.get(type).push(metric);
116
- }
117
-
118
- measure(fn, name, context = {}) {
119
- if (!this.enabled) return fn();
120
-
121
- this.startTimer(name, context);
122
-
123
- let result;
124
- let error;
125
-
126
- try {
127
- result = fn();
128
- } catch (e) {
129
- error = e;
130
- }
131
-
132
- const duration = this.stopTimer(name);
133
-
134
- if (error) {
135
- throw error;
136
- }
137
-
138
- return result;
139
- }
140
-
141
- measureAsync(fn, name, context = {}) {
142
- if (!this.enabled) return fn();
143
-
144
- this.startTimer(name, context);
145
-
146
- return fn().then(result => {
147
- this.stopTimer(name);
148
- return result;
149
- }).catch(error => {
150
- this.stopTimer(name);
151
- throw error;
152
- });
153
- }
154
-
155
- getMetrics(type) {
156
- if (type) {
157
- return this.metrics.get(type) || [];
158
- }
159
- return Array.from(this.metrics.entries());
160
- }
161
-
162
- getSummary() {
163
- const summary = {
164
- navigation: null,
165
- paint: null,
166
- timers: [],
167
- resources: [],
168
- longTasks: []
169
- };
170
-
171
- if (this.metrics.has('navigation')) {
172
- summary.navigation = this.metrics.get('navigation')[0];
173
- }
174
-
175
- if (this.metrics.has('paint')) {
176
- summary.paint = this.metrics.get('paint');
177
- }
178
-
179
- if (this.metrics.has('timer')) {
180
- summary.timers = this.metrics.get('timer');
181
- }
182
-
183
- if (this.metrics.has('resource')) {
184
- summary.resources = this.metrics.get('resource');
185
- }
186
-
187
- if (this.metrics.has('longtask')) {
188
- summary.longTasks = this.metrics.get('longtask');
189
- }
190
-
191
- return summary;
192
- }
193
-
194
- getPerformanceScore() {
195
- const summary = this.getSummary();
196
- let score = 100;
197
-
198
- if (summary.navigation) {
199
- if (summary.navigation.load > 3000) score -= 20;
200
- else if (summary.navigation.load > 2000) score -= 10;
201
-
202
- if (summary.navigation.domContentLoaded > 1500) score -= 15;
203
- else if (summary.navigation.domContentLoaded > 1000) score -= 5;
204
- }
205
-
206
- if (summary.paint) {
207
- const fcp = summary.paint.find(p => p.name === 'first-contentful-paint');
208
- if (fcp && fcp.startTime > 2000) score -= 20;
209
- else if (fcp && fcp.startTime > 1000) score -= 10;
210
- }
211
-
212
- if (summary.longTasks.length > 0) {
213
- score -= summary.longTasks.length * 10;
214
- }
215
-
216
- return Math.max(0, score);
217
- }
218
-
219
- logSummary() {
220
- const summary = this.getSummary();
221
- const score = this.getPerformanceScore();
222
-
223
- console.group('[KupolaPerformance] Summary');
224
- console.log('Score:', score);
225
- console.log('Navigation:', summary.navigation);
226
- console.log('Paint:', summary.paint);
227
- console.log('Long Tasks:', summary.longTasks.length);
228
- console.groupEnd();
229
- }
230
-
231
- clear() {
232
- this.metrics.clear();
233
- this.timers.clear();
234
- }
235
-
236
- destroy() {
237
- this.observers.forEach(observer => {
238
- observer.disconnect();
239
- });
240
- this.observers = [];
241
- this.clear();
242
- this.enabled = false;
243
- }
244
- }
245
-
246
- const kupolaPerformance = new KupolaPerformance();
247
- window.kupolaPerformance = kupolaPerformance;
248
- window.KupolaPerformance = KupolaPerformance;
249
-
250
- export default KupolaPerformance;
package/js/router.js DELETED
@@ -1,396 +0,0 @@
1
- class KupolaRouter {
2
- constructor(options = {}) {
3
- this.mode = options.mode || 'hash';
4
- this.routes = options.routes || [];
5
- this.base = options.base || '';
6
- this.currentRoute = null;
7
- this.beforeEachHandlers = [];
8
- this.afterEachHandlers = [];
9
- this.isStarted = false;
10
- this.animationClass = 'fade';
11
- this.componentCache = new Map();
12
- this._routeHandler = () => this._handleRoute();
13
-
14
- this._setupRoutes();
15
- this._bindEvents();
16
- }
17
-
18
- _setupRoutes() {
19
- this.routeMap = new Map();
20
- this._registerRoutes(this.routes, '');
21
- }
22
-
23
- _registerRoutes(routes, parentPath) {
24
- routes.forEach(route => {
25
- const fullPath = route.path.startsWith('/')
26
- ? route.path
27
- : parentPath + (parentPath && !route.path.startsWith('/') ? '/' : '') + route.path;
28
- const pathRegex = this._pathToRegex(fullPath);
29
- this.routeMap.set(fullPath, { ...route, regex: pathRegex, parentPath });
30
-
31
- if (route.children && route.children.length > 0) {
32
- this._registerRoutes(route.children, fullPath);
33
- }
34
- });
35
- }
36
-
37
- _pathToRegex(path) {
38
- const regexStr = path
39
- .replace(/:(\w+)/g, '([^/]+)')
40
- .replace(/\*/g, '.*');
41
- return new RegExp(`^${regexStr}$`);
42
- }
43
-
44
- _bindEvents() {
45
- if (this.mode === 'hash') {
46
- window.addEventListener('hashchange', this._routeHandler);
47
- } else {
48
- window.addEventListener('popstate', this._routeHandler);
49
- }
50
- }
51
-
52
- _handleRoute() {
53
- const path = this._getCurrentPath();
54
- this.navigate(path);
55
- }
56
-
57
- _getCurrentPath() {
58
- if (this.mode === 'hash') {
59
- return location.hash.slice(1) || '/';
60
- }
61
- return location.pathname.replace(this.base, '') || '/';
62
- }
63
-
64
- async navigate(path, replace = false) {
65
- const route = this._matchRoute(path);
66
- if (!route) return;
67
-
68
- const from = this.currentRoute;
69
-
70
- for (const handler of this.beforeEachHandlers) {
71
- const result = await handler(route, from);
72
- if (result === false) return;
73
- }
74
-
75
- this.currentRoute = route;
76
- this._updateURL(path, replace);
77
- await this._renderRoute(route);
78
-
79
- for (const handler of this.afterEachHandlers) {
80
- handler(route);
81
- }
82
- }
83
-
84
- _matchRoute(path) {
85
- for (const [, route] of this.routeMap) {
86
- const match = path.match(route.regex);
87
- if (match) {
88
- const params = {};
89
- const paramNames = route.path.match(/:(\w+)/g) || [];
90
- paramNames.forEach((name, index) => {
91
- params[name.slice(1)] = match[index + 1];
92
- });
93
-
94
- const query = this._parseQuery();
95
-
96
- return {
97
- ...route,
98
- params,
99
- query,
100
- fullPath: path
101
- };
102
- }
103
- }
104
- return null;
105
- }
106
-
107
- _parseQuery() {
108
- const search = location.search.slice(1);
109
- const params = {};
110
- if (search) {
111
- search.split('&').forEach(pair => {
112
- const [key, value] = pair.split('=');
113
- params[key] = decodeURIComponent(value || '');
114
- });
115
- }
116
- return params;
117
- }
118
-
119
- _updateURL(path, replace) {
120
- if (this.mode === 'hash') {
121
- const url = `#${path}`;
122
- if (replace) {
123
- location.replace(url);
124
- } else {
125
- location.hash = path;
126
- }
127
- } else {
128
- const url = this.base + path + location.search;
129
- if (replace) {
130
- history.replaceState({}, '', url);
131
- } else {
132
- history.pushState({}, '', url);
133
- }
134
- }
135
- }
136
-
137
- async _renderRoute(route) {
138
- if (route.parentPath && route.parentPath !== '') {
139
- await this._renderNestedRoute(route);
140
- } else {
141
- await this._renderRootRoute(route);
142
- }
143
- }
144
-
145
- async _renderRootRoute(route) {
146
- const container = document.querySelector('[data-router-view]');
147
- if (!container || !route.component) return;
148
-
149
- this._cleanupContainerComponents(container);
150
-
151
- container.classList.add('router-view-leave');
152
- container.classList.remove('router-view-enter');
153
-
154
- await this._waitForAnimation(container);
155
-
156
- const componentName = await this._resolveComponent(route.component);
157
- if (!componentName) return;
158
-
159
- const componentElement = document.createElement('div');
160
- componentElement.setAttribute('data-component', componentName);
161
- componentElement.classList.add('router-view-enter');
162
-
163
- Object.keys(route.params).forEach(key => {
164
- componentElement.setAttribute(`data-prop-${key}`, route.params[key]);
165
- });
166
-
167
- container.innerHTML = '';
168
- container.appendChild(componentElement);
169
-
170
- if (window.kupolaRegistry) {
171
- await window.kupolaRegistry.bootstrap(container);
172
- }
173
-
174
- setTimeout(() => {
175
- container.classList.remove('router-view-leave');
176
- componentElement.classList.remove('router-view-enter');
177
- }, 10);
178
- }
179
-
180
- async _renderNestedRoute(route) {
181
- const parentRoute = this.routeMap.get(route.parentPath);
182
- if (!parentRoute) return;
183
-
184
- const rootContainer = document.querySelector('[data-router-view]');
185
- if (!rootContainer) return;
186
-
187
- const existingParent = document.querySelector(`[data-component="${parentRoute.component}"]`);
188
-
189
- if (!existingParent) {
190
- this._cleanupContainerComponents(rootContainer);
191
-
192
- rootContainer.classList.add('router-view-leave');
193
- rootContainer.classList.remove('router-view-enter');
194
-
195
- await this._waitForAnimation(rootContainer);
196
-
197
- const parentName = await this._resolveComponent(parentRoute.component);
198
- if (!parentName) return;
199
-
200
- const parentElement = document.createElement('div');
201
- parentElement.setAttribute('data-component', parentName);
202
-
203
- rootContainer.innerHTML = '';
204
- rootContainer.appendChild(parentElement);
205
-
206
- if (window.kupolaRegistry) {
207
- await window.kupolaRegistry.bootstrap(rootContainer);
208
- }
209
-
210
- setTimeout(() => {
211
- rootContainer.classList.remove('router-view-leave');
212
- }, 50);
213
-
214
- await this._renderChildComponent(route);
215
- } else {
216
- await this._renderChildComponent(route);
217
- }
218
- }
219
-
220
- async _renderChildComponent(route) {
221
- const parentElement = document.querySelector(`[data-component="${this._getParentComponent(route.parentPath)}"]`);
222
- if (!parentElement) return;
223
-
224
- const container = parentElement.querySelector('[data-router-view]');
225
- if (!container || !route.component) return;
226
-
227
- const componentName = await this._resolveComponent(route.component);
228
- if (!componentName) return;
229
-
230
- const componentElement = document.createElement('div');
231
- componentElement.setAttribute('data-component', componentName);
232
- componentElement.classList.add('router-view-enter');
233
-
234
- Object.keys(route.params).forEach(key => {
235
- componentElement.setAttribute(`data-prop-${key}`, route.params[key]);
236
- });
237
-
238
- container.innerHTML = '';
239
- container.appendChild(componentElement);
240
-
241
- if (window.kupolaRegistry) {
242
- await window.kupolaRegistry.bootstrap(container);
243
- }
244
-
245
- setTimeout(() => {
246
- componentElement.classList.remove('router-view-enter');
247
- }, 10);
248
- }
249
-
250
- async _resolveComponent(component) {
251
- if (typeof component === 'function') {
252
- const cacheKey = component.toString();
253
- if (this.componentCache.has(cacheKey)) {
254
- return this.componentCache.get(cacheKey);
255
- }
256
-
257
- try {
258
- const result = await component();
259
- const componentClass = result.default || result;
260
-
261
- const componentName = `lazy-${Math.random().toString(36).substr(2, 9)}`;
262
-
263
- if (window.kupolaRegistry) {
264
- window.kupolaRegistry.register(componentName, componentClass);
265
- }
266
-
267
- this.componentCache.set(cacheKey, componentName);
268
- return componentName;
269
- } catch (e) {
270
- console.error('Failed to load lazy component:', e);
271
- return null;
272
- }
273
- }
274
-
275
- if (typeof component === 'string' && component.startsWith('lazy:')) {
276
- const componentName = component.slice(5);
277
- if (window.kupolaRegistry) {
278
- try {
279
- await window.kupolaRegistry.getAsync(componentName);
280
- } catch (e) {
281
- console.error(`Failed to load lazy component ${componentName}:`, e);
282
- return null;
283
- }
284
- }
285
- return componentName;
286
- }
287
-
288
- return component;
289
- }
290
-
291
- _getParentComponent(parentPath) {
292
- for (const [path, route] of this.routeMap) {
293
- if (path === parentPath) {
294
- return route.component;
295
- }
296
- }
297
- return null;
298
- }
299
-
300
- setAnimation(name) {
301
- this.animationClass = name;
302
- }
303
-
304
- push(path) {
305
- this.navigate(path, false);
306
- }
307
-
308
- replace(path) {
309
- this.navigate(path, true);
310
- }
311
-
312
- go(delta) {
313
- history.go(delta);
314
- }
315
-
316
- back() {
317
- history.back();
318
- }
319
-
320
- forward() {
321
- history.forward();
322
- }
323
-
324
- beforeEach(handler) {
325
- this.beforeEachHandlers.push(handler);
326
- }
327
-
328
- afterEach(handler) {
329
- this.afterEachHandlers.push(handler);
330
- }
331
-
332
- _waitForAnimation(element) {
333
- return new Promise(resolve => {
334
- const transitionDuration = this._getTransitionDuration(element);
335
- if (transitionDuration > 0) {
336
- const cleanup = () => {
337
- element.removeEventListener('transitionend', cleanup);
338
- element.removeEventListener('animationend', cleanup);
339
- resolve();
340
- };
341
- element.addEventListener('transitionend', cleanup);
342
- element.addEventListener('animationend', cleanup);
343
- setTimeout(cleanup, transitionDuration + 100);
344
- } else {
345
- resolve();
346
- }
347
- });
348
- }
349
-
350
- _getTransitionDuration(element) {
351
- const style = window.getComputedStyle(element);
352
- const transitionDuration = parseFloat(style.transitionDuration) || 0;
353
- const animationDuration = parseFloat(style.animationDuration) || 0;
354
- return Math.max(transitionDuration, animationDuration) * 1000;
355
- }
356
-
357
- _cleanupContainerComponents(container) {
358
- const components = container.querySelectorAll('[data-component]');
359
- components.forEach(element => {
360
- const instance = element.__kupolaInstance;
361
- if (instance && typeof instance.unmount === 'function') {
362
- instance.unmount().catch(e => console.error(`Error unmounting component:`, e));
363
- }
364
- });
365
-
366
- if (window.kupolaInitializer) {
367
- const allElements = container.querySelectorAll('[data-component], [data-dropdown], [data-select], [data-datepicker], [data-timepicker], [data-slider], [data-carousel], [data-drawer], [data-modal], [data-dialog], [data-color-picker], [data-calendar], [data-slide-captcha], [data-heatmap]');
368
- allElements.forEach(element => {
369
- window.kupolaInitializer.cleanup(element);
370
- });
371
- }
372
- }
373
-
374
- destroy() {
375
- if (this.mode === 'hash') {
376
- window.removeEventListener('hashchange', this._routeHandler);
377
- } else {
378
- window.removeEventListener('popstate', this._routeHandler);
379
- }
380
- this.routes = [];
381
- this.routeMap.clear();
382
- this.beforeEachHandlers = [];
383
- this.afterEachHandlers = [];
384
- }
385
- }
386
-
387
- function createRouter(options) {
388
- return new KupolaRouter(options);
389
- }
390
-
391
- if (typeof module !== 'undefined' && module.exports) {
392
- module.exports = { KupolaRouter, createRouter };
393
- } else {
394
- window.KupolaRouter = KupolaRouter;
395
- window.createRouter = createRouter;
396
- }