@kupola/kupola 1.2.0 → 1.4.0

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 (111) 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/css/components-ext.css +157 -0
  8. package/css/components.css +69 -0
  9. package/css/theme-dark.css +5 -5
  10. package/css/utilities.css +119 -1
  11. package/dist/css/accessibility.css +119 -0
  12. package/dist/css/animations.css +224 -0
  13. package/dist/css/brand-themes.css +300 -0
  14. package/dist/css/colors_and_type.css +441 -0
  15. package/dist/css/components-ext.css +4165 -0
  16. package/dist/css/components.css +1483 -0
  17. package/dist/css/kupola.css +1 -12
  18. package/dist/css/kupola.min.css +1 -0
  19. package/dist/css/responsive.css +697 -0
  20. package/dist/css/scaffold.css +145 -0
  21. package/dist/css/states.css +316 -0
  22. package/dist/css/theme-dark.css +296 -0
  23. package/dist/css/theme-light.css +296 -0
  24. package/dist/css/utilities.css +171 -0
  25. package/dist/icons.svg +284 -0
  26. package/dist/kupola.cjs.js +17409 -257
  27. package/dist/kupola.cjs.js.map +1 -1
  28. package/dist/kupola.css +9000 -0
  29. package/dist/kupola.esm.js +17183 -7597
  30. package/dist/kupola.esm.js.map +1 -1
  31. package/dist/kupola.min.css +1 -0
  32. package/dist/kupola.min.js +2 -0
  33. package/dist/kupola.min.js.map +1 -0
  34. package/dist/kupola.umd.js +17415 -257
  35. package/dist/kupola.umd.js.map +1 -1
  36. package/dist/plugins/vite-plugin-kupola.js +120 -0
  37. package/dist/types/kupola.d.ts +421 -323
  38. package/js/calendar.js +334 -25
  39. package/js/carousel.js +182 -48
  40. package/js/collapse.js +148 -34
  41. package/js/color-picker.js +416 -108
  42. package/js/component.js +8 -19
  43. package/js/countdown.js +9 -8
  44. package/js/data-bind.js +73 -16
  45. package/js/datepicker.js +488 -110
  46. package/js/depends.js +710 -0
  47. package/js/dialog.js +4 -2
  48. package/js/drawer.js +172 -8
  49. package/js/dropdown.js +272 -17
  50. package/js/dynamic-tags.js +156 -40
  51. package/js/fileupload.js +9 -8
  52. package/js/form.js +280 -254
  53. package/js/global-events.js +281 -188
  54. package/js/heatmap.js +10 -7
  55. package/js/i18n.js +18 -10
  56. package/js/icons.js +141 -161
  57. package/js/image-preview.js +146 -2
  58. package/js/initializer.js +151 -71
  59. package/js/kupola-core.js +123 -45
  60. package/js/kupola-lifecycle.js +13 -11
  61. package/js/message.js +8 -1
  62. package/js/modal.js +207 -59
  63. package/js/notification.js +8 -1
  64. package/js/numberinput.js +9 -8
  65. package/js/pagination.js +263 -0
  66. package/js/registry.js +29 -12
  67. package/js/select.js +482 -27
  68. package/js/slide-captcha.js +11 -2
  69. package/js/slider.js +442 -25
  70. package/js/statcard.js +9 -7
  71. package/js/table.js +1210 -0
  72. package/js/tag.js +268 -14
  73. package/js/theme-standalone.js +88 -0
  74. package/js/theme.js +14 -43
  75. package/js/timepicker.js +335 -66
  76. package/js/tooltip.js +317 -86
  77. package/js/utils.js +6 -2
  78. package/js/validation.js +6 -2
  79. package/js/virtual-list.js +11 -7
  80. package/js/web-components.js +288 -0
  81. package/package.json +81 -67
  82. package/plugins/vite-plugin-kupola.js +120 -0
  83. package/scripts/build-css.cjs +113 -0
  84. package/scripts/build-svg-sprite.cjs +107 -0
  85. package/types/kupola.d.ts +421 -323
  86. package/CHANGELOG.md +0 -130
  87. package/INTEGRATION.md +0 -440
  88. package/PROJECT_SUMMARY.md +0 -312
  89. package/SKILL.md +0 -572
  90. package/dist/utils/utils/Kupola.cs +0 -77
  91. package/dist/utils/utils/Kupola.java +0 -104
  92. package/dist/utils/utils/kupola.go +0 -120
  93. package/dist/utils/utils/kupola.js +0 -63
  94. package/dist/utils/utils/kupola.py +0 -1392
  95. package/dist/utils/utils/kupola.rb +0 -69
  96. package/js/composition-api.js +0 -458
  97. package/js/error-handler.js +0 -181
  98. package/js/http.js +0 -419
  99. package/js/kupola-devtools.js +0 -598
  100. package/js/performance.js +0 -250
  101. package/js/router.js +0 -396
  102. package/js/security.js +0 -189
  103. package/js/test-utils.js +0 -251
  104. package/templates/base.html +0 -30
  105. package/templates/base_dashboard.html +0 -99
  106. package/utils/Kupola.cs +0 -77
  107. package/utils/Kupola.java +0 -104
  108. package/utils/kupola.go +0 -120
  109. package/utils/kupola.js +0 -63
  110. package/utils/kupola.py +0 -1392
  111. 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
  }