@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/scrollbar.d.ts CHANGED
@@ -9,19 +9,19 @@ declare class Scrollbar {
9
9
  private static activeInstance;
10
10
  private static globalListenersInstalled;
11
11
  private static instanceCount;
12
- private static globalListenerAbortController;
12
+ private static globalListeners;
13
13
  private readonly container;
14
14
  private readonly viewport;
15
15
  private readonly content;
16
16
  private readonly track;
17
17
  private readonly thumb;
18
18
  private readonly MIN_THUMB_HEIGHT;
19
- private readonly ro;
19
+ private readonly resizeObserver;
20
20
  private dragging;
21
21
  private activePointerId;
22
22
  private startPointerY;
23
23
  private startThumbTop;
24
- private abortController;
24
+ private listeners;
25
25
  private constructor();
26
26
  private getRequiredElements;
27
27
  private getMinThumbHeight;
package/js/scrollbar.js CHANGED
@@ -1,21 +1,22 @@
1
+ import { ListenerGroup } from './listeners.js';
1
2
  class Scrollbar {
2
3
  static instances = new WeakMap();
3
4
  static activeInstance = null;
4
5
  static globalListenersInstalled = false;
5
6
  static instanceCount = 0;
6
- static globalListenerAbortController = null;
7
+ static globalListeners = null;
7
8
  container;
8
9
  viewport;
9
10
  content;
10
11
  track;
11
12
  thumb;
12
13
  MIN_THUMB_HEIGHT;
13
- ro;
14
+ resizeObserver;
14
15
  dragging = false;
15
16
  activePointerId = null;
16
17
  startPointerY = 0;
17
18
  startThumbTop = 0;
18
- abortController = new AbortController();
19
+ listeners = new ListenerGroup();
19
20
  constructor(container) {
20
21
  this.container = container;
21
22
  const elements = this.getRequiredElements(container);
@@ -24,14 +25,14 @@ class Scrollbar {
24
25
  this.track = elements.track;
25
26
  this.thumb = elements.thumb;
26
27
  this.MIN_THUMB_HEIGHT = this.getMinThumbHeight();
27
- this.ro = new ResizeObserver(this.updateThumb);
28
+ this.resizeObserver = new ResizeObserver(() => this.updateThumb());
28
29
  this.attachEventListeners();
29
30
  Scrollbar.instances.set(container, this);
30
31
  Scrollbar.instanceCount++;
31
32
  if (!Scrollbar.globalListenersInstalled) {
32
33
  Scrollbar.installGlobalListeners();
33
34
  }
34
- requestAnimationFrame(this.updateThumb);
35
+ requestAnimationFrame(() => this.updateThumb());
35
36
  }
36
37
  getRequiredElements(container) {
37
38
  const viewport = container.querySelector('.viewport');
@@ -44,39 +45,37 @@ class Scrollbar {
44
45
  return { viewport, content, track, thumb };
45
46
  }
46
47
  getMinThumbHeight() {
47
- const cssValue = getComputedStyle(document.documentElement)
48
- .getPropertyValue('--thumb-min')
49
- .trim();
48
+ const cssValue = getComputedStyle(document.documentElement).getPropertyValue('--thumb-min').trim();
50
49
  const parsed = parseInt(cssValue, 10);
51
50
  const defaultMin = 28;
52
51
  const absoluteMin = 16;
53
52
  return Math.max(absoluteMin, parsed || defaultMin);
54
53
  }
55
54
  static installGlobalListeners() {
56
- const ac = new AbortController();
57
- Scrollbar.globalListenerAbortController = ac;
55
+ const listeners = new ListenerGroup();
56
+ Scrollbar.globalListeners = listeners;
58
57
  document.addEventListener('pointermove', (e) => {
59
58
  Scrollbar.activeInstance?.handlePointerMove(e);
60
- }, { passive: false, signal: ac.signal });
59
+ }, { passive: false, signal: listeners.signal });
61
60
  document.addEventListener('pointerup', (e) => {
62
61
  Scrollbar.activeInstance?.handlePointerUp(e);
63
- }, { signal: ac.signal });
62
+ }, { signal: listeners.signal });
64
63
  document.addEventListener('pointercancel', (e) => {
65
64
  Scrollbar.activeInstance?.handlePointerUp(e);
66
- }, { signal: ac.signal });
65
+ }, { signal: listeners.signal });
67
66
  Scrollbar.globalListenersInstalled = true;
68
67
  }
69
68
  attachEventListeners() {
70
- const sig = { signal: this.abortController.signal };
71
- this.viewport.addEventListener('scroll', this.updateThumb, { passive: true, signal: sig.signal });
72
- this.thumb.addEventListener('pointerdown', this.handleThumbPointerDown, sig);
73
- this.track.addEventListener('click', this.handleTrackClick, sig);
74
- this.container.addEventListener('wheel', this.handleContainerWheel, { passive: false, signal: sig.signal });
75
- window.addEventListener('resize', this.updateThumb, sig);
76
- this.ro.observe(this.viewport);
77
- this.ro.observe(this.content);
78
- }
79
- updateThumb = () => {
69
+ const sig = { signal: this.listeners.signal };
70
+ this.viewport.addEventListener('scroll', () => this.updateThumb(), { ...sig, passive: true });
71
+ this.thumb.addEventListener('pointerdown', (e) => this.handleThumbPointerDown(e), sig);
72
+ this.track.addEventListener('click', (e) => this.handleTrackClick(e), sig);
73
+ this.container.addEventListener('wheel', (e) => this.handleContainerWheel(e), { ...sig, passive: false });
74
+ window.addEventListener('resize', () => this.updateThumb(), sig);
75
+ this.resizeObserver.observe(this.viewport);
76
+ this.resizeObserver.observe(this.content);
77
+ }
78
+ updateThumb() {
80
79
  const viewportHeight = this.viewport.clientHeight;
81
80
  const contentHeight = this.content.scrollHeight;
82
81
  const trackHeight = this.track.clientHeight;
@@ -93,8 +92,8 @@ class Scrollbar {
93
92
  const scrollRatio = this.viewport.scrollTop / (maxScroll || 1);
94
93
  const thumbTop = scrollRatio * (maxThumbTop || 0);
95
94
  this.thumb.style.top = `${thumbTop}px`;
96
- };
97
- handleThumbPointerDown = (e) => {
95
+ }
96
+ handleThumbPointerDown(e) {
98
97
  e.preventDefault();
99
98
  this.dragging = true;
100
99
  this.activePointerId = e.pointerId;
@@ -110,8 +109,8 @@ class Scrollbar {
110
109
  const trackRect = this.track.getBoundingClientRect();
111
110
  this.startThumbTop = thumbRect.top - trackRect.top;
112
111
  document.body.style.userSelect = 'none';
113
- };
114
- handlePointerMove = (e) => {
112
+ }
113
+ handlePointerMove(e) {
115
114
  if (!this.dragging || this.activePointerId !== e.pointerId) {
116
115
  return;
117
116
  }
@@ -127,8 +126,8 @@ class Scrollbar {
127
126
  const maxScroll = contentHeight - viewportHeight;
128
127
  const scrollRatio = newThumbTop / (maxThumbTop || 1);
129
128
  this.viewport.scrollTop = scrollRatio * (maxScroll || 0);
130
- };
131
- handlePointerUp = (e) => {
129
+ }
130
+ handlePointerUp(e) {
132
131
  if (!this.dragging || this.activePointerId !== e.pointerId) {
133
132
  return;
134
133
  }
@@ -142,8 +141,8 @@ class Scrollbar {
142
141
  this.activePointerId = null;
143
142
  Scrollbar.activeInstance = null;
144
143
  document.body.style.userSelect = '';
145
- };
146
- handleTrackClick = (e) => {
144
+ }
145
+ handleTrackClick(e) {
147
146
  if (e.target === this.thumb) {
148
147
  return;
149
148
  }
@@ -160,8 +159,8 @@ class Scrollbar {
160
159
  const scrollRatio = clampedThumbTop / (maxThumbTop || 1);
161
160
  const scrollTop = scrollRatio * (maxScroll || 0);
162
161
  this.viewport.scrollTo({ top: scrollTop, behavior: 'smooth' });
163
- };
164
- handleContainerWheel = (e) => {
162
+ }
163
+ handleContainerWheel(e) {
165
164
  const { scrollTop, scrollHeight, clientHeight } = this.viewport;
166
165
  const scrollable = scrollHeight > clientHeight;
167
166
  const atTop = scrollTop === 0 && e.deltaY < 0;
@@ -170,25 +169,23 @@ class Scrollbar {
170
169
  e.preventDefault();
171
170
  }
172
171
  this.viewport.scrollTop += e.deltaY;
173
- };
172
+ }
174
173
  destroy() {
175
- this.abortController.abort();
176
- this.ro.disconnect();
174
+ this.listeners.destroy();
175
+ this.resizeObserver.disconnect();
177
176
  Scrollbar.instances.delete(this.container);
178
177
  if (Scrollbar.activeInstance === this) {
179
178
  Scrollbar.activeInstance = null;
180
179
  }
181
180
  Scrollbar.instanceCount--;
182
181
  if (Scrollbar.instanceCount === 0) {
183
- Scrollbar.globalListenerAbortController?.abort();
184
- Scrollbar.globalListenerAbortController = null;
182
+ Scrollbar.globalListeners?.destroy();
183
+ Scrollbar.globalListeners = null;
185
184
  Scrollbar.globalListenersInstalled = false;
186
185
  }
187
186
  }
188
187
  static create(elementOrSelector) {
189
- const container = typeof elementOrSelector === 'string'
190
- ? document.querySelector(elementOrSelector)
191
- : elementOrSelector;
188
+ const container = typeof elementOrSelector === 'string' ? document.querySelector(elementOrSelector) : elementOrSelector;
192
189
  if (!container) {
193
190
  throw new Error(`Scrollbar: Element not found for selector "${elementOrSelector}"`);
194
191
  }
@@ -199,7 +196,7 @@ class Scrollbar {
199
196
  }
200
197
  static initAll(selector) {
201
198
  const containers = document.querySelectorAll(selector);
202
- return Array.from(containers).map(container => Scrollbar.create(container));
199
+ return Array.from(containers).map((container) => Scrollbar.create(container));
203
200
  }
204
201
  static initOne(elementOrSelector) {
205
202
  return Scrollbar.create(elementOrSelector);
package/js/select.d.ts CHANGED
@@ -2,7 +2,7 @@ declare class Select {
2
2
  private readonly element;
3
3
  private readonly isMultiselect;
4
4
  private readonly dropdown;
5
- private readonly documentClickHandler;
5
+ private listeners;
6
6
  constructor(elementOrSelector: string | HTMLSelectElement);
7
7
  destroy(): void;
8
8
  value(): string | string[];
package/js/select.js CHANGED
@@ -1,12 +1,11 @@
1
+ import { ListenerGroup } from './listeners.js';
1
2
  class Select {
2
3
  element;
3
4
  isMultiselect;
4
5
  dropdown;
5
- documentClickHandler;
6
+ listeners = new ListenerGroup();
6
7
  constructor(elementOrSelector) {
7
- const element = typeof elementOrSelector === 'string'
8
- ? document.querySelector(elementOrSelector)
9
- : elementOrSelector;
8
+ const element = typeof elementOrSelector === 'string' ? document.querySelector(elementOrSelector) : elementOrSelector;
10
9
  if (!element) {
11
10
  throw new Error(`Select: Element not found for selector "${elementOrSelector}"`);
12
11
  }
@@ -17,39 +16,36 @@ class Select {
17
16
  }
18
17
  this.isMultiselect = result.isMulti;
19
18
  this.dropdown = result.dropdown;
20
- this.documentClickHandler = (e) => {
19
+ document.addEventListener('click', (e) => {
21
20
  if (this.dropdown && !this.dropdown.contains(e.target)) {
22
21
  this.dropdown.classList.remove('open');
23
22
  }
24
- };
25
- document.addEventListener('click', this.documentClickHandler);
23
+ }, { signal: this.listeners.signal });
26
24
  }
27
25
  destroy() {
28
- document.removeEventListener('click', this.documentClickHandler);
26
+ this.listeners.destroy();
29
27
  this.dropdown?.classList.remove('open');
30
28
  }
31
29
  value() {
32
30
  const selectedValues = Array.from(this.element.options)
33
- .filter(option => option.selected)
34
- .map(option => option.value);
31
+ .filter((option) => option.selected)
32
+ .map((option) => option.value);
35
33
  return this.isMultiselect ? selectedValues : selectedValues[0];
36
34
  }
37
35
  static init(elementOrSelector) {
38
- const element = typeof elementOrSelector === 'string'
39
- ? document.querySelector(elementOrSelector)
40
- : elementOrSelector;
36
+ const element = typeof elementOrSelector === 'string' ? document.querySelector(elementOrSelector) : elementOrSelector;
41
37
  if (!element)
42
38
  return null;
43
39
  const result = Select.initElement(element);
44
40
  if (!result)
45
41
  return null;
46
- const handler = (e) => {
42
+ const listeners = new ListenerGroup();
43
+ document.addEventListener('click', (e) => {
47
44
  if (!result.dropdown.contains(e.target)) {
48
45
  result.dropdown.classList.remove('open');
49
46
  }
50
- };
51
- document.addEventListener('click', handler);
52
- return () => document.removeEventListener('click', handler);
47
+ }, { signal: listeners.signal });
48
+ return () => listeners.destroy();
53
49
  }
54
50
  static initElement(element) {
55
51
  if (!Select.transformSelect(element)) {
@@ -94,7 +90,7 @@ class Select {
94
90
  return { isMulti, dropdown };
95
91
  }
96
92
  static closeAllDropdowns(exceptDropdown) {
97
- document.querySelectorAll('.dropdown').forEach(dropdown => {
93
+ document.querySelectorAll('.dropdown').forEach((dropdown) => {
98
94
  if (dropdown !== exceptDropdown) {
99
95
  dropdown.classList.remove('open');
100
96
  }
@@ -103,15 +99,15 @@ class Select {
103
99
  static handleMultiSelect(option, optionsContainer, selected, selectElement) {
104
100
  option.classList.toggle('selected');
105
101
  const selectedOptions = Array.from(optionsContainer.querySelectorAll('.dropdown-option.selected'));
106
- const values = selectedOptions.map(opt => opt.textContent?.trim() || '');
102
+ const values = selectedOptions.map((opt) => opt.textContent?.trim() || '');
107
103
  selected.textContent = values.length ? values.join(', ') : 'Select options';
108
- const selectedValues = selectedOptions.map(opt => opt.dataset.value || '');
109
- Array.from(selectElement.options).forEach(opt => {
104
+ const selectedValues = selectedOptions.map((opt) => opt.dataset.value || '');
105
+ Array.from(selectElement.options).forEach((opt) => {
110
106
  opt.selected = selectedValues.includes(opt.value);
111
107
  });
112
108
  }
113
109
  static handleSingleSelect(option, optionsContainer, selected, dropdown, selectElement) {
114
- optionsContainer.querySelectorAll('.dropdown-option').forEach(opt => {
110
+ optionsContainer.querySelectorAll('.dropdown-option').forEach((opt) => {
115
111
  opt.classList.remove('selected');
116
112
  });
117
113
  option.classList.add('selected');
@@ -146,7 +142,7 @@ class Select {
146
142
  optionsMenu.className = 'dropdown-options-menu hidden';
147
143
  optionsMenu.innerHTML = 'Select options<span class="dropdown-options-icon icon icon-close"></span>';
148
144
  dropdownOptions.appendChild(optionsMenu);
149
- Array.from(select.options).forEach(opt => {
145
+ Array.from(select.options).forEach((opt) => {
150
146
  const optDiv = document.createElement('div');
151
147
  optDiv.className = 'dropdown-option';
152
148
  optDiv.dataset.value = opt.value;
@@ -12,7 +12,7 @@ declare class SidebarNav {
12
12
  private opts;
13
13
  private touchStartX;
14
14
  private touchStartY;
15
- private abortController;
15
+ private listeners;
16
16
  constructor(containerOrSelector: string | HTMLElement, options?: SidebarNavOptions);
17
17
  open(): void;
18
18
  close(): void;
package/js/sidebar-nav.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { ListenerGroup } from './listeners.js';
1
2
  class SidebarNav {
2
3
  nav;
3
4
  backdrop;
@@ -6,11 +7,9 @@ class SidebarNav {
6
7
  opts;
7
8
  touchStartX = 0;
8
9
  touchStartY = 0;
9
- abortController = new AbortController();
10
+ listeners = new ListenerGroup();
10
11
  constructor(containerOrSelector, options = {}) {
11
- const container = typeof containerOrSelector === 'string'
12
- ? document.querySelector(containerOrSelector)
13
- : containerOrSelector;
12
+ const container = typeof containerOrSelector === 'string' ? document.querySelector(containerOrSelector) : containerOrSelector;
14
13
  this.opts = {
15
14
  toggleSelector: options.toggleSelector ?? '.sidebar-toggle',
16
15
  breakpoint: options.breakpoint ?? 768,
@@ -20,7 +19,7 @@ class SidebarNav {
20
19
  this.nav = container?.querySelector('.sidebar-nav') ?? null;
21
20
  this.backdrop = container?.querySelector('.sidebar-backdrop') ?? null;
22
21
  this.toggleBtn = document.querySelector(this.opts.toggleSelector);
23
- const sig = { signal: this.abortController.signal };
22
+ const sig = { signal: this.listeners.signal };
24
23
  this.toggleBtn?.addEventListener('click', () => this.toggle(), sig);
25
24
  this.backdrop?.addEventListener('click', () => this.close(), sig);
26
25
  window.addEventListener('resize', () => {
@@ -30,7 +29,7 @@ class SidebarNav {
30
29
  document.addEventListener('touchstart', (e) => {
31
30
  this.touchStartX = e.touches[0].clientX;
32
31
  this.touchStartY = e.touches[0].clientY;
33
- }, { passive: true, signal: this.abortController.signal });
32
+ }, { ...sig, passive: true });
34
33
  document.addEventListener('touchend', (e) => {
35
34
  if (window.innerWidth > this.opts.breakpoint)
36
35
  return;
@@ -44,7 +43,7 @@ class SidebarNav {
44
43
  else if (this.isOpen() && dx <= -this.opts.swipeThreshold) {
45
44
  this.close();
46
45
  }
47
- }, { passive: true, signal: this.abortController.signal });
46
+ }, { ...sig, passive: true });
48
47
  this.closeBtn = document.createElement('button');
49
48
  this.closeBtn.className = 'sidebar-close';
50
49
  this.closeBtn.setAttribute('aria-label', 'Close navigation');
@@ -61,13 +60,18 @@ class SidebarNav {
61
60
  this.backdrop?.classList.remove('is-visible');
62
61
  }
63
62
  toggle() {
64
- this.nav?.classList.contains('is-open') ? this.close() : this.open();
63
+ if (this.nav?.classList.contains('is-open')) {
64
+ this.close();
65
+ }
66
+ else {
67
+ this.open();
68
+ }
65
69
  }
66
70
  isOpen() {
67
71
  return this.nav?.classList.contains('is-open') ?? false;
68
72
  }
69
73
  destroy() {
70
- this.abortController.abort();
74
+ this.listeners.destroy();
71
75
  this.closeBtn?.remove();
72
76
  }
73
77
  }
package/js/stepper.d.ts CHANGED
@@ -11,7 +11,7 @@ declare class Stepper {
11
11
  private current;
12
12
  private readonly onChange?;
13
13
  private readonly iconBasePath;
14
- private abortController;
14
+ private listeners;
15
15
  private injectedConnectors;
16
16
  constructor(elementOrSelector: string | HTMLElement, options?: StepperOptions);
17
17
  private injectConnectors;
package/js/stepper.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { ListenerGroup } from './listeners.js';
1
2
  class Stepper {
2
3
  container;
3
4
  steps;
@@ -5,12 +6,10 @@ class Stepper {
5
6
  current;
6
7
  onChange;
7
8
  iconBasePath;
8
- abortController = new AbortController();
9
+ listeners = new ListenerGroup();
9
10
  injectedConnectors = false;
10
11
  constructor(elementOrSelector, options = {}) {
11
- const element = typeof elementOrSelector === 'string'
12
- ? document.querySelector(elementOrSelector)
13
- : elementOrSelector;
12
+ const element = typeof elementOrSelector === 'string' ? document.querySelector(elementOrSelector) : elementOrSelector;
14
13
  if (!element)
15
14
  throw new Error('Stepper: element not found');
16
15
  this.container = element;
@@ -27,7 +26,7 @@ class Stepper {
27
26
  if (options.clickable) {
28
27
  this.container.classList.add('stepper-clickable');
29
28
  this.steps.forEach((step, i) => {
30
- step.addEventListener('click', () => this.goTo(i), { signal: this.abortController.signal });
29
+ step.addEventListener('click', () => this.goTo(i), { signal: this.listeners.signal });
31
30
  });
32
31
  }
33
32
  this.render();
@@ -88,9 +87,8 @@ class Stepper {
88
87
  const previous = this.current;
89
88
  this.current = index;
90
89
  this.render();
91
- if (this.onChange && previous !== index) {
92
- this.onChange(index, previous);
93
- }
90
+ if (previous !== index)
91
+ this.onChange?.(index, previous);
94
92
  }
95
93
  setError(index) {
96
94
  if (index < 0 || index >= this.steps.length)
@@ -115,12 +113,12 @@ class Stepper {
115
113
  return this.current === this.steps.length - 1;
116
114
  }
117
115
  destroy() {
118
- this.abortController.abort();
116
+ this.listeners.destroy();
119
117
  if (this.injectedConnectors) {
120
- this.connectors.forEach(c => c.remove());
118
+ this.connectors.forEach((c) => c.remove());
121
119
  this.connectors = [];
122
120
  }
123
- this.steps.forEach(step => step.removeAttribute('aria-current'));
121
+ this.steps.forEach((step) => step.removeAttribute('aria-current'));
124
122
  }
125
123
  }
126
124
  export { Stepper };
package/js/table.d.ts CHANGED
@@ -23,7 +23,7 @@ declare class Table {
23
23
  private tableBody;
24
24
  private tableHeader;
25
25
  private paginationContainer;
26
- private abortController;
26
+ private listeners;
27
27
  constructor(elementOrSelector: string | HTMLElement, options?: TableOptions);
28
28
  private parseTableFromDOM;
29
29
  private init;
package/js/table.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Select } from './select.js';
2
+ import { ListenerGroup } from './listeners.js';
2
3
  class Table {
3
4
  container;
4
5
  data;
@@ -11,11 +12,9 @@ class Table {
11
12
  tableBody;
12
13
  tableHeader;
13
14
  paginationContainer;
14
- abortController = new AbortController();
15
+ listeners = new ListenerGroup();
15
16
  constructor(elementOrSelector, options = {}) {
16
- const element = typeof elementOrSelector === 'string'
17
- ? document.querySelector(elementOrSelector)
18
- : elementOrSelector;
17
+ const element = typeof elementOrSelector === 'string' ? document.querySelector(elementOrSelector) : elementOrSelector;
19
18
  if (!element) {
20
19
  throw new Error(`Table: Element not found for selector "${elementOrSelector}"`);
21
20
  }
@@ -44,10 +43,10 @@ class Table {
44
43
  this.columns = Array.from(ths).map((th, index) => ({
45
44
  key: `col${index}`,
46
45
  label: th.textContent?.trim() || '',
47
- sortable: true
46
+ sortable: true,
48
47
  }));
49
48
  const trs = tbody.querySelectorAll('tr');
50
- this.data = Array.from(trs).map(tr => {
49
+ this.data = Array.from(trs).map((tr) => {
51
50
  const row = {};
52
51
  const tds = tr.querySelectorAll('td');
53
52
  tds.forEach((td, index) => {
@@ -73,7 +72,7 @@ class Table {
73
72
  searchInput.className = 'search-input';
74
73
  searchInput.addEventListener('input', (e) => {
75
74
  this.handleSearch(e.target.value);
76
- }, { signal: this.abortController.signal });
75
+ }, { signal: this.listeners.signal });
77
76
  controlsDiv.appendChild(searchInput);
78
77
  const selectGroup = document.createElement('div');
79
78
  selectGroup.className = 'select-group';
@@ -82,7 +81,7 @@ class Table {
82
81
  selectGroup.appendChild(label);
83
82
  const pageSizeSelect = document.createElement('select');
84
83
  pageSizeSelect.className = 'page-size-select';
85
- [5, 10, 20, 50].forEach(size => {
84
+ [5, 10, 20, 50].forEach((size) => {
86
85
  const option = document.createElement('option');
87
86
  option.value = String(size);
88
87
  option.textContent = `${size} per page`;
@@ -91,7 +90,7 @@ class Table {
91
90
  });
92
91
  pageSizeSelect.addEventListener('change', (e) => {
93
92
  this.handlePageSizeChange(parseInt(e.target.value, 10));
94
- }, { signal: this.abortController.signal });
93
+ }, { signal: this.listeners.signal });
95
94
  this.assignUniqueId(pageSizeSelect, 'page-size-select-0');
96
95
  selectGroup.appendChild(pageSizeSelect);
97
96
  controlsDiv.appendChild(selectGroup);
@@ -105,13 +104,13 @@ class Table {
105
104
  const thead = document.createElement('thead');
106
105
  const tbody = document.createElement('tbody');
107
106
  const tr = document.createElement('tr');
108
- this.columns.forEach(col => {
107
+ this.columns.forEach((col) => {
109
108
  const th = document.createElement('th');
110
109
  th.textContent = col.label;
111
110
  th.dataset.key = col.key;
112
111
  if (col.sortable !== false) {
113
112
  th.classList.add('sortable');
114
- th.addEventListener('click', () => this.handleSort(col.key), { signal: this.abortController.signal });
113
+ th.addEventListener('click', () => this.handleSort(col.key), { signal: this.listeners.signal });
115
114
  }
116
115
  tr.appendChild(th);
117
116
  });
@@ -131,17 +130,18 @@ class Table {
131
130
  let processedData = [...this.data];
132
131
  if (this.filterText) {
133
132
  const lowerFilter = this.filterText.toLowerCase();
134
- processedData = processedData.filter(row => {
135
- return this.columns.some(col => {
133
+ processedData = processedData.filter((row) => {
134
+ return this.columns.some((col) => {
136
135
  const val = String(row[col.key] ?? '').toLowerCase();
137
136
  return val.includes(lowerFilter);
138
137
  });
139
138
  });
140
139
  }
141
140
  if (this.sortColumn) {
141
+ const col = this.sortColumn;
142
142
  processedData.sort((a, b) => {
143
- const valA = a[this.sortColumn];
144
- const valB = b[this.sortColumn];
143
+ const valA = a[col];
144
+ const valB = b[col];
145
145
  if (valA == null && valB == null)
146
146
  return 0;
147
147
  if (valA == null)
@@ -186,9 +186,9 @@ class Table {
186
186
  this.tableBody.appendChild(tr);
187
187
  return;
188
188
  }
189
- data.forEach(row => {
189
+ data.forEach((row) => {
190
190
  const tr = document.createElement('tr');
191
- this.columns.forEach(col => {
191
+ this.columns.forEach((col) => {
192
192
  const td = document.createElement('td');
193
193
  td.textContent = String(row[col.key] ?? '');
194
194
  td.setAttribute('data-label', col.label);
@@ -199,7 +199,7 @@ class Table {
199
199
  }
200
200
  updateHeaderSortIcons() {
201
201
  const ths = this.tableHeader.querySelectorAll('th');
202
- ths.forEach(th => {
202
+ ths.forEach((th) => {
203
203
  th.classList.remove('sort-asc', 'sort-desc');
204
204
  if (th.dataset.key === this.sortColumn) {
205
205
  th.classList.add(this.sortDirection === 'asc' ? 'sort-asc' : 'sort-desc');
@@ -216,14 +216,15 @@ class Table {
216
216
  this.paginationContainer.appendChild(info);
217
217
  const buttonsDiv = document.createElement('div');
218
218
  buttonsDiv.className = 'pagination-buttons';
219
+ const sig = { signal: this.listeners.signal };
219
220
  const prevBtn = document.createElement('button');
220
221
  prevBtn.className = 'page-btn';
221
222
  prevBtn.textContent = 'Previous';
222
223
  prevBtn.disabled = this.currentPage === 1;
223
- prevBtn.addEventListener('click', () => this.setPage(this.currentPage - 1));
224
+ prevBtn.addEventListener('click', () => this.setPage(this.currentPage - 1), sig);
224
225
  buttonsDiv.appendChild(prevBtn);
225
226
  let startPage = Math.max(1, this.currentPage - 2);
226
- let endPage = Math.min(totalPages, startPage + 4);
227
+ const endPage = Math.min(totalPages, startPage + 4);
227
228
  if (endPage - startPage < 4) {
228
229
  startPage = Math.max(1, endPage - 4);
229
230
  }
@@ -231,14 +232,14 @@ class Table {
231
232
  const btn = document.createElement('button');
232
233
  btn.className = `page-btn ${i === this.currentPage ? 'active' : ''}`;
233
234
  btn.textContent = String(i);
234
- btn.addEventListener('click', () => this.setPage(i));
235
+ btn.addEventListener('click', () => this.setPage(i), sig);
235
236
  buttonsDiv.appendChild(btn);
236
237
  }
237
238
  const nextBtn = document.createElement('button');
238
239
  nextBtn.className = 'page-btn';
239
240
  nextBtn.textContent = 'Next';
240
241
  nextBtn.disabled = this.currentPage === totalPages;
241
- nextBtn.addEventListener('click', () => this.setPage(this.currentPage + 1));
242
+ nextBtn.addEventListener('click', () => this.setPage(this.currentPage + 1), sig);
242
243
  buttonsDiv.appendChild(nextBtn);
243
244
  this.paginationContainer.appendChild(buttonsDiv);
244
245
  }
@@ -298,7 +299,7 @@ class Table {
298
299
  return this.getFilteredAndSortedData();
299
300
  }
300
301
  destroy() {
301
- this.abortController.abort();
302
+ this.listeners.destroy();
302
303
  this.container.innerHTML = '';
303
304
  }
304
305
  }
package/js/tabs.d.ts CHANGED
@@ -12,7 +12,7 @@ declare class Tabs {
12
12
  private tabItems;
13
13
  private tabPanels;
14
14
  private currentTab;
15
- private abortController;
15
+ private listeners;
16
16
  constructor(elementOrSelector: string | HTMLElement, options?: TabsOptions);
17
17
  private init;
18
18
  private bindEvents;