@dodlhuat/basix 1.4.2 → 1.4.3

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 (90) hide show
  1. package/README.md +13 -1
  2. package/css/calendar.scss +4 -3
  3. package/css/code-viewer.scss +1 -1
  4. package/css/datepicker.scss +83 -70
  5. package/css/editor.scss +2 -1
  6. package/css/flyout-menu.scss +2 -1
  7. package/css/form.scss +11 -32
  8. package/css/mixins.scss +25 -0
  9. package/css/range-slider.scss +7 -6
  10. package/css/stepper.scss +2 -1
  11. package/css/style.css +84 -71
  12. package/css/style.css.map +1 -1
  13. package/css/style.min.css +1 -1
  14. package/css/style.min.css.map +1 -1
  15. package/css/timepicker.scss +1 -1
  16. package/css/virtual-dropdown.scss +6 -16
  17. package/js/bottom-sheet.d.ts +3 -5
  18. package/js/bottom-sheet.js +39 -58
  19. package/js/calendar.d.ts +1 -2
  20. package/js/calendar.js +77 -84
  21. package/js/carousel.d.ts +1 -1
  22. package/js/carousel.js +22 -14
  23. package/js/chart.d.ts +1 -1
  24. package/js/chart.js +104 -65
  25. package/js/code-viewer.d.ts +1 -1
  26. package/js/code-viewer.js +7 -18
  27. package/js/color-picker.d.ts +2 -2
  28. package/js/color-picker.js +20 -22
  29. package/js/context-menu.d.ts +1 -1
  30. package/js/context-menu.js +10 -12
  31. package/js/datepicker.d.ts +14 -3
  32. package/js/datepicker.js +180 -99
  33. package/js/dropdown.d.ts +1 -1
  34. package/js/dropdown.js +4 -5
  35. package/js/editor.d.ts +1 -1
  36. package/js/editor.js +30 -34
  37. package/js/file-uploader.d.ts +2 -9
  38. package/js/file-uploader.js +57 -86
  39. package/js/flyout-menu.d.ts +3 -3
  40. package/js/flyout-menu.js +20 -22
  41. package/js/gallery.d.ts +1 -2
  42. package/js/gallery.js +14 -20
  43. package/js/group-picker.d.ts +1 -1
  44. package/js/group-picker.js +22 -29
  45. package/js/lightbox.d.ts +2 -2
  46. package/js/lightbox.js +28 -27
  47. package/js/listeners.d.ts +7 -0
  48. package/js/listeners.js +14 -0
  49. package/js/modal.d.ts +2 -1
  50. package/js/modal.js +13 -20
  51. package/js/popover.d.ts +2 -2
  52. package/js/popover.js +42 -37
  53. package/js/position.js +3 -5
  54. package/js/push-menu.d.ts +2 -0
  55. package/js/push-menu.js +21 -15
  56. package/js/range-slider.d.ts +2 -2
  57. package/js/range-slider.js +7 -6
  58. package/js/scroll.js +4 -7
  59. package/js/scrollbar.d.ts +3 -3
  60. package/js/scrollbar.js +39 -42
  61. package/js/select.d.ts +1 -1
  62. package/js/select.js +19 -23
  63. package/js/sidebar-nav.d.ts +1 -1
  64. package/js/sidebar-nav.js +13 -9
  65. package/js/stepper.d.ts +1 -1
  66. package/js/stepper.js +9 -11
  67. package/js/table.d.ts +1 -1
  68. package/js/table.js +24 -23
  69. package/js/tabs.d.ts +1 -1
  70. package/js/tabs.js +10 -17
  71. package/js/theme.d.ts +1 -0
  72. package/js/theme.js +6 -15
  73. package/js/timepicker.d.ts +8 -6
  74. package/js/timepicker.js +36 -36
  75. package/js/toast.d.ts +2 -1
  76. package/js/toast.js +8 -4
  77. package/js/tooltip.d.ts +1 -4
  78. package/js/tooltip.js +14 -23
  79. package/js/tree.d.ts +0 -1
  80. package/js/tree.js +6 -11
  81. package/js/utils.js +7 -8
  82. package/js/virtual-dropdown.d.ts +1 -1
  83. package/js/virtual-dropdown.js +26 -28
  84. package/package.json +1 -1
  85. package/css/calendar.css +0 -928
  86. package/css/guitar-chords.css +0 -251
  87. package/js/form-builder.js +0 -107
  88. package/js/guitar-chords.js +0 -268
  89. package/js/lazy-loader.js +0 -121
  90. package/js/request.js +0 -51
package/js/calendar.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { ListenerGroup } from './listeners.js';
1
2
  const CalendarLogic = {
2
3
  getMonthGrid(year, month, firstDayOfWeek) {
3
4
  const firstOfMonth = new Date(year, month, 1);
@@ -30,9 +31,7 @@ const CalendarLogic = {
30
31
  });
31
32
  },
32
33
  isSameDay(a, b) {
33
- return a.getFullYear() === b.getFullYear()
34
- && a.getMonth() === b.getMonth()
35
- && a.getDate() === b.getDate();
34
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
36
35
  },
37
36
  isToday(date) {
38
37
  return CalendarLogic.isSameDay(date, new Date());
@@ -53,13 +52,13 @@ const CalendarLogic = {
53
52
  dayStart.setHours(0, 0, 0, 0);
54
53
  const dayEnd = new Date(day);
55
54
  dayEnd.setHours(23, 59, 59, 999);
56
- return events.filter(e => e.start <= dayEnd && e.end >= dayStart);
55
+ return events.filter((e) => e.start <= dayEnd && e.end >= dayStart);
57
56
  },
58
57
  getAllDayEvents(events, day) {
59
- return CalendarLogic.getEventsForDay(events, day).filter(e => e.allDay);
58
+ return CalendarLogic.getEventsForDay(events, day).filter((e) => e.allDay);
60
59
  },
61
60
  getTimedEvents(events, day) {
62
- return CalendarLogic.getEventsForDay(events, day).filter(e => !e.allDay);
61
+ return CalendarLogic.getEventsForDay(events, day).filter((e) => !e.allDay);
63
62
  },
64
63
  getEventPosition(event, day) {
65
64
  const dayStart = new Date(day);
@@ -82,7 +81,7 @@ const CalendarLogic = {
82
81
  return [];
83
82
  const weekStart = CalendarLogic.startOfDay(weekDays[0]);
84
83
  const weekEnd = CalendarLogic.startOfDay(weekDays[6]);
85
- const relevant = events.filter(e => {
84
+ const relevant = events.filter((e) => {
86
85
  const s = CalendarLogic.startOfDay(e.start);
87
86
  const en = CalendarLogic.startOfDay(e.end);
88
87
  return s <= weekEnd && en >= weekStart;
@@ -91,7 +90,7 @@ const CalendarLogic = {
91
90
  const diff = a.start.getTime() - b.start.getTime();
92
91
  if (diff !== 0)
93
92
  return diff;
94
- return (b.end.getTime() - b.start.getTime()) - (a.end.getTime() - a.start.getTime());
93
+ return b.end.getTime() - b.start.getTime() - (a.end.getTime() - a.start.getTime());
95
94
  });
96
95
  const laneEnds = [];
97
96
  const layouts = [];
@@ -136,7 +135,7 @@ const CalendarLogic = {
136
135
  const diff = a.start.getTime() - b.start.getTime();
137
136
  if (diff !== 0)
138
137
  return diff;
139
- return (b.end.getTime() - b.start.getTime()) - (a.end.getTime() - a.start.getTime());
138
+ return b.end.getTime() - b.start.getTime() - (a.end.getTime() - a.start.getTime());
140
139
  });
141
140
  const colEnds = [];
142
141
  const assigns = [];
@@ -151,23 +150,18 @@ const CalendarLogic = {
151
150
  assigns.push({ event, col });
152
151
  }
153
152
  return assigns.map(({ event, col }) => {
154
- const cols = assigns
155
- .filter(a => a.event.start < event.end && a.event.end > event.start)
156
- .reduce((max, a) => Math.max(max, a.col), 0) + 1;
153
+ const cols = assigns.filter((a) => a.event.start < event.end && a.event.end > event.start).reduce((max, a) => Math.max(max, a.col), 0) + 1;
157
154
  const pos = CalendarLogic.getEventPosition(event, day);
158
155
  return { event, top: pos.top, height: pos.height, col, cols };
159
156
  });
160
157
  },
161
158
  nowLinePct() {
162
159
  const now = new Date();
163
- return (now.getHours() * 60 + now.getMinutes()) / 1440 * 100;
160
+ return ((now.getHours() * 60 + now.getMinutes()) / 1440) * 100;
164
161
  },
165
162
  };
166
163
  const DEFAULT_LOCALE = {
167
- monthNames: [
168
- 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
169
- 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember',
170
- ],
164
+ monthNames: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
171
165
  dayNamesShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
172
166
  dayNamesFull: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
173
167
  firstDayOfWeek: 1,
@@ -185,13 +179,8 @@ class CalendarRenderer {
185
179
  }
186
180
  renderWeekdayHeaders() {
187
181
  const { dayNamesShort, firstDayOfWeek } = this.locale;
188
- const ordered = [
189
- ...dayNamesShort.slice(firstDayOfWeek),
190
- ...dayNamesShort.slice(0, firstDayOfWeek),
191
- ];
192
- return ordered
193
- .map(name => `<div class="cal__weekday" aria-label="${name}">${name}</div>`)
194
- .join('');
182
+ const ordered = [...dayNamesShort.slice(firstDayOfWeek), ...dayNamesShort.slice(0, firstDayOfWeek)];
183
+ return ordered.map((name) => `<div class="cal__weekday" aria-label="${name}">${name}</div>`).join('');
195
184
  }
196
185
  renderEvent(event, compact = false) {
197
186
  const cls = event.className ?? '';
@@ -211,7 +200,9 @@ class CalendarRenderer {
211
200
  event.className ?? '',
212
201
  continuesBefore ? 'cal__span-bar--cont-before' : '',
213
202
  continuesAfter ? 'cal__span-bar--cont-after' : '',
214
- ].filter(Boolean).join(' ');
203
+ ]
204
+ .filter(Boolean)
205
+ .join(' ');
215
206
  return `<div class="${cls}"
216
207
  style="--span-col:${colStart};--span-len:${colSpan};--span-lane:${lane}"
217
208
  data-event-id="${event.id}"
@@ -225,30 +216,28 @@ class CalendarRenderer {
225
216
  return `<div class="cal__day cal__day--empty" aria-hidden="true"></div>`;
226
217
  }
227
218
  const allForDay = CalendarLogic.getEventsForDay(events, date);
228
- const pillEvents = allForDay.filter(e => !CalendarLogic.isMultiDay(e));
219
+ const pillEvents = allForDay.filter((e) => !CalendarLogic.isMultiDay(e));
229
220
  const isToday = CalendarLogic.isToday(date);
230
- const classes = [
231
- 'cal__day',
232
- isToday ? 'is-today' : '',
233
- isOutside ? 'cal__day--outside' : '',
234
- allForDay.length > 0 ? 'has-events' : '',
235
- ].filter(Boolean).join(' ');
236
- const eventsHtml = pillEvents.slice(0, 3).map(e => this.renderEvent(e, true)).join('');
221
+ const classes = ['cal__day', isToday ? 'is-today' : '', isOutside ? 'cal__day--outside' : '', allForDay.length > 0 ? 'has-events' : '']
222
+ .filter(Boolean)
223
+ .join(' ');
224
+ const eventsHtml = pillEvents
225
+ .slice(0, 3)
226
+ .map((e) => this.renderEvent(e, true))
227
+ .join('');
237
228
  const moreCount = pillEvents.length - 3;
238
229
  const moreHtml = moreCount > 0 ? `<div class="cal__event-more">+${moreCount}</div>` : '';
239
- return `<div class="${classes}" aria-label="${date.toLocaleDateString()}">
230
+ return `<div class="${classes}" data-date="${date.toISOString()}" aria-label="${date.toLocaleDateString()}">
240
231
  <span class="cal__day-num">${date.getDate()}</span>
241
232
  <div class="cal__day-events">${eventsHtml}${moreHtml}</div>
242
233
  </div>`;
243
234
  }
244
235
  renderWeekRow(weekDays, currentMonth, currentYear, events, showOutsideDays) {
245
- const multiDay = events.filter(e => CalendarLogic.isMultiDay(e));
236
+ const multiDay = events.filter((e) => CalendarLogic.isMultiDay(e));
246
237
  const spans = CalendarLogic.computeSpanLayout(weekDays, multiDay);
247
- const maxLanes = spans.length > 0 ? Math.max(...spans.map(s => s.lane)) + 1 : 0;
248
- const dayCells = weekDays
249
- .map(d => this.renderMonthDay(d, currentMonth, currentYear, events, showOutsideDays))
250
- .join('');
251
- const spanBars = spans.map(s => this.renderSpanBar(s)).join('');
238
+ const maxLanes = spans.length > 0 ? Math.max(...spans.map((s) => s.lane)) + 1 : 0;
239
+ const dayCells = weekDays.map((d) => this.renderMonthDay(d, currentMonth, currentYear, events, showOutsideDays)).join('');
240
+ const spanBars = spans.map((s) => this.renderSpanBar(s)).join('');
252
241
  return `<div class="cal__week-row" style="--span-lanes:${maxLanes}">
253
242
  ${dayCells}${spanBars}
254
243
  </div>`;
@@ -266,31 +255,34 @@ class CalendarRenderer {
266
255
  }
267
256
  renderWeekView(date, events, firstDayOfWeek, showNowLine = false) {
268
257
  const days = CalendarLogic.getWeekDays(date, firstDayOfWeek);
269
- const headCols = days.map(d => {
258
+ const headCols = days
259
+ .map((d) => {
270
260
  const isToday = CalendarLogic.isToday(d);
271
- const cls = ['cal__week-head-day', isToday ? 'is-today' : '']
272
- .filter(Boolean).join(' ');
261
+ const cls = ['cal__week-head-day', isToday ? 'is-today' : ''].filter(Boolean).join(' ');
273
262
  const dow = this.locale.dayNamesShort[(d.getDay() + 7) % 7];
274
263
  return `<div class="${cls}">${dow}<span>${d.getDate()}</span></div>`;
275
- }).join('');
276
- const allDayEvents = events.filter(e => e.allDay);
264
+ })
265
+ .join('');
266
+ const allDayEvents = events.filter((e) => e.allDay);
277
267
  const allDayLayouts = CalendarLogic.computeSpanLayout(days, allDayEvents);
278
- const allDayLanes = allDayLayouts.length > 0 ? Math.max(...allDayLayouts.map(l => l.lane)) + 1 : 0;
268
+ const allDayLanes = allDayLayouts.length > 0 ? Math.max(...allDayLayouts.map((l) => l.lane)) + 1 : 0;
279
269
  const allDayCols = days.map(() => `<div class="cal__allday-col"></div>`).join('');
280
- const allDayBars = allDayLayouts.map(l => this.renderSpanBar(l)).join('');
270
+ const allDayBars = allDayLayouts.map((l) => this.renderSpanBar(l)).join('');
281
271
  const hourLabels = Array.from({ length: 24 }, (_, h) => {
282
272
  const label = h === 0 ? '' : `${String(h).padStart(2, '0')}:00`;
283
273
  return `<div class="cal__time-slot">${label}</div>`;
284
274
  }).join('');
285
- const dayCols = days.map(d => {
275
+ const dayCols = days
276
+ .map((d) => {
286
277
  const timedEvents = CalendarLogic.getTimedEvents(events, d);
287
278
  const hourCells = Array.from({ length: 24 }, () => `<div class="cal__day-col-hour"></div>`).join('');
288
279
  const layouts = CalendarLogic.computeTimedLayout(timedEvents, d);
289
- const eventOverlays = layouts.map(({ event, top, height, col, cols }) => {
280
+ const eventOverlays = layouts
281
+ .map(({ event, top, height, col, cols }) => {
290
282
  const cls = event.className ?? '';
291
283
  let posStyle = `top:${top.toFixed(2)}%;height:${height.toFixed(2)}%`;
292
284
  if (cols > 1) {
293
- const l = (col / cols * 100).toFixed(2);
285
+ const l = ((col / cols) * 100).toFixed(2);
294
286
  const w = (100 / cols).toFixed(2);
295
287
  posStyle += `;left:calc(${l}% + 2px);right:auto;width:calc(${w}% - 4px)`;
296
288
  }
@@ -300,12 +292,12 @@ class CalendarRenderer {
300
292
  <span class="cal__event-time">${CalendarLogic.formatTime(event.start)}</span>
301
293
  ${event.title}
302
294
  </div>`;
303
- }).join('');
295
+ })
296
+ .join('');
304
297
  return `<div class="cal__day-col" data-date="${d.toISOString()}">${hourCells}${eventOverlays}</div>`;
305
- }).join('');
306
- const nowLine = showNowLine
307
- ? `<div class="cal__now-line" style="top:${CalendarLogic.nowLinePct().toFixed(3)}%"></div>`
308
- : '';
298
+ })
299
+ .join('');
300
+ const nowLine = showNowLine ? `<div class="cal__now-line" style="top:${CalendarLogic.nowLinePct().toFixed(3)}%"></div>` : '';
309
301
  return `<div class="cal__week" role="grid">
310
302
  <div class="cal__week-head">
311
303
  <div class="cal__week-head-time"></div>
@@ -333,7 +325,7 @@ class CalendarRenderer {
333
325
  for (let d = 1; d <= daysInMonth; d++) {
334
326
  const day = new Date(year, month, d);
335
327
  const dayEvents = CalendarLogic.getEventsForDay(events, day);
336
- const filtered = dayEvents.filter(e => {
328
+ const filtered = dayEvents.filter((e) => {
337
329
  if (!CalendarLogic.isMultiDay(e))
338
330
  return true;
339
331
  if (shownMultiDay.has(e.id))
@@ -351,7 +343,8 @@ class CalendarRenderer {
351
343
  <span class="cal__agenda-num ${isToday ? 'is-today' : ''}">${d}</span>
352
344
  </div>
353
345
  <div class="cal__agenda-events">
354
- ${filtered.map(e => {
346
+ ${filtered
347
+ .map((e) => {
355
348
  const isMulti = CalendarLogic.isMultiDay(e);
356
349
  let timeLabel;
357
350
  if (isMulti) {
@@ -368,7 +361,8 @@ class CalendarRenderer {
368
361
  <span class="cal__agenda-event-time">${timeLabel}</span>
369
362
  <span class="cal__agenda-event-title">${e.title}</span>
370
363
  </div>`;
371
- }).join('')}
364
+ })
365
+ .join('')}
372
366
  </div>
373
367
  </div>`;
374
368
  }
@@ -386,6 +380,7 @@ class Calendar {
386
380
  currentView;
387
381
  events = [];
388
382
  nowLineTimer = null;
383
+ listeners = new ListenerGroup();
389
384
  constructor(options) {
390
385
  if (typeof options.container === 'string') {
391
386
  const el = document.querySelector(options.container);
@@ -451,7 +446,7 @@ class Calendar {
451
446
  this.render();
452
447
  }
453
448
  removeEvent(id) {
454
- this.events = this.events.filter(e => e.id !== id);
449
+ this.events = this.events.filter((e) => e.id !== id);
455
450
  this.render();
456
451
  }
457
452
  setEvents(events) {
@@ -463,26 +458,24 @@ class Calendar {
463
458
  }
464
459
  destroy() {
465
460
  this.clearNowLineTimer();
466
- this.container.removeEventListener('click', this.boundHandleClick);
467
- this.container.removeEventListener('keydown', this.boundHandleKeydown);
461
+ this.listeners.destroy();
468
462
  this.container.innerHTML = '';
469
463
  this.container.removeAttribute('data-cal');
470
464
  }
471
- getTitle() {
465
+ getTitle(weekDays) {
472
466
  const { monthNames } = this.locale;
473
467
  const y = this.currentDate.getFullYear();
474
468
  const m = this.currentDate.getMonth();
475
- if (this.currentView === 'week') {
476
- const days = CalendarLogic.getWeekDays(this.currentDate, this.locale.firstDayOfWeek);
477
- const first = days[0];
478
- const last = days[6];
469
+ if (this.currentView === 'week' && weekDays) {
470
+ const first = weekDays[0];
471
+ const last = weekDays[6];
479
472
  return first.getMonth() === last.getMonth()
480
473
  ? `${monthNames[first.getMonth()]} ${y}`
481
474
  : `${monthNames[first.getMonth()]} – ${monthNames[last.getMonth()]} ${y}`;
482
475
  }
483
476
  return `${monthNames[m]} ${y}`;
484
477
  }
485
- buildHeader() {
478
+ buildHeader(weekDays) {
486
479
  const v = this.currentView;
487
480
  return `<div class="cal__header">
488
481
  <div class="cal__nav">
@@ -494,7 +487,7 @@ class Calendar {
494
487
  <svg class="icon-svg" aria-hidden="true"><use href="${this.options.iconBasePath}icons.svg#chevron_right"/></svg>
495
488
  </button>
496
489
  </div>
497
- <h2 class="cal__title" aria-live="polite">${this.getTitle()}</h2>
490
+ <h2 class="cal__title" aria-live="polite">${this.getTitle(weekDays)}</h2>
498
491
  <div class="cal__view-toggle" role="group" aria-label="Ansicht wählen">
499
492
  <button class="cal__btn ${v === 'month' ? 'cal__btn--active' : ''}" data-action="view-month" aria-pressed="${v === 'month'}">${this.locale.month}</button>
500
493
  <button class="cal__btn ${v === 'week' ? 'cal__btn--active' : ''}" data-action="view-week" aria-pressed="${v === 'week'}">${this.locale.week}</button>
@@ -502,7 +495,7 @@ class Calendar {
502
495
  </div>
503
496
  </div>`;
504
497
  }
505
- buildBody() {
498
+ buildBody(weekDays) {
506
499
  const { firstDayOfWeek } = this.locale;
507
500
  const y = this.currentDate.getFullYear();
508
501
  const m = this.currentDate.getMonth();
@@ -510,8 +503,7 @@ class Calendar {
510
503
  case 'month':
511
504
  return this.renderer.renderMonthView(y, m, this.events, this.options.showOutsideDays, firstDayOfWeek);
512
505
  case 'week': {
513
- const weekDays = CalendarLogic.getWeekDays(this.currentDate, firstDayOfWeek);
514
- const showNowLine = weekDays.some(d => CalendarLogic.isToday(d));
506
+ const showNowLine = weekDays?.some((d) => CalendarLogic.isToday(d)) ?? false;
515
507
  return this.renderer.renderWeekView(this.currentDate, this.events, firstDayOfWeek, showNowLine);
516
508
  }
517
509
  case 'agenda':
@@ -520,18 +512,16 @@ class Calendar {
520
512
  }
521
513
  render() {
522
514
  this.clearNowLineTimer();
515
+ const weekDays = this.currentView === 'week' ? CalendarLogic.getWeekDays(this.currentDate, this.locale.firstDayOfWeek) : null;
523
516
  const rootClass = ['cal', this.options.className].filter(Boolean).join(' ');
524
517
  this.container.setAttribute('data-cal', this.currentView);
525
518
  this.container.innerHTML = `<div class="${rootClass}" role="application" aria-label="Kalender">
526
- ${this.buildHeader()}
527
- <div class="cal__body">${this.buildBody()}</div>
519
+ ${this.buildHeader(weekDays)}
520
+ <div class="cal__body">${this.buildBody(weekDays)}</div>
528
521
  </div>`;
529
- if (this.currentView === 'week') {
530
- const weekDays = CalendarLogic.getWeekDays(this.currentDate, this.locale.firstDayOfWeek);
531
- if (weekDays.some(d => CalendarLogic.isToday(d))) {
532
- this.scrollToNow();
533
- this.startNowLineTimer();
534
- }
522
+ if (weekDays?.some((d) => CalendarLogic.isToday(d))) {
523
+ this.scrollToNow();
524
+ this.startNowLineTimer();
535
525
  }
536
526
  }
537
527
  scrollToNow() {
@@ -554,11 +544,10 @@ class Calendar {
554
544
  this.nowLineTimer = null;
555
545
  }
556
546
  }
557
- boundHandleClick = (e) => this.handleClick(e);
558
- boundHandleKeydown = (e) => this.handleKeydown(e);
559
547
  attachEvents() {
560
- this.container.addEventListener('click', this.boundHandleClick);
561
- this.container.addEventListener('keydown', this.boundHandleKeydown);
548
+ const sig = { signal: this.listeners.signal };
549
+ this.container.addEventListener('click', (e) => this.handleClick(e), sig);
550
+ this.container.addEventListener('keydown', (e) => this.handleKeydown(e), sig);
562
551
  }
563
552
  handleClick(e) {
564
553
  const target = e.target;
@@ -582,13 +571,17 @@ class Calendar {
582
571
  const eventEl = target.closest('[data-event-id]');
583
572
  if (eventEl) {
584
573
  const id = eventEl.dataset.eventId;
585
- const event = this.events.find(ev => ev.id === id);
574
+ const event = this.events.find((ev) => ev.id === id);
586
575
  if (event) {
587
576
  e.stopPropagation();
588
577
  this.options.onEventClick(event);
589
578
  }
590
579
  return;
591
580
  }
581
+ const dayEl = target.closest('.cal__day[data-date]');
582
+ if (dayEl) {
583
+ this.options.onDayClick(new Date(dayEl.dataset.date));
584
+ }
592
585
  }
593
586
  handleKeydown(e) {
594
587
  const target = e.target;
package/js/carousel.d.ts CHANGED
@@ -15,7 +15,7 @@ declare class Carousel {
15
15
  private dotsNav;
16
16
  private dots;
17
17
  private autoPlayTimer;
18
- private abortController;
18
+ private listeners;
19
19
  constructor(elementOrSelector: string | HTMLElement, options?: CarouselOptions);
20
20
  private init;
21
21
  private setupDOM;
package/js/carousel.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { ListenerGroup } from './listeners.js';
1
2
  class Carousel {
2
3
  root;
3
4
  options;
@@ -10,15 +11,13 @@ class Carousel {
10
11
  dotsNav;
11
12
  dots;
12
13
  autoPlayTimer = null;
13
- abortController = new AbortController();
14
+ listeners = new ListenerGroup();
14
15
  constructor(elementOrSelector, options = {}) {
15
- const element = typeof elementOrSelector === 'string'
16
- ? document.querySelector(elementOrSelector)
17
- : elementOrSelector;
16
+ const element = typeof elementOrSelector === 'string' ? document.querySelector(elementOrSelector) : elementOrSelector;
18
17
  this.options = {
19
18
  loop: options.loop ?? false,
20
19
  autoPlay: options.autoPlay ?? false,
21
- autoPlayInterval: options.autoPlayInterval ?? 3000
20
+ autoPlayInterval: options.autoPlayInterval ?? 3000,
22
21
  };
23
22
  if (!element) {
24
23
  throw new Error(`Carousel: Element not found for selector "${elementOrSelector}"`);
@@ -29,6 +28,9 @@ class Carousel {
29
28
  init() {
30
29
  this.setupDOM();
31
30
  this.slides = Array.from(this.track.children);
31
+ if (this.slides.length === 0) {
32
+ throw new Error('Carousel: no slide elements found.');
33
+ }
32
34
  this.slideWidth = this.slides[0].getBoundingClientRect().width;
33
35
  this.currentIndex = 0;
34
36
  this.bindEvents();
@@ -43,7 +45,7 @@ class Carousel {
43
45
  container.classList.add('carousel-track-container');
44
46
  this.track = document.createElement('ul');
45
47
  this.track.classList.add('carousel-track');
46
- slides.forEach(slide => {
48
+ slides.forEach((slide) => {
47
49
  slide.classList.add('carousel-slide');
48
50
  this.track.appendChild(slide);
49
51
  });
@@ -73,19 +75,25 @@ class Carousel {
73
75
  this.root.setAttribute('tabindex', '0');
74
76
  }
75
77
  bindEvents() {
76
- const sig = { signal: this.abortController.signal };
78
+ const sig = { signal: this.listeners.signal };
77
79
  this.nextButton.addEventListener('click', () => this.moveToNextSlide(), sig);
78
80
  this.prevButton.addEventListener('click', () => this.moveToPrevSlide(), sig);
79
81
  this.dotsNav.addEventListener('click', (e) => {
80
82
  const targetDot = e.target.closest('button');
81
83
  if (!targetDot)
82
84
  return;
83
- const targetIndex = this.dots.findIndex(dot => dot === targetDot);
85
+ const targetIndex = this.dots.findIndex((dot) => dot === targetDot);
84
86
  this.moveToSlide(targetIndex);
85
87
  }, sig);
88
+ let resizeTimer = null;
86
89
  window.addEventListener('resize', () => {
87
- this.slideWidth = this.slides[0].getBoundingClientRect().width;
88
- this.moveToSlide(this.currentIndex, false);
90
+ if (resizeTimer !== null)
91
+ clearTimeout(resizeTimer);
92
+ resizeTimer = setTimeout(() => {
93
+ this.slideWidth = this.slides[0].getBoundingClientRect().width;
94
+ this.moveToSlide(this.currentIndex, false);
95
+ resizeTimer = null;
96
+ }, 100);
89
97
  }, sig);
90
98
  this.root.addEventListener('keydown', (e) => {
91
99
  if (e.key === 'ArrowLeft')
@@ -134,17 +142,17 @@ class Carousel {
134
142
  this.moveToSlide(this.currentIndex - 1);
135
143
  }
136
144
  updateDots(targetIndex) {
137
- this.dots.forEach(dot => dot.classList.remove('current-slide'));
145
+ this.dots.forEach((dot) => dot.classList.remove('current-slide'));
138
146
  this.dots[targetIndex].classList.add('current-slide');
139
147
  }
140
148
  addTouchSupport() {
141
149
  let startX = 0;
142
150
  let isDragging = false;
143
- const sig = { signal: this.abortController.signal };
151
+ const sig = { signal: this.listeners.signal };
144
152
  this.track.addEventListener('touchstart', (e) => {
145
153
  startX = e.touches[0].clientX;
146
154
  isDragging = true;
147
- }, { passive: true, signal: sig.signal });
155
+ }, { ...sig, passive: true });
148
156
  this.track.addEventListener('touchend', (e) => {
149
157
  if (!isDragging)
150
158
  return;
@@ -177,7 +185,7 @@ class Carousel {
177
185
  }
178
186
  destroy() {
179
187
  this.pauseAutoPlay();
180
- this.abortController.abort();
188
+ this.listeners.destroy();
181
189
  }
182
190
  }
183
191
  export { Carousel };
package/js/chart.d.ts CHANGED
@@ -28,7 +28,7 @@ declare class Chart {
28
28
  private opts;
29
29
  private tooltip;
30
30
  private colors;
31
- private abortController;
31
+ private listeners;
32
32
  private resizeTimer;
33
33
  private resizeObserver;
34
34
  constructor(selector: string | HTMLElement, options: ChartOptions);