@dodlhuat/basix 1.2.8 → 1.2.9
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/package.json +1 -1
- package/js/bottom-sheet.ts +0 -224
- package/js/calendar.ts +0 -774
- package/js/carousel.ts +0 -222
- package/js/chart.ts +0 -694
- package/js/code-viewer.ts +0 -188
- package/js/context-menu.ts +0 -252
- package/js/datepicker.ts +0 -640
- package/js/dropdown.ts +0 -180
- package/js/editor.ts +0 -492
- package/js/file-uploader.ts +0 -361
- package/js/flyout-menu.ts +0 -255
- package/js/gallery.ts +0 -237
- package/js/group-picker.ts +0 -451
- package/js/lightbox.ts +0 -333
- package/js/modal.ts +0 -171
- package/js/popover.ts +0 -221
- package/js/position.ts +0 -111
- package/js/push-menu.ts +0 -286
- package/js/range-slider.ts +0 -33
- package/js/scroll.ts +0 -47
- package/js/scrollbar.ts +0 -335
- package/js/select.ts +0 -235
- package/js/sidebar-nav.ts +0 -66
- package/js/stepper.ts +0 -109
- package/js/table.ts +0 -459
- package/js/tabs.ts +0 -280
- package/js/theme.ts +0 -235
- package/js/timepicker.ts +0 -202
- package/js/toast.ts +0 -134
- package/js/tooltip.ts +0 -196
- package/js/tree.ts +0 -244
- package/js/tsconfig.json +0 -19
- package/js/utils.ts +0 -119
- package/js/virtual-dropdown.ts +0 -396
package/js/stepper.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
interface StepperOptions {
|
|
2
|
-
defaultStep?: number;
|
|
3
|
-
clickable?: boolean;
|
|
4
|
-
onChange?: (current: number, previous: number) => void;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
class Stepper {
|
|
8
|
-
private container: HTMLElement;
|
|
9
|
-
private steps: HTMLElement[];
|
|
10
|
-
private connectors: HTMLElement[];
|
|
11
|
-
private current: number;
|
|
12
|
-
private readonly onChange?: (current: number, previous: number) => void;
|
|
13
|
-
private abortController = new AbortController();
|
|
14
|
-
|
|
15
|
-
constructor(elementOrSelector: string | HTMLElement, options: StepperOptions = {}) {
|
|
16
|
-
const element = typeof elementOrSelector === 'string'
|
|
17
|
-
? document.querySelector<HTMLElement>(elementOrSelector)
|
|
18
|
-
: elementOrSelector;
|
|
19
|
-
|
|
20
|
-
if (!element) throw new Error(`Stepper: element not found`);
|
|
21
|
-
|
|
22
|
-
this.container = element;
|
|
23
|
-
this.steps = Array.from(this.container.querySelectorAll<HTMLElement>('.stepper-step'));
|
|
24
|
-
this.connectors = Array.from(this.container.querySelectorAll<HTMLElement>('.stepper-connector'));
|
|
25
|
-
this.onChange = options.onChange;
|
|
26
|
-
this.current = options.defaultStep ?? 0;
|
|
27
|
-
|
|
28
|
-
if (this.steps.length === 0) {
|
|
29
|
-
console.warn('Stepper: no .stepper-step elements found');
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (options.clickable) {
|
|
34
|
-
this.container.classList.add('stepper-clickable');
|
|
35
|
-
this.steps.forEach((step, i) => {
|
|
36
|
-
step.addEventListener('click', () => this.goTo(i), { signal: this.abortController.signal });
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
this.render();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
private render(): void {
|
|
44
|
-
this.steps.forEach((step, i) => {
|
|
45
|
-
step.classList.remove('active', 'completed');
|
|
46
|
-
|
|
47
|
-
if (i < this.current) step.classList.add('completed');
|
|
48
|
-
else if (i === this.current) step.classList.add('active');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
this.connectors.forEach((connector, i) => {
|
|
52
|
-
connector.classList.toggle('completed', i < this.current);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public next(): void {
|
|
57
|
-
if (this.current < this.steps.length - 1) {
|
|
58
|
-
this.goTo(this.current + 1);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
public prev(): void {
|
|
63
|
-
if (this.current > 0) {
|
|
64
|
-
this.goTo(this.current - 1);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
public goTo(index: number): void {
|
|
69
|
-
if (index < 0 || index >= this.steps.length) return;
|
|
70
|
-
const previous = this.current;
|
|
71
|
-
this.current = index;
|
|
72
|
-
this.render();
|
|
73
|
-
if (this.onChange && previous !== index) {
|
|
74
|
-
this.onChange(index, previous);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public setError(index: number): void {
|
|
79
|
-
if (index < 0 || index >= this.steps.length) return;
|
|
80
|
-
this.steps[index].classList.add('error');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public clearError(index: number): void {
|
|
84
|
-
if (index < 0 || index >= this.steps.length) return;
|
|
85
|
-
this.steps[index].classList.remove('error');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public getStep(): number {
|
|
89
|
-
return this.current;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
public getStepCount(): number {
|
|
93
|
-
return this.steps.length;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
public isFirst(): boolean {
|
|
97
|
-
return this.current === 0;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public isLast(): boolean {
|
|
101
|
-
return this.current === this.steps.length - 1;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
public destroy(): void {
|
|
105
|
-
this.abortController.abort();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export { Stepper, type StepperOptions };
|
package/js/table.ts
DELETED
|
@@ -1,459 +0,0 @@
|
|
|
1
|
-
import { Select } from "./select.js";
|
|
2
|
-
|
|
3
|
-
interface TableColumn {
|
|
4
|
-
key: string;
|
|
5
|
-
label: string;
|
|
6
|
-
sortable?: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface TableRow {
|
|
10
|
-
[key: string]: string | number | boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface TableOptions {
|
|
14
|
-
data?: TableRow[];
|
|
15
|
-
columns?: TableColumn[];
|
|
16
|
-
pageSize?: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
type SortDirection = 'asc' | 'desc';
|
|
20
|
-
|
|
21
|
-
class Table {
|
|
22
|
-
private container: HTMLElement;
|
|
23
|
-
private data: TableRow[];
|
|
24
|
-
private columns: TableColumn[];
|
|
25
|
-
private pageSize: number;
|
|
26
|
-
private currentPage: number;
|
|
27
|
-
private sortColumn: string | null;
|
|
28
|
-
private sortDirection: SortDirection;
|
|
29
|
-
private filterText: string;
|
|
30
|
-
private tableBody!: HTMLTableSectionElement;
|
|
31
|
-
private tableHeader!: HTMLTableSectionElement;
|
|
32
|
-
private paginationContainer!: HTMLDivElement;
|
|
33
|
-
private abortController = new AbortController();
|
|
34
|
-
|
|
35
|
-
constructor(elementOrSelector: string | HTMLElement, options: TableOptions = {}) {
|
|
36
|
-
const element = typeof elementOrSelector === 'string'
|
|
37
|
-
? document.querySelector<HTMLElement>(elementOrSelector)
|
|
38
|
-
: elementOrSelector;
|
|
39
|
-
|
|
40
|
-
if (!element) {
|
|
41
|
-
throw new Error(`Table: Element not found for selector "${elementOrSelector}"`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this.container = element;
|
|
45
|
-
this.data = options.data || [];
|
|
46
|
-
this.columns = options.columns || [];
|
|
47
|
-
this.pageSize = options.pageSize || 10;
|
|
48
|
-
this.currentPage = 1;
|
|
49
|
-
this.sortColumn = null;
|
|
50
|
-
this.sortDirection = 'asc';
|
|
51
|
-
this.filterText = '';
|
|
52
|
-
|
|
53
|
-
if (this.data.length === 0 && this.container.querySelector('table')) {
|
|
54
|
-
this.parseTableFromDOM();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
this.init();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Parses an existing HTML table in the DOM to extract data and columns
|
|
62
|
-
*/
|
|
63
|
-
private parseTableFromDOM(): void {
|
|
64
|
-
const table = this.container.querySelector('table');
|
|
65
|
-
if (!table) return;
|
|
66
|
-
|
|
67
|
-
const thead = table.querySelector('thead');
|
|
68
|
-
const tbody = table.querySelector('tbody');
|
|
69
|
-
|
|
70
|
-
if (!thead || !tbody) return;
|
|
71
|
-
|
|
72
|
-
// Parse columns from header
|
|
73
|
-
const ths = thead.querySelectorAll('th');
|
|
74
|
-
this.columns = Array.from(ths).map((th, index) => ({
|
|
75
|
-
key: `col${index}`,
|
|
76
|
-
label: th.textContent?.trim() || '',
|
|
77
|
-
sortable: true
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
|
-
// Parse data from body rows
|
|
81
|
-
const trs = tbody.querySelectorAll('tr');
|
|
82
|
-
this.data = Array.from(trs).map(tr => {
|
|
83
|
-
const row: TableRow = {};
|
|
84
|
-
const tds = tr.querySelectorAll('td');
|
|
85
|
-
|
|
86
|
-
tds.forEach((td, index) => {
|
|
87
|
-
if (this.columns[index]) {
|
|
88
|
-
row[this.columns[index].key] = td.textContent?.trim() || '';
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
return row;
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// Clear the existing static table
|
|
96
|
-
this.container.innerHTML = '';
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Initializes the table by rendering controls, structure, and content
|
|
101
|
-
*/
|
|
102
|
-
private init(): void {
|
|
103
|
-
this.renderControls();
|
|
104
|
-
this.renderTableStructure();
|
|
105
|
-
this.render();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Renders the search and page size controls
|
|
110
|
-
*/
|
|
111
|
-
private renderControls(): void {
|
|
112
|
-
const controlsDiv = document.createElement('div');
|
|
113
|
-
controlsDiv.className = 'table-controls';
|
|
114
|
-
|
|
115
|
-
// Search input
|
|
116
|
-
const searchInput = document.createElement('input');
|
|
117
|
-
searchInput.type = 'text';
|
|
118
|
-
searchInput.placeholder = 'Search...';
|
|
119
|
-
searchInput.className = 'search-input';
|
|
120
|
-
searchInput.addEventListener('input', (e) => {
|
|
121
|
-
this.handleSearch((e.target as HTMLInputElement).value);
|
|
122
|
-
}, { signal: this.abortController.signal });
|
|
123
|
-
controlsDiv.appendChild(searchInput);
|
|
124
|
-
|
|
125
|
-
// Page size selector
|
|
126
|
-
const selectGroup = document.createElement('div');
|
|
127
|
-
selectGroup.className = 'select-group';
|
|
128
|
-
|
|
129
|
-
const label = document.createElement('label');
|
|
130
|
-
label.textContent = 'Page Size';
|
|
131
|
-
selectGroup.appendChild(label);
|
|
132
|
-
|
|
133
|
-
const pageSizeSelect = document.createElement('select');
|
|
134
|
-
pageSizeSelect.className = 'page-size-select';
|
|
135
|
-
|
|
136
|
-
[5, 10, 20, 50].forEach(size => {
|
|
137
|
-
const option = document.createElement('option');
|
|
138
|
-
option.value = String(size);
|
|
139
|
-
option.textContent = `${size} per page`;
|
|
140
|
-
option.selected = size === this.pageSize;
|
|
141
|
-
pageSizeSelect.appendChild(option);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
pageSizeSelect.addEventListener('change', (e) => {
|
|
145
|
-
this.handlePageSizeChange(parseInt((e.target as HTMLSelectElement).value, 10));
|
|
146
|
-
}, { signal: this.abortController.signal });
|
|
147
|
-
|
|
148
|
-
this.assignUniqueId(pageSizeSelect, 'page-size-select-0');
|
|
149
|
-
selectGroup.appendChild(pageSizeSelect);
|
|
150
|
-
controlsDiv.appendChild(selectGroup);
|
|
151
|
-
|
|
152
|
-
this.container.appendChild(controlsDiv);
|
|
153
|
-
new Select('#' + pageSizeSelect.id);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Creates the table structure (table, thead, tbody, pagination container)
|
|
158
|
-
*/
|
|
159
|
-
private renderTableStructure(): void {
|
|
160
|
-
const wrapper = document.createElement('div');
|
|
161
|
-
wrapper.className = 'table-wrapper';
|
|
162
|
-
|
|
163
|
-
const table = document.createElement('table');
|
|
164
|
-
const thead = document.createElement('thead');
|
|
165
|
-
const tbody = document.createElement('tbody');
|
|
166
|
-
|
|
167
|
-
// Create header row
|
|
168
|
-
const tr = document.createElement('tr');
|
|
169
|
-
this.columns.forEach(col => {
|
|
170
|
-
const th = document.createElement('th');
|
|
171
|
-
th.textContent = col.label;
|
|
172
|
-
th.dataset.key = col.key;
|
|
173
|
-
|
|
174
|
-
if (col.sortable !== false) {
|
|
175
|
-
th.classList.add('sortable');
|
|
176
|
-
th.addEventListener('click', () => this.handleSort(col.key), { signal: this.abortController.signal });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
tr.appendChild(th);
|
|
180
|
-
});
|
|
181
|
-
thead.appendChild(tr);
|
|
182
|
-
|
|
183
|
-
table.appendChild(thead);
|
|
184
|
-
table.appendChild(tbody);
|
|
185
|
-
wrapper.appendChild(table);
|
|
186
|
-
this.container.appendChild(wrapper);
|
|
187
|
-
|
|
188
|
-
// Create pagination container
|
|
189
|
-
const paginationDiv = document.createElement('div');
|
|
190
|
-
paginationDiv.className = 'pagination';
|
|
191
|
-
this.container.appendChild(paginationDiv);
|
|
192
|
-
|
|
193
|
-
this.tableBody = tbody;
|
|
194
|
-
this.tableHeader = thead;
|
|
195
|
-
this.paginationContainer = paginationDiv;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Returns filtered and sorted data based on current state
|
|
200
|
-
*/
|
|
201
|
-
private getFilteredAndSortedData(): TableRow[] {
|
|
202
|
-
let processedData = [...this.data];
|
|
203
|
-
|
|
204
|
-
// Apply filter
|
|
205
|
-
if (this.filterText) {
|
|
206
|
-
const lowerFilter = this.filterText.toLowerCase();
|
|
207
|
-
processedData = processedData.filter(row => {
|
|
208
|
-
return this.columns.some(col => {
|
|
209
|
-
const val = String(row[col.key] ?? '').toLowerCase();
|
|
210
|
-
return val.includes(lowerFilter);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Apply sort
|
|
216
|
-
if (this.sortColumn) {
|
|
217
|
-
processedData.sort((a, b) => {
|
|
218
|
-
const valA = a[this.sortColumn!];
|
|
219
|
-
const valB = b[this.sortColumn!];
|
|
220
|
-
|
|
221
|
-
// Handle null/undefined values
|
|
222
|
-
if (valA == null && valB == null) return 0;
|
|
223
|
-
if (valA == null) return 1;
|
|
224
|
-
if (valB == null) return -1;
|
|
225
|
-
|
|
226
|
-
if (valA < valB) return this.sortDirection === 'asc' ? -1 : 1;
|
|
227
|
-
if (valA > valB) return this.sortDirection === 'asc' ? 1 : -1;
|
|
228
|
-
return 0;
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return processedData;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Renders the table body, pagination, and header sort indicators
|
|
237
|
-
*/
|
|
238
|
-
private render(): void {
|
|
239
|
-
const processedData = this.getFilteredAndSortedData();
|
|
240
|
-
const totalItems = processedData.length;
|
|
241
|
-
const totalPages = Math.ceil(totalItems / this.pageSize);
|
|
242
|
-
|
|
243
|
-
// Ensure current page is valid
|
|
244
|
-
if (this.currentPage > totalPages && totalPages > 0) {
|
|
245
|
-
this.currentPage = totalPages;
|
|
246
|
-
}
|
|
247
|
-
if (this.currentPage < 1 && totalPages > 0) {
|
|
248
|
-
this.currentPage = 1;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const startIndex = (this.currentPage - 1) * this.pageSize;
|
|
252
|
-
const endIndex = Math.min(startIndex + this.pageSize, totalItems);
|
|
253
|
-
const pageData = processedData.slice(startIndex, endIndex);
|
|
254
|
-
|
|
255
|
-
this.renderBody(pageData);
|
|
256
|
-
this.renderPagination(totalItems, totalPages, startIndex, endIndex);
|
|
257
|
-
this.updateHeaderSortIcons();
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Renders the table body rows
|
|
262
|
-
*/
|
|
263
|
-
private renderBody(data: TableRow[]): void {
|
|
264
|
-
this.tableBody.innerHTML = '';
|
|
265
|
-
|
|
266
|
-
if (data.length === 0) {
|
|
267
|
-
const tr = document.createElement('tr');
|
|
268
|
-
const td = document.createElement('td');
|
|
269
|
-
td.colSpan = this.columns.length;
|
|
270
|
-
td.textContent = 'No results found';
|
|
271
|
-
td.style.textAlign = 'center';
|
|
272
|
-
tr.appendChild(td);
|
|
273
|
-
this.tableBody.appendChild(tr);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
data.forEach(row => {
|
|
278
|
-
const tr = document.createElement('tr');
|
|
279
|
-
this.columns.forEach(col => {
|
|
280
|
-
const td = document.createElement('td');
|
|
281
|
-
td.textContent = String(row[col.key] ?? '');
|
|
282
|
-
td.setAttribute('data-label', col.label); // For mobile view
|
|
283
|
-
tr.appendChild(td);
|
|
284
|
-
});
|
|
285
|
-
this.tableBody.appendChild(tr);
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Updates the sort direction indicators in table headers
|
|
291
|
-
*/
|
|
292
|
-
private updateHeaderSortIcons(): void {
|
|
293
|
-
const ths = this.tableHeader.querySelectorAll('th');
|
|
294
|
-
ths.forEach(th => {
|
|
295
|
-
th.classList.remove('sort-asc', 'sort-desc');
|
|
296
|
-
if (th.dataset.key === this.sortColumn) {
|
|
297
|
-
th.classList.add(this.sortDirection === 'asc' ? 'sort-asc' : 'sort-desc');
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Renders pagination controls and info
|
|
304
|
-
*/
|
|
305
|
-
private renderPagination(
|
|
306
|
-
totalItems: number,
|
|
307
|
-
totalPages: number,
|
|
308
|
-
startIndex: number,
|
|
309
|
-
endIndex: number
|
|
310
|
-
): void {
|
|
311
|
-
this.paginationContainer.innerHTML = '';
|
|
312
|
-
|
|
313
|
-
if (totalItems === 0) return;
|
|
314
|
-
|
|
315
|
-
// Info text
|
|
316
|
-
const info = document.createElement('div');
|
|
317
|
-
info.className = 'pagination-info';
|
|
318
|
-
info.textContent = `Showing ${startIndex + 1} to ${endIndex} of ${totalItems} entries`;
|
|
319
|
-
this.paginationContainer.appendChild(info);
|
|
320
|
-
|
|
321
|
-
// Pagination buttons
|
|
322
|
-
const buttonsDiv = document.createElement('div');
|
|
323
|
-
buttonsDiv.className = 'pagination-buttons';
|
|
324
|
-
|
|
325
|
-
// Previous button
|
|
326
|
-
const prevBtn = document.createElement('button');
|
|
327
|
-
prevBtn.className = 'page-btn';
|
|
328
|
-
prevBtn.textContent = 'Previous';
|
|
329
|
-
prevBtn.disabled = this.currentPage === 1;
|
|
330
|
-
prevBtn.addEventListener('click', () => this.setPage(this.currentPage - 1));
|
|
331
|
-
buttonsDiv.appendChild(prevBtn);
|
|
332
|
-
|
|
333
|
-
// Calculate page range to display (max 5 pages)
|
|
334
|
-
let startPage = Math.max(1, this.currentPage - 2);
|
|
335
|
-
let endPage = Math.min(totalPages, startPage + 4);
|
|
336
|
-
|
|
337
|
-
if (endPage - startPage < 4) {
|
|
338
|
-
startPage = Math.max(1, endPage - 4);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Page number buttons
|
|
342
|
-
for (let i = startPage; i <= endPage; i++) {
|
|
343
|
-
const btn = document.createElement('button');
|
|
344
|
-
btn.className = `page-btn ${i === this.currentPage ? 'active' : ''}`;
|
|
345
|
-
btn.textContent = String(i);
|
|
346
|
-
btn.addEventListener('click', () => this.setPage(i));
|
|
347
|
-
buttonsDiv.appendChild(btn);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Next button
|
|
351
|
-
const nextBtn = document.createElement('button');
|
|
352
|
-
nextBtn.className = 'page-btn';
|
|
353
|
-
nextBtn.textContent = 'Next';
|
|
354
|
-
nextBtn.disabled = this.currentPage === totalPages;
|
|
355
|
-
nextBtn.addEventListener('click', () => this.setPage(this.currentPage + 1));
|
|
356
|
-
buttonsDiv.appendChild(nextBtn);
|
|
357
|
-
|
|
358
|
-
this.paginationContainer.appendChild(buttonsDiv);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Handles search input changes
|
|
363
|
-
*/
|
|
364
|
-
private handleSearch(text: string): void {
|
|
365
|
-
this.filterText = text;
|
|
366
|
-
this.currentPage = 1; // Reset to first page on search
|
|
367
|
-
this.render();
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Handles column header clicks for sorting
|
|
372
|
-
*/
|
|
373
|
-
private handleSort(key: string): void {
|
|
374
|
-
if (this.sortColumn === key) {
|
|
375
|
-
// Toggle sort direction
|
|
376
|
-
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
|
|
377
|
-
} else {
|
|
378
|
-
this.sortColumn = key;
|
|
379
|
-
this.sortDirection = 'asc';
|
|
380
|
-
}
|
|
381
|
-
this.render();
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Handles page size changes
|
|
386
|
-
*/
|
|
387
|
-
private handlePageSizeChange(size: number): void {
|
|
388
|
-
this.pageSize = size;
|
|
389
|
-
this.currentPage = 1;
|
|
390
|
-
this.render();
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* Sets the current page and re-renders
|
|
395
|
-
*/
|
|
396
|
-
private setPage(page: number): void {
|
|
397
|
-
this.currentPage = page;
|
|
398
|
-
this.render();
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
* Assigns a unique ID to an element, incrementing if necessary
|
|
403
|
-
*/
|
|
404
|
-
private assignUniqueId(element: HTMLElement, baseId: string): string | null {
|
|
405
|
-
if (!element || !baseId) return null;
|
|
406
|
-
|
|
407
|
-
let id = baseId;
|
|
408
|
-
let counter = 1;
|
|
409
|
-
|
|
410
|
-
// If baseId already ends with a number, extract it
|
|
411
|
-
const match = baseId.match(/^(.*?)(\d+)$/);
|
|
412
|
-
if (match) {
|
|
413
|
-
id = match[1];
|
|
414
|
-
counter = parseInt(match[2], 10);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
let uniqueId = baseId;
|
|
418
|
-
|
|
419
|
-
while (document.getElementById(uniqueId)) {
|
|
420
|
-
counter++;
|
|
421
|
-
uniqueId = `${id}${counter}`;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
element.id = uniqueId;
|
|
425
|
-
return uniqueId;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Public API: Updates the table data and re-renders
|
|
430
|
-
*/
|
|
431
|
-
public setData(data: TableRow[]): void {
|
|
432
|
-
this.data = data;
|
|
433
|
-
this.currentPage = 1;
|
|
434
|
-
this.render();
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Public API: Updates the columns and re-renders
|
|
439
|
-
*/
|
|
440
|
-
public setColumns(columns: TableColumn[]): void {
|
|
441
|
-
this.columns = columns;
|
|
442
|
-
this.container.innerHTML = '';
|
|
443
|
-
this.init();
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Public API: Gets the current filtered and sorted data
|
|
448
|
-
*/
|
|
449
|
-
public getData(): TableRow[] {
|
|
450
|
-
return this.getFilteredAndSortedData();
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
public destroy(): void {
|
|
454
|
-
this.abortController.abort();
|
|
455
|
-
this.container.innerHTML = '';
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export { Table, TableRow, TableColumn, TableOptions };
|