@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/calendar.js CHANGED
@@ -1,5 +1,5 @@
1
1
  class Calendar {
2
- constructor(element) {
2
+ constructor(element, options = {}) {
3
3
  this.element = element;
4
4
  this.titleEl = element.querySelector('.ds-calendar__title');
5
5
  this.daysEl = element.querySelector('.ds-calendar__days');
@@ -13,6 +13,26 @@ class Calendar {
13
13
  }
14
14
 
15
15
  this.currentDate = new Date();
16
+ this.selectedDate = options.selectedDate ? new Date(options.selectedDate) : null;
17
+ this.rangeStart = options.rangeStart ? new Date(options.rangeStart) : null;
18
+ this.rangeEnd = options.rangeEnd ? new Date(options.rangeEnd) : null;
19
+ this.isRangeMode = options.rangeMode || element.hasAttribute('data-calendar-range');
20
+ this.viewMode = options.viewMode || element.getAttribute('data-calendar-view') || 'month'; // month | week
21
+ this.events = options.events || [];
22
+ this.i18n = options.i18n || {
23
+ months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
24
+ shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
25
+ weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
26
+ shortWeekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
27
+ today: 'Today',
28
+ selectRangeStart: 'Select start date',
29
+ selectRangeEnd: 'Select end date'
30
+ };
31
+ this.onSelect = options.onSelect || null;
32
+ this.onRangeSelect = options.onRangeSelect || null;
33
+ this.onChange = options.onChange || null;
34
+ this.onEventClick = options.onEventClick || null;
35
+
16
36
  this._init();
17
37
  }
18
38
 
@@ -20,18 +40,29 @@ class Calendar {
20
40
  this.render();
21
41
 
22
42
  const prevHandler = () => {
23
- this.currentDate.setMonth(this.currentDate.getMonth() - 1);
43
+ if (this.viewMode === 'week') {
44
+ this.currentDate.setDate(this.currentDate.getDate() - 7);
45
+ } else {
46
+ this.currentDate.setMonth(this.currentDate.getMonth() - 1);
47
+ }
24
48
  this.render();
49
+ this._emitChange();
25
50
  };
26
51
 
27
52
  const nextHandler = () => {
28
- this.currentDate.setMonth(this.currentDate.getMonth() + 1);
53
+ if (this.viewMode === 'week') {
54
+ this.currentDate.setDate(this.currentDate.getDate() + 7);
55
+ } else {
56
+ this.currentDate.setMonth(this.currentDate.getMonth() + 1);
57
+ }
29
58
  this.render();
59
+ this._emitChange();
30
60
  };
31
61
 
32
62
  const todayHandler = () => {
33
63
  this.currentDate = new Date();
34
64
  this.render();
65
+ this._emitChange();
35
66
  };
36
67
 
37
68
  if (this.prevBtn) {
@@ -50,11 +81,72 @@ class Calendar {
50
81
  }
51
82
  }
52
83
 
84
+ _emitChange() {
85
+ const data = {
86
+ date: this.currentDate,
87
+ selectedDate: this.selectedDate,
88
+ rangeStart: this.rangeStart,
89
+ rangeEnd: this.rangeEnd,
90
+ viewMode: this.viewMode
91
+ };
92
+ if (this.onChange) this.onChange(data);
93
+ this.element.dispatchEvent(new CustomEvent('kupola:calendar-change', { detail: data, bubbles: true }));
94
+ }
95
+
96
+ _formatDate(date) {
97
+ const year = date.getFullYear();
98
+ const month = String(date.getMonth() + 1).padStart(2, '0');
99
+ const day = String(date.getDate()).padStart(2, '0');
100
+ return `${year}-${month}-${day}`;
101
+ }
102
+
103
+ _isSameDay(date1, date2) {
104
+ if (!date1 || !date2) return false;
105
+ return this._formatDate(date1) === this._formatDate(date2);
106
+ }
107
+
108
+ _isDateInRange(date) {
109
+ if (!this.rangeStart || !this.rangeEnd) return false;
110
+ const dateStr = this._formatDate(date);
111
+ const startStr = this._formatDate(this.rangeStart);
112
+ const endStr = this._formatDate(this.rangeEnd);
113
+ return dateStr >= startStr && dateStr <= endStr;
114
+ }
115
+
116
+ _isRangeStart(date) {
117
+ return this._isSameDay(date, this.rangeStart);
118
+ }
119
+
120
+ _isRangeEnd(date) {
121
+ return this._isSameDay(date, this.rangeEnd);
122
+ }
123
+
124
+ _getEventsForDate(date) {
125
+ const dateStr = this._formatDate(date);
126
+ return this.events.filter(e => {
127
+ const eventStart = e.date || e.start;
128
+ const eventEnd = e.end;
129
+ if (!eventStart) return false;
130
+ const startStr = typeof eventStart === 'string' ? eventStart : this._formatDate(eventStart);
131
+ if (!eventEnd) return startStr === dateStr;
132
+ const endStr = typeof eventEnd === 'string' ? eventEnd : this._formatDate(eventEnd);
133
+ return dateStr >= startStr && dateStr <= endStr;
134
+ });
135
+ }
136
+
53
137
  render() {
54
138
  const year = this.currentDate.getFullYear();
55
139
  const month = this.currentDate.getMonth();
56
140
 
57
- this.titleEl.textContent = `${year} ${['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][month]}`;
141
+ if (this.viewMode === 'week') {
142
+ this._renderWeekView(year, month);
143
+ } else {
144
+ this._renderMonthView(year, month);
145
+ }
146
+ }
147
+
148
+ _renderMonthView(year, month) {
149
+ this.titleEl.textContent = `${year} ${this.i18n.months[month]}`;
58
150
 
59
151
  const firstDay = new Date(year, month, 1).getDay();
60
152
  const daysInMonth = new Date(year, month + 1, 0).getDate();
@@ -68,23 +160,165 @@ class Calendar {
68
160
  }
69
161
 
70
162
  const today = new Date();
71
- const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
163
+ const todayStr = this._formatDate(today);
72
164
 
73
165
  for (let day = 1; day <= daysInMonth; day++) {
166
+ const currentDate = new Date(year, month, day);
74
167
  const dayEl = document.createElement('button');
75
168
  dayEl.className = 'ds-calendar__day';
76
169
  dayEl.textContent = day;
77
170
 
78
- const dayStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
171
+ const dayStr = this._formatDate(currentDate);
172
+
173
+ if (dayStr === todayStr) {
174
+ dayEl.classList.add('is-today');
175
+ }
176
+
177
+ if (this._isSameDay(currentDate, this.selectedDate)) {
178
+ dayEl.classList.add('is-selected');
179
+ }
180
+
181
+ if (this.isRangeMode) {
182
+ if (this._isRangeStart(currentDate)) {
183
+ dayEl.classList.add('is-range-start');
184
+ }
185
+ if (this._isRangeEnd(currentDate)) {
186
+ dayEl.classList.add('is-range-end');
187
+ }
188
+ if (this._isDateInRange(currentDate)) {
189
+ dayEl.classList.add('is-in-range');
190
+ }
191
+ }
192
+
193
+ const dayEvents = this._getEventsForDate(currentDate);
194
+ if (dayEvents.length > 0) {
195
+ dayEl.classList.add('has-events');
196
+ const eventDot = document.createElement('span');
197
+ eventDot.className = 'ds-calendar__day-event';
198
+ eventDot.style.backgroundColor = dayEvents[0].color || '#007bff';
199
+ dayEl.appendChild(eventDot);
200
+ }
201
+
202
+ const clickHandler = () => {
203
+ this.element.querySelectorAll('.ds-calendar__day').forEach(d => d.classList.remove('is-selected'));
204
+ dayEl.classList.add('is-selected');
205
+
206
+ if (this.isRangeMode) {
207
+ if (!this.rangeStart || (this.rangeEnd && !this._isSameDay(currentDate, this.rangeEnd))) {
208
+ this.rangeStart = currentDate;
209
+ this.rangeEnd = null;
210
+ } else if (this.rangeStart && !this.rangeEnd) {
211
+ if (currentDate < this.rangeStart) {
212
+ this.rangeEnd = this.rangeStart;
213
+ this.rangeStart = currentDate;
214
+ } else {
215
+ this.rangeEnd = currentDate;
216
+ }
217
+
218
+ if (this.onRangeSelect) {
219
+ this.onRangeSelect({ start: this.rangeStart, end: this.rangeEnd });
220
+ }
221
+ this.element.dispatchEvent(new CustomEvent('kupola:calendar-range-select', {
222
+ detail: { start: this.rangeStart, end: this.rangeEnd },
223
+ bubbles: true
224
+ }));
225
+ }
226
+ } else {
227
+ this.selectedDate = currentDate;
228
+ if (this.onSelect) {
229
+ this.onSelect({ date: currentDate, dateStr: dayStr });
230
+ }
231
+ this.element.dispatchEvent(new CustomEvent('kupola:calendar-select', {
232
+ detail: { date: currentDate, dateStr: dayStr },
233
+ bubbles: true
234
+ }));
235
+ }
236
+
237
+ dayEvents.forEach(event => {
238
+ if (this.onEventClick) {
239
+ this.onEventClick(event, currentDate);
240
+ }
241
+ });
242
+
243
+ this.render();
244
+ };
245
+
246
+ dayEl.addEventListener('click', clickHandler);
247
+ this._listeners.push({ el: dayEl, event: 'click', handler: clickHandler });
248
+
249
+ this.daysEl.appendChild(dayEl);
250
+ }
251
+ }
252
+
253
+ _renderWeekView(year, month) {
254
+ const dayOfWeek = this.currentDate.getDay();
255
+ const monday = new Date(year, month, this.currentDate.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1));
256
+
257
+ const startDate = monday;
258
+ const endDate = new Date(monday);
259
+ endDate.setDate(monday.getDate() + 6);
260
+
261
+ this.titleEl.textContent = `${this.i18n.shortMonths[startDate.getMonth()]} ${startDate.getDate()} - ${this.i18n.shortMonths[endDate.getMonth()]} ${endDate.getDate()} ${year}`;
262
+
263
+ this.daysEl.innerHTML = '';
264
+
265
+ const today = new Date();
266
+ const todayStr = this._formatDate(today);
267
+
268
+ for (let i = 0; i < 7; i++) {
269
+ const currentDate = new Date(monday);
270
+ currentDate.setDate(monday.getDate() + i);
271
+
272
+ const dayEl = document.createElement('button');
273
+ dayEl.className = 'ds-calendar__day ds-calendar__day--week';
274
+
275
+ const dayHeader = document.createElement('span');
276
+ dayHeader.className = 'ds-calendar__day-header';
277
+ dayHeader.textContent = this.i18n.shortWeekdays[currentDate.getDay()];
278
+ dayEl.appendChild(dayHeader);
279
+
280
+ const dayNum = document.createElement('span');
281
+ dayNum.className = 'ds-calendar__day-number';
282
+ dayNum.textContent = currentDate.getDate();
283
+ dayEl.appendChild(dayNum);
284
+
285
+ const dayStr = this._formatDate(currentDate);
79
286
 
80
287
  if (dayStr === todayStr) {
81
288
  dayEl.classList.add('is-today');
82
289
  }
83
290
 
291
+ if (this._isSameDay(currentDate, this.selectedDate)) {
292
+ dayEl.classList.add('is-selected');
293
+ }
294
+
295
+ const dayEvents = this._getEventsForDate(currentDate);
296
+ if (dayEvents.length > 0) {
297
+ const eventsContainer = document.createElement('span');
298
+ eventsContainer.className = 'ds-calendar__day-events';
299
+ dayEvents.slice(0, 3).forEach(event => {
300
+ const eventDot = document.createElement('span');
301
+ eventDot.className = 'ds-calendar__day-event';
302
+ eventDot.style.backgroundColor = event.color || '#007bff';
303
+ eventsContainer.appendChild(eventDot);
304
+ });
305
+ dayEl.appendChild(eventsContainer);
306
+ }
307
+
84
308
  const clickHandler = () => {
85
309
  this.element.querySelectorAll('.ds-calendar__day').forEach(d => d.classList.remove('is-selected'));
86
310
  dayEl.classList.add('is-selected');
87
- this.$emit('select', { date: new Date(year, month, day), dateStr: dayStr });
311
+ this.selectedDate = currentDate;
312
+
313
+ if (this.onSelect) {
314
+ this.onSelect({ date: currentDate, dateStr: dayStr });
315
+ }
316
+ this.element.dispatchEvent(new CustomEvent('kupola:calendar-select', {
317
+ detail: { date: currentDate, dateStr: dayStr },
318
+ bubbles: true
319
+ }));
320
+
321
+ this.render();
88
322
  };
89
323
 
90
324
  dayEl.addEventListener('click', clickHandler);
@@ -110,44 +344,118 @@ class Calendar {
110
344
  setDate(date) {
111
345
  this.currentDate = new Date(date);
112
346
  this.render();
347
+ this._emitChange();
113
348
  }
114
349
 
115
350
  getDate() {
116
351
  return this.currentDate;
117
352
  }
118
353
 
354
+ setSelectedDate(date) {
355
+ this.selectedDate = date ? new Date(date) : null;
356
+ this.render();
357
+ }
358
+
359
+ getSelectedDate() {
360
+ return this.selectedDate;
361
+ }
362
+
363
+ setRange(start, end) {
364
+ this.rangeStart = start ? new Date(start) : null;
365
+ this.rangeEnd = end ? new Date(end) : null;
366
+ this.render();
367
+
368
+ if (this.onRangeSelect && this.rangeStart && this.rangeEnd) {
369
+ this.onRangeSelect({ start: this.rangeStart, end: this.rangeEnd });
370
+ }
371
+ }
372
+
373
+ getRange() {
374
+ return { start: this.rangeStart, end: this.rangeEnd };
375
+ }
376
+
377
+ setEvents(events) {
378
+ this.events = events || [];
379
+ this.render();
380
+ }
381
+
382
+ addEvent(event) {
383
+ this.events.push(event);
384
+ this.render();
385
+ }
386
+
387
+ removeEvent(eventId) {
388
+ this.events = this.events.filter(e => e.id !== eventId);
389
+ this.render();
390
+ }
391
+
392
+ setViewMode(mode) {
393
+ if (mode === 'month' || mode === 'week') {
394
+ this.viewMode = mode;
395
+ this.render();
396
+ this._emitChange();
397
+ }
398
+ }
399
+
400
+ getViewMode() {
401
+ return this.viewMode;
402
+ }
403
+
404
+ setI18n(i18n) {
405
+ this.i18n = { ...this.i18n, ...i18n };
406
+ this.render();
407
+ }
408
+
119
409
  prevMonth() {
120
410
  this.currentDate.setMonth(this.currentDate.getMonth() - 1);
121
411
  this.render();
412
+ this._emitChange();
122
413
  }
123
414
 
124
415
  nextMonth() {
125
416
  this.currentDate.setMonth(this.currentDate.getMonth() + 1);
126
417
  this.render();
418
+ this._emitChange();
419
+ }
420
+
421
+ prevWeek() {
422
+ this.currentDate.setDate(this.currentDate.getDate() - 7);
423
+ this.render();
424
+ this._emitChange();
425
+ }
426
+
427
+ nextWeek() {
428
+ this.currentDate.setDate(this.currentDate.getDate() + 7);
429
+ this.render();
430
+ this._emitChange();
127
431
  }
128
432
 
129
433
  goToToday() {
130
434
  this.currentDate = new Date();
131
435
  this.render();
436
+ this._emitChange();
132
437
  }
133
438
 
134
- $emit(eventName, data) {
135
- if (this.element) {
136
- const customEvent = new CustomEvent(`kupola:calendar:${eventName}`, {
137
- detail: data,
138
- bubbles: true,
139
- cancelable: true
140
- });
141
- this.element.dispatchEvent(customEvent);
142
- }
439
+ goToDate(date) {
440
+ this.currentDate = new Date(date);
441
+ this.render();
442
+ this._emitChange();
443
+ }
444
+
445
+ toggleRangeMode() {
446
+ this.isRangeMode = !this.isRangeMode;
447
+ this.rangeStart = null;
448
+ this.rangeEnd = null;
449
+ this.render();
450
+ this._emitChange();
143
451
  }
144
452
  }
145
453
 
146
- function initCalendar(element) {
454
+ function initCalendar(element, options) {
147
455
  if (element.__kupolaInitialized) return;
148
456
 
149
457
  try {
150
- const calendar = new Calendar(element);
458
+ const calendar = new Calendar(element, options);
151
459
  element.__kupolaInstance = calendar;
152
460
  element.__kupolaInitialized = true;
153
461
  } catch (error) {
@@ -171,14 +479,15 @@ function initCalendars() {
171
479
  });
172
480
  }
173
481
 
174
- if (typeof module !== 'undefined' && module.exports) {
175
- module.exports = { Calendar, initCalendars, initCalendar, cleanupCalendar };
176
- } else {
482
+ export { Calendar, initCalendars, initCalendar, cleanupCalendar };
483
+
484
+ if (typeof window !== 'undefined') {
177
485
  window.Calendar = Calendar;
178
486
  window.initCalendar = initCalendar;
179
487
  window.cleanupCalendar = cleanupCalendar;
180
- }
181
-
182
- if (window.kupolaInitializer) {
183
- window.kupolaInitializer.register('calendar', initCalendar, cleanupCalendar);
488
+ window.initCalendars = initCalendars;
489
+
490
+ if (window.kupolaInitializer) {
491
+ window.kupolaInitializer.register('calendar', initCalendar, cleanupCalendar);
492
+ }
184
493
  }