@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
@@ -0,0 +1,263 @@
1
+ /**
2
+ * KupolaPagination - Standalone pagination component
3
+ * Works with useDeps or plain data
4
+ */
5
+
6
+ import { ref } from './data-bind.js';
7
+
8
+ class KupolaPagination {
9
+ constructor(element, options = {}) {
10
+ this.element = typeof element === 'string' ? document.querySelector(element) : element;
11
+ this.options = options;
12
+
13
+ // State
14
+ this._current = options.current || 1;
15
+ this._total = options.total || 0;
16
+ this._pageSize = options.pageSize || 10;
17
+ this._maxPages = options.maxPages || 7;
18
+ this._showTotal = options.showTotal !== false;
19
+ this._showSizeChanger = options.showSizeChanger || false;
20
+ this._pageSizes = options.pageSizes || [10, 20, 50, 100];
21
+ this._simple = options.simple || false;
22
+
23
+ // Refs for reactive integration
24
+ this.current = ref(this._current);
25
+ this.total = ref(this._total);
26
+
27
+ // Callbacks
28
+ this.onChange = options.onChange || null;
29
+ this.onPageSizeChange = options.onPageSizeChange || null;
30
+
31
+ this._init();
32
+ }
33
+
34
+ _init() {
35
+ this.element.classList.add('kupola-pagination');
36
+ this.render();
37
+ }
38
+
39
+ get totalPages() {
40
+ return Math.max(1, Math.ceil(this._total / this._pageSize));
41
+ }
42
+
43
+ setCurrent(page) {
44
+ page = Math.max(1, Math.min(page, this.totalPages));
45
+ if (page === this._current) return;
46
+ this._current = page;
47
+ this.current.value = page;
48
+ if (this.onChange) this.onChange(page, this._pageSize);
49
+ this.render();
50
+ }
51
+
52
+ setTotal(total) {
53
+ if (total && typeof total === 'object' && 'value' in total) {
54
+ this._total = total.value || 0;
55
+ total._subscribers?.add((val) => {
56
+ this._total = val || 0;
57
+ if (this._current > this.totalPages) {
58
+ this.setCurrent(this.totalPages);
59
+ } else {
60
+ this.render();
61
+ }
62
+ });
63
+ } else {
64
+ this._total = total;
65
+ }
66
+ this.total.value = this._total;
67
+ this.render();
68
+ }
69
+
70
+ setPageSize(size) {
71
+ this._pageSize = size;
72
+ this._current = 1;
73
+ this.current.value = 1;
74
+ if (this.onPageSizeChange) this.onPageSizeChange(size, this._current);
75
+ this.render();
76
+ }
77
+
78
+ render() {
79
+ const el = this.element;
80
+ el.innerHTML = '';
81
+
82
+ if (this._total <= 0) return;
83
+
84
+ if (this._simple) {
85
+ this._renderSimple(el);
86
+ } else {
87
+ this._renderFull(el);
88
+ }
89
+ }
90
+
91
+ _renderSimple(el) {
92
+ const total = this.totalPages;
93
+
94
+ const prev = this._btn('‹', () => this.setCurrent(this._current - 1));
95
+ prev.disabled = this._current <= 1;
96
+ el.appendChild(prev);
97
+
98
+ const info = document.createElement('span');
99
+ info.className = 'kupola-pagination-simple-info';
100
+ info.textContent = `${this._current} / ${total}`;
101
+ el.appendChild(info);
102
+
103
+ const next = this._btn('›', () => this.setCurrent(this._current + 1));
104
+ next.disabled = this._current >= total;
105
+ el.appendChild(next);
106
+ }
107
+
108
+ _renderFull(el) {
109
+ const total = this.totalPages;
110
+
111
+ // Total info
112
+ if (this._showTotal) {
113
+ const info = document.createElement('span');
114
+ info.className = 'kupola-pagination-total';
115
+ info.textContent = `共 ${this._total} 条`;
116
+ el.appendChild(info);
117
+ }
118
+
119
+ // Size changer
120
+ if (this._showSizeChanger) {
121
+ const select = document.createElement('select');
122
+ select.className = 'kupola-pagination-size';
123
+ this._pageSizes.forEach(size => {
124
+ const opt = document.createElement('option');
125
+ opt.value = size;
126
+ opt.textContent = `${size} 条/页`;
127
+ if (size === this._pageSize) opt.selected = true;
128
+ select.appendChild(opt);
129
+ });
130
+ select.addEventListener('change', () => this.setPageSize(parseInt(select.value)));
131
+ el.appendChild(select);
132
+ }
133
+
134
+ // Page buttons container
135
+ const pages = document.createElement('div');
136
+ pages.className = 'kupola-pagination-pages';
137
+
138
+ // Prev
139
+ const prev = this._btn('‹', () => this.setCurrent(this._current - 1));
140
+ prev.disabled = this._current <= 1;
141
+ pages.appendChild(prev);
142
+
143
+ // Page numbers
144
+ this._getPageRange().forEach(p => {
145
+ if (p === '...') {
146
+ const span = document.createElement('span');
147
+ span.className = 'kupola-pagination-ellipsis';
148
+ span.textContent = '···';
149
+ pages.appendChild(span);
150
+ } else {
151
+ const btn = this._btn(p, () => this.setCurrent(p));
152
+ if (p === this._current) btn.classList.add('active');
153
+ pages.appendChild(btn);
154
+ }
155
+ });
156
+
157
+ // Next
158
+ const next = this._btn('›', () => this.setCurrent(this._current + 1));
159
+ next.disabled = this._current >= total;
160
+ pages.appendChild(next);
161
+
162
+ el.appendChild(pages);
163
+
164
+ // Jumper
165
+ if (total > 10) {
166
+ const jumper = document.createElement('span');
167
+ jumper.className = 'kupola-pagination-jumper';
168
+ jumper.innerHTML = '跳至 <input type="number" min="1" max="' + total + '" value="' + this._current + '"> 页';
169
+ const input = jumper.querySelector('input');
170
+ input.addEventListener('change', () => {
171
+ const page = parseInt(input.value);
172
+ if (page >= 1 && page <= total) {
173
+ this.setCurrent(page);
174
+ }
175
+ });
176
+ input.addEventListener('keydown', (e) => {
177
+ if (e.key === 'Enter') {
178
+ const page = parseInt(input.value);
179
+ if (page >= 1 && page <= total) {
180
+ this.setCurrent(page);
181
+ }
182
+ }
183
+ });
184
+ el.appendChild(jumper);
185
+ }
186
+ }
187
+
188
+ _btn(text, onClick) {
189
+ const btn = document.createElement('button');
190
+ btn.className = 'kupola-pagination-btn';
191
+ btn.textContent = text;
192
+ btn.type = 'button';
193
+ btn.addEventListener('click', onClick);
194
+ return btn;
195
+ }
196
+
197
+ _getPageRange() {
198
+ const total = this.totalPages;
199
+ const max = this._maxPages;
200
+
201
+ if (total <= max) {
202
+ return Array.from({ length: total }, (_, i) => i + 1);
203
+ }
204
+
205
+ const range = [];
206
+ const half = Math.floor(max / 2);
207
+
208
+ if (this._current <= half + 1) {
209
+ for (let i = 1; i <= max - 2; i++) range.push(i);
210
+ range.push('...', total);
211
+ } else if (this._current >= total - half) {
212
+ range.push(1, '...');
213
+ for (let i = total - max + 3; i <= total; i++) range.push(i);
214
+ } else {
215
+ range.push(1, '...');
216
+ for (let i = this._current - half + 2; i <= this._current + half - 2; i++) range.push(i);
217
+ range.push('...', total);
218
+ }
219
+
220
+ return range;
221
+ }
222
+
223
+ destroy() {
224
+ this.element.innerHTML = '';
225
+ this.element.classList.remove('kupola-pagination');
226
+ }
227
+ }
228
+
229
+ // CSS styles
230
+ let stylesInjected = false;
231
+ function injectPaginationStyles() {
232
+ if (stylesInjected || typeof document === 'undefined') return;
233
+ const style = document.createElement('style');
234
+ style.textContent = `
235
+ .kupola-pagination { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
236
+ .kupola-pagination-pages { display: flex; gap: 4px; align-items: center; }
237
+ .kupola-pagination-btn { min-width: 32px; height: 32px; border: 1px solid #d9d9d9; border-radius: 4px; background: #fff; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; transition: all 0.2s; }
238
+ .kupola-pagination-btn:hover:not(:disabled):not(.active) { border-color: #1890ff; color: #1890ff; }
239
+ .kupola-pagination-btn.active { background: #1890ff; color: #fff; border-color: #1890ff; }
240
+ .kupola-pagination-btn:disabled { opacity: 0.4; cursor: not-allowed; }
241
+ .kupola-pagination-ellipsis { padding: 0 4px; color: #999; user-select: none; }
242
+ .kupola-pagination-total { color: #666; font-size: 14px; }
243
+ .kupola-pagination-size { padding: 4px 8px; border: 1px solid #d9d9d9; border-radius: 4px; font-size: 13px; }
244
+ .kupola-pagination-simple-info { padding: 0 8px; font-size: 14px; color: #333; }
245
+ .kupola-pagination-jumper { font-size: 14px; color: #666; }
246
+ .kupola-pagination-jumper input { width: 50px; height: 28px; margin: 0 4px; padding: 0 8px; border: 1px solid #d9d9d9; border-radius: 4px; text-align: center; font-size: 13px; }
247
+ .kupola-pagination-jumper input:focus { outline: none; border-color: #1890ff; }
248
+ `;
249
+ document.head.appendChild(style);
250
+ stylesInjected = true;
251
+ }
252
+
253
+ function initPagination(element, options) {
254
+ injectPaginationStyles();
255
+ return new KupolaPagination(element, options);
256
+ }
257
+
258
+ export { KupolaPagination, initPagination };
259
+
260
+ if (typeof window !== 'undefined') {
261
+ window.KupolaPagination = KupolaPagination;
262
+ window.initPagination = initPagination;
263
+ }
package/js/registry.js CHANGED
@@ -1,4 +1,7 @@
1
- class KupolaComponentRegistry {
1
+ import { KupolaComponent, applyMixin } from './component.js';
2
+ import { kupolaInitializer } from './initializer.js';
3
+
4
+ export class KupolaComponentRegistry {
2
5
  constructor() {
3
6
  this.components = new Map();
4
7
  this.lazyComponents = new Map();
@@ -10,7 +13,7 @@ class KupolaComponentRegistry {
10
13
  }
11
14
 
12
15
  register(name, componentClass) {
13
- if (!(componentClass.prototype instanceof window.KupolaComponent)) {
16
+ if (!(componentClass.prototype instanceof KupolaComponent)) {
14
17
  throw new Error(`Component ${name} must extend KupolaComponent`);
15
18
  }
16
19
  this.components.set(name, componentClass);
@@ -48,7 +51,7 @@ class KupolaComponentRegistry {
48
51
  try {
49
52
  const result = await loader();
50
53
  const componentClass = result.default || result;
51
- if (!(componentClass.prototype instanceof window.KupolaComponent)) {
54
+ if (!(componentClass.prototype instanceof KupolaComponent)) {
52
55
  throw new Error(`Component ${name} must extend KupolaComponent`);
53
56
  }
54
57
  this.loadedComponents.set(name, componentClass);
@@ -70,8 +73,8 @@ class KupolaComponentRegistry {
70
73
  useMixin(componentClass, ...mixinNames) {
71
74
  mixinNames.forEach(name => {
72
75
  const mixin = this.mixins.get(name);
73
- if (mixin && window.applyMixin) {
74
- window.applyMixin(componentClass, mixin);
76
+ if (mixin) {
77
+ applyMixin(componentClass, mixin);
75
78
  }
76
79
  });
77
80
  }
@@ -98,8 +101,8 @@ class KupolaComponentRegistry {
98
101
  try {
99
102
  const componentName = element.getAttribute('data-component');
100
103
 
101
- if (window.kupolaInitializer && componentName) {
102
- const initializer = window.kupolaInitializer.get(componentName);
104
+ if (componentName) {
105
+ const initializer = kupolaInitializer.get(componentName);
103
106
  if (initializer) {
104
107
  try {
105
108
  await initializer(element);
@@ -127,11 +130,11 @@ class KupolaComponentRegistry {
127
130
 
128
131
  const mixinNames = element.getAttribute('data-mixins');
129
132
  const componentClass = ComponentClass;
130
- if (mixinNames && window.applyMixin) {
133
+ if (mixinNames) {
131
134
  mixinNames.split(',').forEach(name => {
132
135
  const mixin = this.mixins.get(name.trim());
133
136
  if (mixin) {
134
- window.applyMixin(componentClass, mixin);
137
+ applyMixin(componentClass, mixin);
135
138
  }
136
139
  });
137
140
  }
@@ -152,15 +155,26 @@ class KupolaComponentRegistry {
152
155
  mutations.forEach(mutation => {
153
156
  mutation.addedNodes.forEach(node => {
154
157
  if (node.nodeType === Node.ELEMENT_NODE) {
158
+ // Try registry first (class components via data-component)
155
159
  if (node.hasAttribute('data-component')) {
156
160
  this._upgradeElement(node).catch(e => console.error(e));
157
161
  }
158
162
  this._upgradeElements(node).catch(e => console.error(e));
163
+ // Also try initializer (function components via data-* attributes / CSS classes)
164
+ kupolaInitializer.initialize(node).catch(() => {});
165
+ // Check children too
166
+ const selector = kupolaInitializer._buildSelector();
167
+ if (selector) {
168
+ node.querySelectorAll?.(selector).forEach(child => {
169
+ kupolaInitializer.initialize(child).catch(() => {});
170
+ });
171
+ }
159
172
  }
160
173
  });
161
174
 
162
175
  mutation.removedNodes.forEach(node => {
163
176
  if (node.nodeType === Node.ELEMENT_NODE) {
177
+ // Cleanup registry instances
164
178
  const instance = this.instances.get(node);
165
179
  if (instance) {
166
180
  instance.unmount();
@@ -173,6 +187,11 @@ class KupolaComponentRegistry {
173
187
  this.instances.delete(child);
174
188
  }
175
189
  });
190
+ // Cleanup initializer instances
191
+ kupolaInitializer.cleanup(node);
192
+ node.querySelectorAll?.('*').forEach(child => {
193
+ kupolaInitializer.cleanup(child);
194
+ });
176
195
  }
177
196
  });
178
197
  });
@@ -198,8 +217,6 @@ class KupolaComponentRegistry {
198
217
  }
199
218
  }
200
219
 
201
- if (typeof module !== 'undefined' && module.exports) {
202
- module.exports = { KupolaComponentRegistry };
203
- } else {
220
+ if (typeof window !== 'undefined') {
204
221
  window.KupolaComponentRegistry = KupolaComponentRegistry;
205
222
  }