@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
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
  }