@dodlhuat/basix 1.3.2 → 1.3.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.
- package/README.md +13 -7
- package/css/accordion.scss +0 -5
- package/css/badge.scss +1 -6
- package/css/bottom-sheet.scss +3 -8
- package/css/breadcrumb.scss +6 -15
- package/css/button.scss +2 -1
- package/css/calendar.scss +0 -54
- package/css/card.scss +0 -5
- package/css/carousel.scss +0 -3
- package/css/chart.scss +0 -25
- package/css/chat-bubbles.scss +0 -15
- package/css/checkbox.scss +3 -2
- package/css/chips.scss +3 -7
- package/css/code-viewer.scss +1 -5
- package/css/context-menu.scss +4 -6
- package/css/datepicker.scss +4 -7
- package/css/docs.scss +0 -4
- package/css/dropdown.scss +1 -1
- package/css/editor.scss +1 -23
- package/css/file-uploader.scss +2 -2
- package/css/flyout-menu.scss +66 -44
- package/css/form.scss +0 -28
- package/css/gallery.scss +2 -3
- package/css/group-picker.scss +5 -35
- package/css/icons.scss +0 -3
- package/css/lightbox.scss +2 -4
- package/css/mixins.scss +8 -0
- package/css/modal.scss +3 -3
- package/css/parameters.scss +6 -1
- package/css/popover.scss +3 -15
- package/css/progress.scss +0 -6
- package/css/push-menu.scss +3 -28
- package/css/radiobutton.scss +2 -1
- package/css/range-slider.scss +1 -7
- package/css/scrollbar.scss +2 -6
- package/css/sidebar-nav.scss +0 -12
- package/css/stepper.scss +0 -4
- package/css/style.css +63 -68
- package/css/style.css.map +1 -1
- package/css/style.min.css +1 -1
- package/css/style.min.css.map +1 -1
- package/css/style.scss +1 -1
- package/css/table.scss +0 -4
- package/css/tabs.scss +0 -2
- package/css/timeline.scss +1 -13
- package/css/timepicker.scss +6 -7
- package/css/toast.scss +1 -1
- package/css/tooltip.scss +1 -5
- package/css/tree.scss +1 -1
- package/css/typography.scss +3 -3
- package/css/virtual-dropdown.scss +3 -28
- package/js/bottom-sheet.d.ts +3 -1
- package/js/bottom-sheet.js +26 -27
- package/js/calendar.d.ts +7 -0
- package/js/calendar.js +14 -33
- package/js/carousel.d.ts +2 -0
- package/js/carousel.js +13 -5
- package/js/chart.d.ts +4 -0
- package/js/chart.js +13 -31
- package/js/code-viewer.d.ts +1 -0
- package/js/code-viewer.js +4 -0
- package/js/context-menu.d.ts +9 -2
- package/js/context-menu.js +17 -14
- package/js/datepicker.d.ts +4 -0
- package/js/datepicker.js +26 -11
- package/js/dropdown.d.ts +3 -3
- package/js/dropdown.js +6 -9
- package/js/editor.d.ts +1 -0
- package/js/editor.js +9 -3
- package/js/file-uploader.d.ts +4 -0
- package/js/file-uploader.js +52 -43
- package/js/flyout-menu.d.ts +5 -3
- package/js/flyout-menu.js +23 -46
- package/js/gallery.d.ts +3 -0
- package/js/gallery.js +22 -24
- package/js/group-picker.d.ts +5 -0
- package/js/group-picker.js +12 -17
- package/js/lightbox.d.ts +3 -0
- package/js/lightbox.js +12 -6
- package/js/modal.d.ts +3 -1
- package/js/modal.js +14 -11
- package/js/popover.d.ts +2 -0
- package/js/popover.js +26 -30
- package/js/position.d.ts +2 -0
- package/js/position.js +1 -5
- package/js/push-menu.d.ts +2 -0
- package/js/push-menu.js +22 -35
- package/js/range-slider.d.ts +1 -0
- package/js/range-slider.js +5 -3
- package/js/scroll.d.ts +2 -0
- package/js/scroll.js +1 -0
- package/js/scrollbar.d.ts +2 -0
- package/js/scrollbar.js +24 -36
- package/js/select.d.ts +1 -0
- package/js/select.js +5 -10
- package/js/sidebar-nav.d.ts +2 -0
- package/js/sidebar-nav.js +8 -0
- package/js/stepper.d.ts +2 -0
- package/js/stepper.js +7 -1
- package/js/table.d.ts +4 -0
- package/js/table.js +15 -22
- package/js/tabs.d.ts +2 -0
- package/js/tabs.js +6 -14
- package/js/theme.d.ts +1 -0
- package/js/theme.js +5 -13
- package/js/timepicker.d.ts +3 -0
- package/js/timepicker.js +81 -67
- package/js/toast.d.ts +3 -0
- package/js/toast.js +24 -15
- package/js/tooltip.d.ts +2 -0
- package/js/tooltip.js +21 -19
- package/js/tree.d.ts +3 -0
- package/js/tree.js +13 -0
- package/js/utils.d.ts +1 -3
- package/js/utils.js +0 -3
- package/js/virtual-dropdown.d.ts +3 -0
- package/js/virtual-dropdown.js +25 -0
- package/package.json +2 -2
package/js/range-slider.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
/** Enhances a native range input with a CSS fill-percentage custom property. */
|
|
1
2
|
class RangeSlider {
|
|
3
|
+
input;
|
|
2
4
|
constructor(input) {
|
|
3
|
-
this.handleInput = () => {
|
|
4
|
-
this.update();
|
|
5
|
-
};
|
|
6
5
|
this.input = input;
|
|
7
6
|
this.update();
|
|
8
7
|
this.input.addEventListener('input', this.handleInput);
|
|
@@ -18,6 +17,9 @@ class RangeSlider {
|
|
|
18
17
|
const pct = ((+this.input.value - min) / (max - min)) * 100;
|
|
19
18
|
this.input.style.setProperty('--range-fill', `${pct}%`);
|
|
20
19
|
}
|
|
20
|
+
handleInput = () => {
|
|
21
|
+
this.update();
|
|
22
|
+
};
|
|
21
23
|
destroy() {
|
|
22
24
|
this.input.removeEventListener('input', this.handleInput);
|
|
23
25
|
this.input.style.removeProperty('--range-fill');
|
package/js/scroll.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
/** Options for the Scroll.to() utility. */
|
|
1
2
|
interface ScrollOptions {
|
|
2
3
|
behavior?: ScrollBehavior;
|
|
3
4
|
offset?: number;
|
|
4
5
|
block?: ScrollLogicalPosition;
|
|
5
6
|
}
|
|
7
|
+
/** Static utility for smooth-scrolling to a target element with header offset support. */
|
|
6
8
|
declare class Scroll {
|
|
7
9
|
static to(target: string | Element, options?: ScrollOptions): void;
|
|
8
10
|
}
|
package/js/scroll.js
CHANGED
package/js/scrollbar.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
/** DOM element references for a Scrollbar instance. */
|
|
1
2
|
interface ScrollbarElements {
|
|
2
3
|
viewport: HTMLElement;
|
|
3
4
|
content: HTMLElement;
|
|
4
5
|
track: HTMLElement;
|
|
5
6
|
thumb: HTMLElement;
|
|
6
7
|
}
|
|
8
|
+
/** Custom scrollbar overlay that replaces the native scrollbar with a draggable thumb. */
|
|
7
9
|
declare class Scrollbar {
|
|
8
10
|
private static readonly instances;
|
|
9
11
|
private static activeInstance;
|
package/js/scrollbar.js
CHANGED
|
@@ -1,19 +1,36 @@
|
|
|
1
|
+
/** Custom scrollbar overlay that replaces the native scrollbar with a draggable thumb. */
|
|
1
2
|
class Scrollbar {
|
|
3
|
+
static instances = new WeakMap();
|
|
4
|
+
static activeInstance = null;
|
|
5
|
+
static globalListenersInstalled = false;
|
|
6
|
+
static instanceCount = 0;
|
|
7
|
+
static globalListenerAbortController = null;
|
|
8
|
+
container;
|
|
9
|
+
viewport;
|
|
10
|
+
content;
|
|
11
|
+
track;
|
|
12
|
+
thumb;
|
|
13
|
+
MIN_THUMB_HEIGHT;
|
|
14
|
+
ro;
|
|
15
|
+
dragging = false;
|
|
16
|
+
activePointerId = null;
|
|
17
|
+
startPointerY = 0;
|
|
18
|
+
startThumbTop = 0;
|
|
19
|
+
boundPointerMove;
|
|
20
|
+
boundPointerUp;
|
|
21
|
+
boundThumbPointerDown;
|
|
22
|
+
boundTrackClick;
|
|
23
|
+
boundViewportScroll;
|
|
24
|
+
boundUpdateThumb;
|
|
25
|
+
boundContainerWheel;
|
|
2
26
|
constructor(container) {
|
|
3
|
-
this.dragging = false;
|
|
4
|
-
this.activePointerId = null;
|
|
5
|
-
this.startPointerY = 0;
|
|
6
|
-
this.startThumbTop = 0;
|
|
7
27
|
this.container = container;
|
|
8
|
-
// Query and validate required elements
|
|
9
28
|
const elements = this.getRequiredElements(container);
|
|
10
29
|
this.viewport = elements.viewport;
|
|
11
30
|
this.content = elements.content;
|
|
12
31
|
this.track = elements.track;
|
|
13
32
|
this.thumb = elements.thumb;
|
|
14
|
-
// Get minimum thumb height from CSS variable or use default
|
|
15
33
|
this.MIN_THUMB_HEIGHT = this.getMinThumbHeight();
|
|
16
|
-
// Bind all event handlers once
|
|
17
34
|
this.boundPointerMove = this.handlePointerMove.bind(this);
|
|
18
35
|
this.boundPointerUp = this.handlePointerUp.bind(this);
|
|
19
36
|
this.boundThumbPointerDown = this.handleThumbPointerDown.bind(this);
|
|
@@ -21,17 +38,13 @@ class Scrollbar {
|
|
|
21
38
|
this.boundViewportScroll = this.updateThumb.bind(this);
|
|
22
39
|
this.boundUpdateThumb = this.updateThumb.bind(this);
|
|
23
40
|
this.boundContainerWheel = this.handleContainerWheel.bind(this);
|
|
24
|
-
// Setup ResizeObserver
|
|
25
41
|
this.ro = new ResizeObserver(this.boundUpdateThumb);
|
|
26
|
-
// Initialize
|
|
27
42
|
this.attachEventListeners();
|
|
28
43
|
Scrollbar.instances.set(container, this);
|
|
29
|
-
// Track instances and install global listeners once for all
|
|
30
44
|
Scrollbar.instanceCount++;
|
|
31
45
|
if (!Scrollbar.globalListenersInstalled) {
|
|
32
46
|
Scrollbar.installGlobalListeners();
|
|
33
47
|
}
|
|
34
|
-
// Initial thumb update
|
|
35
48
|
requestAnimationFrame(this.boundUpdateThumb);
|
|
36
49
|
}
|
|
37
50
|
getRequiredElements(container) {
|
|
@@ -68,12 +81,10 @@ class Scrollbar {
|
|
|
68
81
|
Scrollbar.globalListenersInstalled = true;
|
|
69
82
|
}
|
|
70
83
|
attachEventListeners() {
|
|
71
|
-
// Instance-specific events
|
|
72
84
|
this.viewport.addEventListener('scroll', this.boundViewportScroll, { passive: true });
|
|
73
85
|
this.thumb.addEventListener('pointerdown', this.boundThumbPointerDown);
|
|
74
86
|
this.track.addEventListener('click', this.boundTrackClick);
|
|
75
87
|
this.container.addEventListener('wheel', this.boundContainerWheel, { passive: false });
|
|
76
|
-
// Observe size changes
|
|
77
88
|
this.ro.observe(this.viewport);
|
|
78
89
|
this.ro.observe(this.content);
|
|
79
90
|
window.addEventListener('resize', this.boundUpdateThumb);
|
|
@@ -82,17 +93,14 @@ class Scrollbar {
|
|
|
82
93
|
const viewportHeight = this.viewport.clientHeight;
|
|
83
94
|
const contentHeight = this.content.scrollHeight;
|
|
84
95
|
const trackHeight = this.track.clientHeight;
|
|
85
|
-
// Hide thumb if content fits in viewport
|
|
86
96
|
if (contentHeight <= viewportHeight + 1) {
|
|
87
97
|
this.thumb.style.display = 'none';
|
|
88
98
|
return;
|
|
89
99
|
}
|
|
90
100
|
this.thumb.style.display = '';
|
|
91
|
-
// Calculate thumb size
|
|
92
101
|
const ratio = viewportHeight / contentHeight;
|
|
93
102
|
const thumbHeight = Math.max(Math.floor(ratio * trackHeight), this.MIN_THUMB_HEIGHT);
|
|
94
103
|
this.thumb.style.height = `${thumbHeight}px`;
|
|
95
|
-
// Calculate thumb position
|
|
96
104
|
const maxScroll = contentHeight - viewportHeight;
|
|
97
105
|
const maxThumbTop = trackHeight - thumbHeight;
|
|
98
106
|
const scrollRatio = this.viewport.scrollTop / (maxScroll || 1);
|
|
@@ -104,7 +112,6 @@ class Scrollbar {
|
|
|
104
112
|
this.dragging = true;
|
|
105
113
|
this.activePointerId = e.pointerId;
|
|
106
114
|
Scrollbar.activeInstance = this;
|
|
107
|
-
// Capture pointer for reliable tracking
|
|
108
115
|
try {
|
|
109
116
|
this.thumb.setPointerCapture(e.pointerId);
|
|
110
117
|
}
|
|
@@ -115,11 +122,9 @@ class Scrollbar {
|
|
|
115
122
|
const thumbRect = this.thumb.getBoundingClientRect();
|
|
116
123
|
const trackRect = this.track.getBoundingClientRect();
|
|
117
124
|
this.startThumbTop = thumbRect.top - trackRect.top;
|
|
118
|
-
// Prevent text selection during drag
|
|
119
125
|
document.body.style.userSelect = 'none';
|
|
120
126
|
}
|
|
121
127
|
handlePointerMove(e) {
|
|
122
|
-
// Only handle events for the active pointer
|
|
123
128
|
if (!this.dragging || this.activePointerId !== e.pointerId) {
|
|
124
129
|
return;
|
|
125
130
|
}
|
|
@@ -128,10 +133,8 @@ class Scrollbar {
|
|
|
128
133
|
const trackHeight = this.track.clientHeight;
|
|
129
134
|
const thumbHeight = this.thumb.clientHeight;
|
|
130
135
|
const maxThumbTop = trackHeight - thumbHeight;
|
|
131
|
-
// Calculate new thumb position
|
|
132
136
|
const newThumbTop = Math.max(0, Math.min(maxThumbTop, this.startThumbTop + pointerDelta));
|
|
133
137
|
this.thumb.style.top = `${newThumbTop}px`;
|
|
134
|
-
// Update viewport scroll position
|
|
135
138
|
const contentHeight = this.content.scrollHeight;
|
|
136
139
|
const viewportHeight = this.viewport.clientHeight;
|
|
137
140
|
const maxScroll = contentHeight - viewportHeight;
|
|
@@ -143,7 +146,6 @@ class Scrollbar {
|
|
|
143
146
|
return;
|
|
144
147
|
}
|
|
145
148
|
this.dragging = false;
|
|
146
|
-
// Release pointer capture
|
|
147
149
|
try {
|
|
148
150
|
this.thumb.releasePointerCapture(e.pointerId);
|
|
149
151
|
}
|
|
@@ -155,7 +157,6 @@ class Scrollbar {
|
|
|
155
157
|
document.body.style.userSelect = '';
|
|
156
158
|
}
|
|
157
159
|
handleTrackClick(e) {
|
|
158
|
-
// Ignore clicks directly on the thumb
|
|
159
160
|
if (e.target === this.thumb) {
|
|
160
161
|
return;
|
|
161
162
|
}
|
|
@@ -163,11 +164,9 @@ class Scrollbar {
|
|
|
163
164
|
const clickY = e.clientY - trackRect.top;
|
|
164
165
|
const thumbHeight = this.thumb.clientHeight;
|
|
165
166
|
const trackHeight = this.track.clientHeight;
|
|
166
|
-
// Center thumb on click position
|
|
167
167
|
const targetThumbTop = clickY - thumbHeight / 2;
|
|
168
168
|
const maxThumbTop = trackHeight - thumbHeight;
|
|
169
169
|
const clampedThumbTop = Math.max(0, Math.min(maxThumbTop, targetThumbTop));
|
|
170
|
-
// Calculate corresponding scroll position
|
|
171
170
|
const contentHeight = this.content.scrollHeight;
|
|
172
171
|
const viewportHeight = this.viewport.clientHeight;
|
|
173
172
|
const maxScroll = contentHeight - viewportHeight;
|
|
@@ -186,21 +185,16 @@ class Scrollbar {
|
|
|
186
185
|
this.viewport.scrollTop += e.deltaY;
|
|
187
186
|
}
|
|
188
187
|
destroy() {
|
|
189
|
-
// Remove event listeners
|
|
190
188
|
this.viewport.removeEventListener('scroll', this.boundViewportScroll);
|
|
191
189
|
this.thumb.removeEventListener('pointerdown', this.boundThumbPointerDown);
|
|
192
190
|
this.track.removeEventListener('click', this.boundTrackClick);
|
|
193
191
|
this.container.removeEventListener('wheel', this.boundContainerWheel);
|
|
194
192
|
window.removeEventListener('resize', this.boundUpdateThumb);
|
|
195
|
-
// Disconnect observer
|
|
196
193
|
this.ro.disconnect();
|
|
197
|
-
// Clear from instances map
|
|
198
194
|
Scrollbar.instances.delete(this.container);
|
|
199
|
-
// Clear active instance if this was it
|
|
200
195
|
if (Scrollbar.activeInstance === this) {
|
|
201
196
|
Scrollbar.activeInstance = null;
|
|
202
197
|
}
|
|
203
|
-
// Uninstall global listeners when last instance is destroyed
|
|
204
198
|
Scrollbar.instanceCount--;
|
|
205
199
|
if (Scrollbar.instanceCount === 0) {
|
|
206
200
|
Scrollbar.globalListenerAbortController?.abort();
|
|
@@ -208,7 +202,6 @@ class Scrollbar {
|
|
|
208
202
|
Scrollbar.globalListenersInstalled = false;
|
|
209
203
|
}
|
|
210
204
|
}
|
|
211
|
-
// Static factory methods
|
|
212
205
|
static create(elementOrSelector) {
|
|
213
206
|
const container = typeof elementOrSelector === 'string'
|
|
214
207
|
? document.querySelector(elementOrSelector)
|
|
@@ -232,9 +225,4 @@ class Scrollbar {
|
|
|
232
225
|
return Scrollbar.instances.get(container);
|
|
233
226
|
}
|
|
234
227
|
}
|
|
235
|
-
Scrollbar.instances = new WeakMap();
|
|
236
|
-
Scrollbar.activeInstance = null;
|
|
237
|
-
Scrollbar.globalListenersInstalled = false;
|
|
238
|
-
Scrollbar.instanceCount = 0;
|
|
239
|
-
Scrollbar.globalListenerAbortController = null;
|
|
240
228
|
export { Scrollbar };
|
package/js/select.d.ts
CHANGED
package/js/select.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
/** Enhances a native `<select>` element with a custom styled dropdown. */
|
|
1
2
|
class Select {
|
|
3
|
+
element;
|
|
4
|
+
isMultiselect;
|
|
5
|
+
dropdown;
|
|
6
|
+
documentClickHandler;
|
|
2
7
|
constructor(elementOrSelector) {
|
|
3
8
|
const element = typeof elementOrSelector === 'string'
|
|
4
9
|
? document.querySelector(elementOrSelector)
|
|
@@ -43,7 +48,6 @@ class Select {
|
|
|
43
48
|
const result = Select.initElement(element);
|
|
44
49
|
if (!result)
|
|
45
50
|
return null;
|
|
46
|
-
// Static init path: add document listener without lifecycle management
|
|
47
51
|
document.addEventListener('click', (e) => {
|
|
48
52
|
if (!result.dropdown.contains(e.target)) {
|
|
49
53
|
result.dropdown.classList.remove('open');
|
|
@@ -69,12 +73,10 @@ class Select {
|
|
|
69
73
|
throw new Error(`Select: Required dropdown elements not found for "${element}"`);
|
|
70
74
|
}
|
|
71
75
|
const isMulti = dropdown.dataset.multi === 'true';
|
|
72
|
-
// Toggle dropdown on selected element click
|
|
73
76
|
selected.addEventListener('click', () => {
|
|
74
77
|
Select.closeAllDropdowns(dropdown);
|
|
75
78
|
dropdown.classList.toggle('open');
|
|
76
79
|
});
|
|
77
|
-
// Handle option selection
|
|
78
80
|
options.addEventListener('click', (e) => {
|
|
79
81
|
const target = e.target;
|
|
80
82
|
if (!target.classList.contains('dropdown-option')) {
|
|
@@ -87,7 +89,6 @@ class Select {
|
|
|
87
89
|
Select.handleSingleSelect(target, options, selected, dropdown, element);
|
|
88
90
|
}
|
|
89
91
|
});
|
|
90
|
-
// Close dropdown when clicking the close icon
|
|
91
92
|
const closeIcon = options.querySelector('.dropdown-options-icon');
|
|
92
93
|
if (closeIcon) {
|
|
93
94
|
closeIcon.addEventListener('click', () => {
|
|
@@ -130,14 +131,12 @@ class Select {
|
|
|
130
131
|
const label = parent.querySelector('label');
|
|
131
132
|
const isMulti = select.hasAttribute('multiple');
|
|
132
133
|
const labelText = label?.textContent?.trim() || 'Select';
|
|
133
|
-
// Create hidden wrapper for original select
|
|
134
134
|
const hiddenWrapper = document.createElement('div');
|
|
135
135
|
hiddenWrapper.classList.add('hidden');
|
|
136
136
|
if (label) {
|
|
137
137
|
hiddenWrapper.appendChild(label);
|
|
138
138
|
}
|
|
139
139
|
hiddenWrapper.appendChild(select);
|
|
140
|
-
// Create dropdown structure
|
|
141
140
|
const dropdown = document.createElement('div');
|
|
142
141
|
dropdown.className = 'dropdown';
|
|
143
142
|
dropdown.dataset.multi = String(isMulti);
|
|
@@ -146,12 +145,10 @@ class Select {
|
|
|
146
145
|
dropdownSelected.textContent = labelText;
|
|
147
146
|
const dropdownOptions = document.createElement('div');
|
|
148
147
|
dropdownOptions.className = 'dropdown-options';
|
|
149
|
-
// Add mobile menu
|
|
150
148
|
const optionsMenu = document.createElement('div');
|
|
151
149
|
optionsMenu.className = 'dropdown-options-menu hidden';
|
|
152
150
|
optionsMenu.innerHTML = 'Select options<span class="dropdown-options-icon icon icon-close"></span>';
|
|
153
151
|
dropdownOptions.appendChild(optionsMenu);
|
|
154
|
-
// Create option elements
|
|
155
152
|
Array.from(select.options).forEach(opt => {
|
|
156
153
|
const optDiv = document.createElement('div');
|
|
157
154
|
optDiv.className = 'dropdown-option';
|
|
@@ -159,10 +156,8 @@ class Select {
|
|
|
159
156
|
optDiv.textContent = opt.textContent;
|
|
160
157
|
dropdownOptions.appendChild(optDiv);
|
|
161
158
|
});
|
|
162
|
-
// Assemble dropdown
|
|
163
159
|
dropdown.appendChild(dropdownSelected);
|
|
164
160
|
dropdown.appendChild(dropdownOptions);
|
|
165
|
-
// Replace original content
|
|
166
161
|
parent.innerHTML = '';
|
|
167
162
|
parent.appendChild(hiddenWrapper);
|
|
168
163
|
parent.appendChild(dropdown);
|
package/js/sidebar-nav.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
/** Configuration options for a SidebarNav instance. */
|
|
1
2
|
interface SidebarNavOptions {
|
|
2
3
|
/** Selector for the toggle button. Default: '.sidebar-toggle' */
|
|
3
4
|
toggleSelector?: string;
|
|
4
5
|
/** Breakpoint (px) above which the sidebar is always visible. Default: 768 */
|
|
5
6
|
breakpoint?: number;
|
|
6
7
|
}
|
|
8
|
+
/** Collapsible sidebar navigation with backdrop and responsive breakpoint support. */
|
|
7
9
|
declare class SidebarNav {
|
|
8
10
|
private nav;
|
|
9
11
|
private backdrop;
|
package/js/sidebar-nav.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
/** Collapsible sidebar navigation with backdrop and responsive breakpoint support. */
|
|
1
2
|
class SidebarNav {
|
|
3
|
+
nav;
|
|
4
|
+
backdrop;
|
|
5
|
+
toggleBtn;
|
|
6
|
+
opts;
|
|
7
|
+
_onToggle;
|
|
8
|
+
_onBackdrop;
|
|
9
|
+
_onResize;
|
|
2
10
|
constructor(containerOrSelector, options = {}) {
|
|
3
11
|
const container = typeof containerOrSelector === 'string'
|
|
4
12
|
? document.querySelector(containerOrSelector)
|
package/js/stepper.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
/** Configuration options for a Stepper instance. */
|
|
1
2
|
interface StepperOptions {
|
|
2
3
|
defaultStep?: number;
|
|
3
4
|
clickable?: boolean;
|
|
4
5
|
onChange?: (current: number, previous: number) => void;
|
|
5
6
|
}
|
|
7
|
+
/** Multi-step progress indicator with clickable steps and connector state. */
|
|
6
8
|
declare class Stepper {
|
|
7
9
|
private container;
|
|
8
10
|
private steps;
|
package/js/stepper.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
/** Multi-step progress indicator with clickable steps and connector state. */
|
|
1
2
|
class Stepper {
|
|
3
|
+
container;
|
|
4
|
+
steps;
|
|
5
|
+
connectors;
|
|
6
|
+
current;
|
|
7
|
+
onChange;
|
|
8
|
+
abortController = new AbortController();
|
|
2
9
|
constructor(elementOrSelector, options = {}) {
|
|
3
|
-
this.abortController = new AbortController();
|
|
4
10
|
const element = typeof elementOrSelector === 'string'
|
|
5
11
|
? document.querySelector(elementOrSelector)
|
|
6
12
|
: elementOrSelector;
|
package/js/table.d.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
+
/** Descriptor for a single table column. */
|
|
1
2
|
interface TableColumn {
|
|
2
3
|
key: string;
|
|
3
4
|
label: string;
|
|
4
5
|
sortable?: boolean;
|
|
5
6
|
}
|
|
7
|
+
/** A single data row, keyed by column key. */
|
|
6
8
|
interface TableRow {
|
|
7
9
|
[key: string]: string | number | boolean;
|
|
8
10
|
}
|
|
11
|
+
/** Configuration options for a Table instance. */
|
|
9
12
|
interface TableOptions {
|
|
10
13
|
data?: TableRow[];
|
|
11
14
|
columns?: TableColumn[];
|
|
12
15
|
pageSize?: number;
|
|
13
16
|
}
|
|
17
|
+
/** Dynamic data table with sorting, filtering, and pagination. */
|
|
14
18
|
declare class Table {
|
|
15
19
|
private container;
|
|
16
20
|
private data;
|
package/js/table.js
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { Select } from "./select.js";
|
|
2
|
+
/** Dynamic data table with sorting, filtering, and pagination. */
|
|
2
3
|
class Table {
|
|
4
|
+
container;
|
|
5
|
+
data;
|
|
6
|
+
columns;
|
|
7
|
+
pageSize;
|
|
8
|
+
currentPage;
|
|
9
|
+
sortColumn;
|
|
10
|
+
sortDirection;
|
|
11
|
+
filterText;
|
|
12
|
+
tableBody;
|
|
13
|
+
tableHeader;
|
|
14
|
+
paginationContainer;
|
|
15
|
+
abortController = new AbortController();
|
|
3
16
|
constructor(elementOrSelector, options = {}) {
|
|
4
|
-
this.abortController = new AbortController();
|
|
5
17
|
const element = typeof elementOrSelector === 'string'
|
|
6
18
|
? document.querySelector(elementOrSelector)
|
|
7
19
|
: elementOrSelector;
|
|
@@ -32,14 +44,12 @@ class Table {
|
|
|
32
44
|
const tbody = table.querySelector('tbody');
|
|
33
45
|
if (!thead || !tbody)
|
|
34
46
|
return;
|
|
35
|
-
// Parse columns from header
|
|
36
47
|
const ths = thead.querySelectorAll('th');
|
|
37
48
|
this.columns = Array.from(ths).map((th, index) => ({
|
|
38
49
|
key: `col${index}`,
|
|
39
50
|
label: th.textContent?.trim() || '',
|
|
40
51
|
sortable: true
|
|
41
52
|
}));
|
|
42
|
-
// Parse data from body rows
|
|
43
53
|
const trs = tbody.querySelectorAll('tr');
|
|
44
54
|
this.data = Array.from(trs).map(tr => {
|
|
45
55
|
const row = {};
|
|
@@ -51,7 +61,6 @@ class Table {
|
|
|
51
61
|
});
|
|
52
62
|
return row;
|
|
53
63
|
});
|
|
54
|
-
// Clear the existing static table
|
|
55
64
|
this.container.innerHTML = '';
|
|
56
65
|
}
|
|
57
66
|
/**
|
|
@@ -68,7 +77,6 @@ class Table {
|
|
|
68
77
|
renderControls() {
|
|
69
78
|
const controlsDiv = document.createElement('div');
|
|
70
79
|
controlsDiv.className = 'table-controls';
|
|
71
|
-
// Search input
|
|
72
80
|
const searchInput = document.createElement('input');
|
|
73
81
|
searchInput.type = 'text';
|
|
74
82
|
searchInput.placeholder = 'Search...';
|
|
@@ -77,7 +85,6 @@ class Table {
|
|
|
77
85
|
this.handleSearch(e.target.value);
|
|
78
86
|
}, { signal: this.abortController.signal });
|
|
79
87
|
controlsDiv.appendChild(searchInput);
|
|
80
|
-
// Page size selector
|
|
81
88
|
const selectGroup = document.createElement('div');
|
|
82
89
|
selectGroup.className = 'select-group';
|
|
83
90
|
const label = document.createElement('label');
|
|
@@ -110,7 +117,6 @@ class Table {
|
|
|
110
117
|
const table = document.createElement('table');
|
|
111
118
|
const thead = document.createElement('thead');
|
|
112
119
|
const tbody = document.createElement('tbody');
|
|
113
|
-
// Create header row
|
|
114
120
|
const tr = document.createElement('tr');
|
|
115
121
|
this.columns.forEach(col => {
|
|
116
122
|
const th = document.createElement('th');
|
|
@@ -127,7 +133,6 @@ class Table {
|
|
|
127
133
|
table.appendChild(tbody);
|
|
128
134
|
wrapper.appendChild(table);
|
|
129
135
|
this.container.appendChild(wrapper);
|
|
130
|
-
// Create pagination container
|
|
131
136
|
const paginationDiv = document.createElement('div');
|
|
132
137
|
paginationDiv.className = 'pagination';
|
|
133
138
|
this.container.appendChild(paginationDiv);
|
|
@@ -140,7 +145,6 @@ class Table {
|
|
|
140
145
|
*/
|
|
141
146
|
getFilteredAndSortedData() {
|
|
142
147
|
let processedData = [...this.data];
|
|
143
|
-
// Apply filter
|
|
144
148
|
if (this.filterText) {
|
|
145
149
|
const lowerFilter = this.filterText.toLowerCase();
|
|
146
150
|
processedData = processedData.filter(row => {
|
|
@@ -150,12 +154,10 @@ class Table {
|
|
|
150
154
|
});
|
|
151
155
|
});
|
|
152
156
|
}
|
|
153
|
-
// Apply sort
|
|
154
157
|
if (this.sortColumn) {
|
|
155
158
|
processedData.sort((a, b) => {
|
|
156
159
|
const valA = a[this.sortColumn];
|
|
157
160
|
const valB = b[this.sortColumn];
|
|
158
|
-
// Handle null/undefined values
|
|
159
161
|
if (valA == null && valB == null)
|
|
160
162
|
return 0;
|
|
161
163
|
if (valA == null)
|
|
@@ -178,7 +180,6 @@ class Table {
|
|
|
178
180
|
const processedData = this.getFilteredAndSortedData();
|
|
179
181
|
const totalItems = processedData.length;
|
|
180
182
|
const totalPages = Math.ceil(totalItems / this.pageSize);
|
|
181
|
-
// Ensure current page is valid
|
|
182
183
|
if (this.currentPage > totalPages && totalPages > 0) {
|
|
183
184
|
this.currentPage = totalPages;
|
|
184
185
|
}
|
|
@@ -212,7 +213,7 @@ class Table {
|
|
|
212
213
|
this.columns.forEach(col => {
|
|
213
214
|
const td = document.createElement('td');
|
|
214
215
|
td.textContent = String(row[col.key] ?? '');
|
|
215
|
-
td.setAttribute('data-label', col.label);
|
|
216
|
+
td.setAttribute('data-label', col.label);
|
|
216
217
|
tr.appendChild(td);
|
|
217
218
|
});
|
|
218
219
|
this.tableBody.appendChild(tr);
|
|
@@ -237,28 +238,23 @@ class Table {
|
|
|
237
238
|
this.paginationContainer.innerHTML = '';
|
|
238
239
|
if (totalItems === 0)
|
|
239
240
|
return;
|
|
240
|
-
// Info text
|
|
241
241
|
const info = document.createElement('div');
|
|
242
242
|
info.className = 'pagination-info';
|
|
243
243
|
info.textContent = `Showing ${startIndex + 1} to ${endIndex} of ${totalItems} entries`;
|
|
244
244
|
this.paginationContainer.appendChild(info);
|
|
245
|
-
// Pagination buttons
|
|
246
245
|
const buttonsDiv = document.createElement('div');
|
|
247
246
|
buttonsDiv.className = 'pagination-buttons';
|
|
248
|
-
// Previous button
|
|
249
247
|
const prevBtn = document.createElement('button');
|
|
250
248
|
prevBtn.className = 'page-btn';
|
|
251
249
|
prevBtn.textContent = 'Previous';
|
|
252
250
|
prevBtn.disabled = this.currentPage === 1;
|
|
253
251
|
prevBtn.addEventListener('click', () => this.setPage(this.currentPage - 1));
|
|
254
252
|
buttonsDiv.appendChild(prevBtn);
|
|
255
|
-
// Calculate page range to display (max 5 pages)
|
|
256
253
|
let startPage = Math.max(1, this.currentPage - 2);
|
|
257
254
|
let endPage = Math.min(totalPages, startPage + 4);
|
|
258
255
|
if (endPage - startPage < 4) {
|
|
259
256
|
startPage = Math.max(1, endPage - 4);
|
|
260
257
|
}
|
|
261
|
-
// Page number buttons
|
|
262
258
|
for (let i = startPage; i <= endPage; i++) {
|
|
263
259
|
const btn = document.createElement('button');
|
|
264
260
|
btn.className = `page-btn ${i === this.currentPage ? 'active' : ''}`;
|
|
@@ -266,7 +262,6 @@ class Table {
|
|
|
266
262
|
btn.addEventListener('click', () => this.setPage(i));
|
|
267
263
|
buttonsDiv.appendChild(btn);
|
|
268
264
|
}
|
|
269
|
-
// Next button
|
|
270
265
|
const nextBtn = document.createElement('button');
|
|
271
266
|
nextBtn.className = 'page-btn';
|
|
272
267
|
nextBtn.textContent = 'Next';
|
|
@@ -280,7 +275,7 @@ class Table {
|
|
|
280
275
|
*/
|
|
281
276
|
handleSearch(text) {
|
|
282
277
|
this.filterText = text;
|
|
283
|
-
this.currentPage = 1;
|
|
278
|
+
this.currentPage = 1;
|
|
284
279
|
this.render();
|
|
285
280
|
}
|
|
286
281
|
/**
|
|
@@ -288,7 +283,6 @@ class Table {
|
|
|
288
283
|
*/
|
|
289
284
|
handleSort(key) {
|
|
290
285
|
if (this.sortColumn === key) {
|
|
291
|
-
// Toggle sort direction
|
|
292
286
|
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
|
|
293
287
|
}
|
|
294
288
|
else {
|
|
@@ -320,7 +314,6 @@ class Table {
|
|
|
320
314
|
return null;
|
|
321
315
|
let id = baseId;
|
|
322
316
|
let counter = 1;
|
|
323
|
-
// If baseId already ends with a number, extract it
|
|
324
317
|
const match = baseId.match(/^(.*?)(\d+)$/);
|
|
325
318
|
if (match) {
|
|
326
319
|
id = match[1];
|
package/js/tabs.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
type TabLayout = 'horizontal' | 'vertical';
|
|
2
2
|
type MenuPosition = 'top' | 'bottom' | 'left' | 'right';
|
|
3
|
+
/** Configuration options for a Tabs instance. */
|
|
3
4
|
interface TabsOptions {
|
|
4
5
|
layout?: TabLayout;
|
|
5
6
|
defaultTab?: number;
|
|
6
7
|
menuPos?: MenuPosition;
|
|
7
8
|
onChange?: (index: number) => void;
|
|
8
9
|
}
|
|
10
|
+
/** Tabbed content component with horizontal/vertical layouts and keyboard navigation. */
|
|
9
11
|
declare class Tabs {
|
|
10
12
|
private container;
|
|
11
13
|
private options;
|