secure-ui-components 0.1.0-beta.1
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/LICENSE +21 -0
- package/README.md +310 -0
- package/dist/components/secure-datetime/secure-datetime.css +263 -0
- package/dist/components/secure-datetime/secure-datetime.d.ts +124 -0
- package/dist/components/secure-datetime/secure-datetime.d.ts.map +1 -0
- package/dist/components/secure-datetime/secure-datetime.js +610 -0
- package/dist/components/secure-datetime/secure-datetime.js.map +1 -0
- package/dist/components/secure-file-upload/secure-file-upload.css +334 -0
- package/dist/components/secure-file-upload/secure-file-upload.d.ts +150 -0
- package/dist/components/secure-file-upload/secure-file-upload.d.ts.map +1 -0
- package/dist/components/secure-file-upload/secure-file-upload.js +911 -0
- package/dist/components/secure-file-upload/secure-file-upload.js.map +1 -0
- package/dist/components/secure-form/secure-form.css +62 -0
- package/dist/components/secure-form/secure-form.d.ts +128 -0
- package/dist/components/secure-form/secure-form.d.ts.map +1 -0
- package/dist/components/secure-form/secure-form.js +697 -0
- package/dist/components/secure-form/secure-form.js.map +1 -0
- package/dist/components/secure-input/secure-input.css +168 -0
- package/dist/components/secure-input/secure-input.d.ts +114 -0
- package/dist/components/secure-input/secure-input.d.ts.map +1 -0
- package/dist/components/secure-input/secure-input.js +785 -0
- package/dist/components/secure-input/secure-input.js.map +1 -0
- package/dist/components/secure-select/secure-select.css +195 -0
- package/dist/components/secure-select/secure-select.d.ts +149 -0
- package/dist/components/secure-select/secure-select.d.ts.map +1 -0
- package/dist/components/secure-select/secure-select.js +634 -0
- package/dist/components/secure-select/secure-select.js.map +1 -0
- package/dist/components/secure-submit-button/secure-submit-button.css +135 -0
- package/dist/components/secure-submit-button/secure-submit-button.d.ts +61 -0
- package/dist/components/secure-submit-button/secure-submit-button.d.ts.map +1 -0
- package/dist/components/secure-submit-button/secure-submit-button.js +399 -0
- package/dist/components/secure-submit-button/secure-submit-button.js.map +1 -0
- package/dist/components/secure-table/secure-table.css +341 -0
- package/dist/components/secure-table/secure-table.d.ts +64 -0
- package/dist/components/secure-table/secure-table.d.ts.map +1 -0
- package/dist/components/secure-table/secure-table.js +567 -0
- package/dist/components/secure-table/secure-table.js.map +1 -0
- package/dist/components/secure-textarea/secure-textarea.css +153 -0
- package/dist/components/secure-textarea/secure-textarea.d.ts +111 -0
- package/dist/components/secure-textarea/secure-textarea.d.ts.map +1 -0
- package/dist/components/secure-textarea/secure-textarea.js +477 -0
- package/dist/components/secure-textarea/secure-textarea.js.map +1 -0
- package/dist/core/base-component.d.ts +134 -0
- package/dist/core/base-component.d.ts.map +1 -0
- package/dist/core/base-component.js +303 -0
- package/dist/core/base-component.js.map +1 -0
- package/dist/core/base.css +37 -0
- package/dist/core/security-config.d.ts +89 -0
- package/dist/core/security-config.d.ts.map +1 -0
- package/dist/core/security-config.js +273 -0
- package/dist/core/security-config.js.map +1 -0
- package/dist/core/types.d.ts +212 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +89 -0
- package/dist/styles/tokens.css +257 -0
- package/package.json +118 -0
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure Table Component
|
|
3
|
+
*
|
|
4
|
+
* A security-aware data table component with filtering, sorting, and pagination.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Real-time filtering/search across all columns
|
|
8
|
+
* - Column sorting (ascending/descending)
|
|
9
|
+
* - Pagination
|
|
10
|
+
* - Security tier-based column masking
|
|
11
|
+
* - XSS prevention via sanitization
|
|
12
|
+
* - Audit logging for data access
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <secure-table
|
|
16
|
+
* id="userTable"
|
|
17
|
+
* security-tier="sensitive"
|
|
18
|
+
* ></secure-table>
|
|
19
|
+
*
|
|
20
|
+
* // Set data programmatically
|
|
21
|
+
* const table = document.getElementById('userTable');
|
|
22
|
+
* table.data = [
|
|
23
|
+
* { id: 1, name: 'John', email: 'john@example.com' },
|
|
24
|
+
* { id: 2, name: 'Jane', email: 'jane@example.com' }
|
|
25
|
+
* ];
|
|
26
|
+
* table.columns = [
|
|
27
|
+
* { key: 'id', label: 'ID', sortable: true },
|
|
28
|
+
* { key: 'name', label: 'Name', sortable: true, filterable: true },
|
|
29
|
+
* { key: 'email', label: 'Email', sortable: true, filterable: true, tier: 'sensitive' }
|
|
30
|
+
* ];
|
|
31
|
+
*/
|
|
32
|
+
import { SecureBaseComponent } from '../../core/base-component.js';
|
|
33
|
+
import { SecurityTier } from '../../core/security-config.js';
|
|
34
|
+
export class SecureTable extends SecureBaseComponent {
|
|
35
|
+
/**
|
|
36
|
+
* Data array for the table
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
#data = [];
|
|
40
|
+
/**
|
|
41
|
+
* Column configuration
|
|
42
|
+
* @private
|
|
43
|
+
*/
|
|
44
|
+
#columns = [];
|
|
45
|
+
/**
|
|
46
|
+
* Filtered data after applying search
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
#filteredData = [];
|
|
50
|
+
/**
|
|
51
|
+
* Current filter/search term
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
#filterTerm = '';
|
|
55
|
+
/**
|
|
56
|
+
* Current sort configuration
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
#sortConfig = { column: null, direction: 'asc' };
|
|
60
|
+
/**
|
|
61
|
+
* Pagination state
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
#pagination = { currentPage: 1, pageSize: 10 };
|
|
65
|
+
/**
|
|
66
|
+
* Whether the component is using slotted server-rendered content
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
#usingSlottedContent = false;
|
|
70
|
+
constructor() {
|
|
71
|
+
super();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Required by abstract base class, but this component manages its own rendering
|
|
75
|
+
* via the private #render() method.
|
|
76
|
+
* @protected
|
|
77
|
+
*/
|
|
78
|
+
render() {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Component lifecycle - called when added to DOM
|
|
83
|
+
*/
|
|
84
|
+
connectedCallback() {
|
|
85
|
+
// Initialize security tier, config, and audit - but skip the base render
|
|
86
|
+
// lifecycle since the table manages its own innerHTML-based rendering for
|
|
87
|
+
// dynamic sort/filter/pagination updates.
|
|
88
|
+
this.initializeSecurity();
|
|
89
|
+
// Try to parse server-rendered content first (progressive enhancement)
|
|
90
|
+
const slottedTable = this.querySelector('table[slot="table"]');
|
|
91
|
+
const parsed = this.#parseSlottedTable();
|
|
92
|
+
if (parsed) {
|
|
93
|
+
console.log('SecureTable: Using server-rendered content', {
|
|
94
|
+
columns: parsed.columns.length,
|
|
95
|
+
rows: parsed.data.length
|
|
96
|
+
});
|
|
97
|
+
this.#usingSlottedContent = true;
|
|
98
|
+
this.#columns = parsed.columns;
|
|
99
|
+
this.#data = parsed.data;
|
|
100
|
+
this.#filteredData = [...parsed.data];
|
|
101
|
+
// Remove the server-rendered table from light DOM now that data is extracted
|
|
102
|
+
if (slottedTable) {
|
|
103
|
+
slottedTable.remove();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
this.#render();
|
|
107
|
+
this.audit('table_mounted', {
|
|
108
|
+
rowCount: this.#data.length,
|
|
109
|
+
columnCount: this.#columns.length,
|
|
110
|
+
usingSlottedContent: this.#usingSlottedContent
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Parse server-rendered table from light DOM slot
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
#parseSlottedTable() {
|
|
118
|
+
const slottedTable = this.querySelector('table[slot="table"]');
|
|
119
|
+
if (!slottedTable)
|
|
120
|
+
return null;
|
|
121
|
+
try {
|
|
122
|
+
// Extract columns from <thead>
|
|
123
|
+
const headers = slottedTable.querySelectorAll('thead th');
|
|
124
|
+
if (headers.length === 0)
|
|
125
|
+
return null;
|
|
126
|
+
const columns = Array.from(headers).map(th => {
|
|
127
|
+
const key = th.getAttribute('data-key') || th.textContent.trim().toLowerCase().replace(/\s+/g, '_');
|
|
128
|
+
return {
|
|
129
|
+
key: key,
|
|
130
|
+
label: th.textContent.trim().replace(/\s+$/, ''), // Remove trailing spaces/badges
|
|
131
|
+
sortable: th.hasAttribute('data-sortable') ? th.getAttribute('data-sortable') !== 'false' : true,
|
|
132
|
+
filterable: th.hasAttribute('data-filterable') ? th.getAttribute('data-filterable') !== 'false' : undefined,
|
|
133
|
+
tier: (th.getAttribute('data-tier') || undefined),
|
|
134
|
+
width: th.getAttribute('data-width') || undefined,
|
|
135
|
+
render: th.hasAttribute('data-render-html') ? this.#createRenderFunction(th) : undefined
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
// Extract data from <tbody>
|
|
139
|
+
const rows = slottedTable.querySelectorAll('tbody tr');
|
|
140
|
+
const data = Array.from(rows).map((tr, _rowIndex) => {
|
|
141
|
+
const cells = tr.querySelectorAll('td');
|
|
142
|
+
const row = {};
|
|
143
|
+
cells.forEach((td, index) => {
|
|
144
|
+
if (index < columns.length) {
|
|
145
|
+
const column = columns[index];
|
|
146
|
+
const dataKey = td.getAttribute('data-key') || column.key;
|
|
147
|
+
// Store both text content and HTML if needed
|
|
148
|
+
if (td.innerHTML.trim().includes('<')) {
|
|
149
|
+
// Cell contains HTML (like forms, badges, etc.)
|
|
150
|
+
row[dataKey] = td.textContent.trim();
|
|
151
|
+
row[`${dataKey}_html`] = td.innerHTML.trim();
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
row[dataKey] = td.textContent.trim();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return row;
|
|
159
|
+
});
|
|
160
|
+
return { columns, data };
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console.error('SecureTable: Error parsing slotted table', error);
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Create a render function for HTML content
|
|
169
|
+
* @private
|
|
170
|
+
*/
|
|
171
|
+
#createRenderFunction(_th) {
|
|
172
|
+
return (value, row, columnKey) => {
|
|
173
|
+
const htmlKey = `${columnKey}_html`;
|
|
174
|
+
return row[htmlKey] || this.#sanitize(value);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Set table data
|
|
179
|
+
*/
|
|
180
|
+
set data(data) {
|
|
181
|
+
if (!Array.isArray(data)) {
|
|
182
|
+
console.error('SecureTable: data must be an array');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
console.log('SecureTable: Setting data, count:', data.length);
|
|
186
|
+
this.#data = data;
|
|
187
|
+
this.#filteredData = [...data];
|
|
188
|
+
this.#render();
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get table data
|
|
192
|
+
*/
|
|
193
|
+
get data() {
|
|
194
|
+
return this.#data;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Set column configuration
|
|
198
|
+
*/
|
|
199
|
+
set columns(columns) {
|
|
200
|
+
if (!Array.isArray(columns)) {
|
|
201
|
+
console.error('SecureTable: columns must be an array');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
console.log('SecureTable: Setting columns, count:', columns.length);
|
|
205
|
+
this.#columns = columns;
|
|
206
|
+
this.#render();
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Get column configuration
|
|
210
|
+
*/
|
|
211
|
+
get columns() {
|
|
212
|
+
return this.#columns;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Apply filter to data
|
|
216
|
+
* @private
|
|
217
|
+
*/
|
|
218
|
+
#applyFilter(term) {
|
|
219
|
+
this.#filterTerm = term.toLowerCase();
|
|
220
|
+
if (!this.#filterTerm) {
|
|
221
|
+
this.#filteredData = [...this.#data];
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
this.#filteredData = this.#data.filter(row => {
|
|
225
|
+
return this.#columns.some(col => {
|
|
226
|
+
if (col.filterable === false)
|
|
227
|
+
return false;
|
|
228
|
+
const value = String(row[col.key] ?? '').toLowerCase();
|
|
229
|
+
return value.includes(this.#filterTerm);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
this.#pagination.currentPage = 1; // Reset to first page
|
|
234
|
+
this.#updateTableContent();
|
|
235
|
+
this.audit('table_filtered', {
|
|
236
|
+
filterTerm: term,
|
|
237
|
+
resultCount: this.#filteredData.length
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Apply sorting to data
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
#applySort(columnKey) {
|
|
245
|
+
if (this.#sortConfig.column === columnKey) {
|
|
246
|
+
// Toggle direction
|
|
247
|
+
this.#sortConfig.direction = this.#sortConfig.direction === 'asc' ? 'desc' : 'asc';
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
this.#sortConfig.column = columnKey;
|
|
251
|
+
this.#sortConfig.direction = 'asc';
|
|
252
|
+
}
|
|
253
|
+
this.#filteredData.sort((a, b) => {
|
|
254
|
+
const aVal = a[columnKey];
|
|
255
|
+
const bVal = b[columnKey];
|
|
256
|
+
let comparison = 0;
|
|
257
|
+
if (aVal > bVal)
|
|
258
|
+
comparison = 1;
|
|
259
|
+
if (aVal < bVal)
|
|
260
|
+
comparison = -1;
|
|
261
|
+
return this.#sortConfig.direction === 'asc' ? comparison : -comparison;
|
|
262
|
+
});
|
|
263
|
+
this.#updateTableContent();
|
|
264
|
+
this.audit('table_sorted', {
|
|
265
|
+
column: columnKey,
|
|
266
|
+
direction: this.#sortConfig.direction
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Change page
|
|
271
|
+
* @private
|
|
272
|
+
*/
|
|
273
|
+
#goToPage(pageNumber) {
|
|
274
|
+
const totalPages = Math.ceil(this.#filteredData.length / this.#pagination.pageSize);
|
|
275
|
+
if (pageNumber < 1 || pageNumber > totalPages)
|
|
276
|
+
return;
|
|
277
|
+
this.#pagination.currentPage = pageNumber;
|
|
278
|
+
this.#updateTableContent();
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Simple HTML sanitization to prevent XSS
|
|
282
|
+
* @private
|
|
283
|
+
*/
|
|
284
|
+
#sanitize(str) {
|
|
285
|
+
if (str === null || str === undefined || str === '')
|
|
286
|
+
return '';
|
|
287
|
+
return String(str)
|
|
288
|
+
.replace(/&/g, '&')
|
|
289
|
+
.replace(/</g, '<')
|
|
290
|
+
.replace(/>/g, '>')
|
|
291
|
+
.replace(/"/g, '"')
|
|
292
|
+
.replace(/'/g, ''');
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Mask sensitive column values based on tier
|
|
296
|
+
* @private
|
|
297
|
+
*/
|
|
298
|
+
#maskValue(value, tier) {
|
|
299
|
+
if (value === null || value === undefined || value === '')
|
|
300
|
+
return '-';
|
|
301
|
+
const strValue = String(value);
|
|
302
|
+
if (tier === SecurityTier.SENSITIVE && strValue.length > 4) {
|
|
303
|
+
return '\u2022'.repeat(strValue.length - 4) + strValue.slice(-4);
|
|
304
|
+
}
|
|
305
|
+
if (tier === SecurityTier.CRITICAL) {
|
|
306
|
+
return '\u2022'.repeat(strValue.length);
|
|
307
|
+
}
|
|
308
|
+
return this.#sanitize(strValue);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Render cell content with custom render function if available
|
|
312
|
+
* @private
|
|
313
|
+
*/
|
|
314
|
+
#renderCell(value, row, column) {
|
|
315
|
+
// If column has custom render function, use it
|
|
316
|
+
if (typeof column.render === 'function') {
|
|
317
|
+
return column.render(value, row, column.key);
|
|
318
|
+
}
|
|
319
|
+
// Check if we have stored HTML content from server-rendered table
|
|
320
|
+
const htmlKey = `${column.key}_html`;
|
|
321
|
+
if (row[htmlKey]) {
|
|
322
|
+
// Don't mask HTML content, it's already rendered
|
|
323
|
+
return row[htmlKey];
|
|
324
|
+
}
|
|
325
|
+
// Otherwise, mask value based on security tier
|
|
326
|
+
return this.#maskValue(value, column.tier);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Generate the table body, thead, and pagination HTML
|
|
330
|
+
* @private
|
|
331
|
+
*/
|
|
332
|
+
#renderTableContent() {
|
|
333
|
+
const totalPages = Math.ceil(this.#filteredData.length / this.#pagination.pageSize);
|
|
334
|
+
const startIndex = (this.#pagination.currentPage - 1) * this.#pagination.pageSize;
|
|
335
|
+
const endIndex = startIndex + this.#pagination.pageSize;
|
|
336
|
+
const pageData = this.#filteredData.slice(startIndex, endIndex);
|
|
337
|
+
let tableHtml;
|
|
338
|
+
let paginationHtml;
|
|
339
|
+
if (pageData.length === 0 || this.#columns.length === 0) {
|
|
340
|
+
const emptyHeading = this.#columns.length === 0 ? 'No columns configured' : 'No results found';
|
|
341
|
+
const emptyBody = this.#columns.length === 0 ? 'Set the columns property to configure the table' : 'Try adjusting your search term';
|
|
342
|
+
tableHtml = `
|
|
343
|
+
<div class="empty-state">
|
|
344
|
+
<div class="empty-state-icon" aria-hidden="true">\uD83D\uDD0D</div>
|
|
345
|
+
<h3>${this.#sanitize(emptyHeading)}</h3>
|
|
346
|
+
<p>${this.#sanitize(emptyBody)}</p>
|
|
347
|
+
</div>`;
|
|
348
|
+
paginationHtml = '';
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
tableHtml = `
|
|
352
|
+
<div class="table-wrapper">
|
|
353
|
+
<table class="data-table">
|
|
354
|
+
<thead>
|
|
355
|
+
<tr>
|
|
356
|
+
${this.#columns.map(col => {
|
|
357
|
+
const isSorted = this.#sortConfig.column === col.key;
|
|
358
|
+
const sortArrow = isSorted ? (this.#sortConfig.direction === 'asc' ? '\u25B2' : '\u25BC') : '\u25B2';
|
|
359
|
+
const ariaSortAttr = col.sortable !== false
|
|
360
|
+
? `aria-sort="${isSorted ? (this.#sortConfig.direction === 'asc' ? 'ascending' : 'descending') : 'none'}"`
|
|
361
|
+
: '';
|
|
362
|
+
return `
|
|
363
|
+
<th
|
|
364
|
+
class="${col.sortable !== false ? 'sortable' : ''} ${isSorted ? 'sorted' : ''}"
|
|
365
|
+
data-column="${this.#sanitize(col.key)}"
|
|
366
|
+
${ariaSortAttr}
|
|
367
|
+
>
|
|
368
|
+
${this.#sanitize(col.label)}
|
|
369
|
+
${col.sortable !== false ? `<span class="sort-indicator" aria-hidden="true">${sortArrow}</span>` : ''}
|
|
370
|
+
${col.tier ? `<span class="security-badge" aria-hidden="true">${this.#sanitize(col.tier)}</span>` : ''}
|
|
371
|
+
</th>`;
|
|
372
|
+
}).join('')}
|
|
373
|
+
</tr>
|
|
374
|
+
</thead>
|
|
375
|
+
<tbody>
|
|
376
|
+
${pageData.map(row => `
|
|
377
|
+
<tr>
|
|
378
|
+
${this.#columns.map(col => `
|
|
379
|
+
<td>${this.#renderCell(row[col.key], row, col)}</td>
|
|
380
|
+
`).join('')}
|
|
381
|
+
</tr>
|
|
382
|
+
`).join('')}
|
|
383
|
+
</tbody>
|
|
384
|
+
</table>
|
|
385
|
+
</div>`;
|
|
386
|
+
paginationHtml = totalPages > 1 ? `
|
|
387
|
+
<div class="pagination">
|
|
388
|
+
<div class="pagination-info">
|
|
389
|
+
Showing ${startIndex + 1}-${Math.min(endIndex, this.#filteredData.length)} of ${this.#filteredData.length} results
|
|
390
|
+
</div>
|
|
391
|
+
<div class="pagination-controls">
|
|
392
|
+
<button class="pagination-button" id="prevBtn" ${this.#pagination.currentPage === 1 ? 'disabled' : ''}>
|
|
393
|
+
\u2190 Previous
|
|
394
|
+
</button>
|
|
395
|
+
${this.#renderPageNumbers(totalPages)}
|
|
396
|
+
<button class="pagination-button" id="nextBtn" ${this.#pagination.currentPage === totalPages ? 'disabled' : ''}>
|
|
397
|
+
Next \u2192
|
|
398
|
+
</button>
|
|
399
|
+
</div>
|
|
400
|
+
</div>` : '';
|
|
401
|
+
}
|
|
402
|
+
return { tableHtml, paginationHtml };
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Full initial render of the table
|
|
406
|
+
* @private
|
|
407
|
+
*/
|
|
408
|
+
#render() {
|
|
409
|
+
if (!this.shadowRoot)
|
|
410
|
+
return;
|
|
411
|
+
const { tableHtml, paginationHtml } = this.#renderTableContent();
|
|
412
|
+
// Styles injected as <link> elements inside innerHTML — loads from 'self' (CSP-safe).
|
|
413
|
+
// getBaseStylesheetUrl() uses import.meta.url from base-component.js so the path
|
|
414
|
+
// resolves correctly regardless of where secure-table.js is located.
|
|
415
|
+
this.shadowRoot.innerHTML = `
|
|
416
|
+
<link rel="stylesheet" href="${this.getBaseStylesheetUrl()}">
|
|
417
|
+
<link rel="stylesheet" href="${new URL('./secure-table.css', import.meta.url).href}">
|
|
418
|
+
<!-- Slot for server-rendered table (fallback when JS fails to load) -->
|
|
419
|
+
<slot name="table"></slot>
|
|
420
|
+
|
|
421
|
+
<div class="table-container">
|
|
422
|
+
<div class="table-header">
|
|
423
|
+
<input
|
|
424
|
+
type="search"
|
|
425
|
+
class="search-input"
|
|
426
|
+
placeholder="Search across all columns..."
|
|
427
|
+
value="${this.#sanitize(this.#filterTerm)}"
|
|
428
|
+
id="searchInput"
|
|
429
|
+
/>
|
|
430
|
+
</div>
|
|
431
|
+
<div id="tableContent">${tableHtml}</div>
|
|
432
|
+
<div id="paginationContent">${paginationHtml}</div>
|
|
433
|
+
</div>
|
|
434
|
+
`;
|
|
435
|
+
// Attach event listeners
|
|
436
|
+
this.#attachEventListeners();
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Partial update — only replaces table body and pagination, preserving search input focus.
|
|
440
|
+
* @private
|
|
441
|
+
*/
|
|
442
|
+
#updateTableContent() {
|
|
443
|
+
if (!this.shadowRoot)
|
|
444
|
+
return;
|
|
445
|
+
const tableContainer = this.shadowRoot.getElementById('tableContent');
|
|
446
|
+
const paginationContainer = this.shadowRoot.getElementById('paginationContent');
|
|
447
|
+
if (!tableContainer) {
|
|
448
|
+
// Fallback to full render if containers don't exist yet
|
|
449
|
+
this.#render();
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const { tableHtml, paginationHtml } = this.#renderTableContent();
|
|
453
|
+
tableContainer.innerHTML = tableHtml;
|
|
454
|
+
if (paginationContainer) {
|
|
455
|
+
paginationContainer.innerHTML = paginationHtml;
|
|
456
|
+
}
|
|
457
|
+
// Re-attach listeners for table and pagination (search input listener is preserved)
|
|
458
|
+
this.#attachTableEventListeners();
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Render page number buttons
|
|
462
|
+
* @private
|
|
463
|
+
*/
|
|
464
|
+
#renderPageNumbers(totalPages) {
|
|
465
|
+
const maxButtons = 5;
|
|
466
|
+
let startPage = Math.max(1, this.#pagination.currentPage - Math.floor(maxButtons / 2));
|
|
467
|
+
const endPage = Math.min(totalPages, startPage + maxButtons - 1);
|
|
468
|
+
if (endPage - startPage < maxButtons - 1) {
|
|
469
|
+
startPage = Math.max(1, endPage - maxButtons + 1);
|
|
470
|
+
}
|
|
471
|
+
let buttons = '';
|
|
472
|
+
for (let i = startPage; i <= endPage; i++) {
|
|
473
|
+
buttons += `
|
|
474
|
+
<button
|
|
475
|
+
class="pagination-button ${i === this.#pagination.currentPage ? 'active' : ''}"
|
|
476
|
+
data-page="${i}"
|
|
477
|
+
>
|
|
478
|
+
${i}
|
|
479
|
+
</button>
|
|
480
|
+
`;
|
|
481
|
+
}
|
|
482
|
+
return buttons;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Attach all event listeners (called on full render only)
|
|
486
|
+
* @private
|
|
487
|
+
*/
|
|
488
|
+
#attachEventListeners() {
|
|
489
|
+
// Search input — only attached once on full render, preserved across partial updates
|
|
490
|
+
const searchInput = this.shadowRoot.getElementById('searchInput');
|
|
491
|
+
if (searchInput) {
|
|
492
|
+
searchInput.addEventListener('input', (e) => {
|
|
493
|
+
this.#applyFilter(e.target.value);
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
// Table and pagination listeners
|
|
497
|
+
this.#attachTableEventListeners();
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Attach event listeners for table headers and pagination (called on every update)
|
|
501
|
+
* @private
|
|
502
|
+
*/
|
|
503
|
+
#attachTableEventListeners() {
|
|
504
|
+
// Column sorting
|
|
505
|
+
const headers = this.shadowRoot.querySelectorAll('th.sortable');
|
|
506
|
+
headers.forEach(th => {
|
|
507
|
+
th.addEventListener('click', () => {
|
|
508
|
+
const column = th.getAttribute('data-column');
|
|
509
|
+
if (!column)
|
|
510
|
+
return;
|
|
511
|
+
this.#applySort(column);
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
// Pagination
|
|
515
|
+
const prevBtn = this.shadowRoot.getElementById('prevBtn');
|
|
516
|
+
const nextBtn = this.shadowRoot.getElementById('nextBtn');
|
|
517
|
+
if (prevBtn) {
|
|
518
|
+
prevBtn.addEventListener('click', () => {
|
|
519
|
+
this.#goToPage(this.#pagination.currentPage - 1);
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
if (nextBtn) {
|
|
523
|
+
nextBtn.addEventListener('click', () => {
|
|
524
|
+
this.#goToPage(this.#pagination.currentPage + 1);
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
// Page number buttons
|
|
528
|
+
const pageButtons = this.shadowRoot.querySelectorAll('.pagination-button[data-page]');
|
|
529
|
+
pageButtons.forEach(btn => {
|
|
530
|
+
btn.addEventListener('click', () => {
|
|
531
|
+
const page = parseInt(btn.getAttribute('data-page'), 10);
|
|
532
|
+
this.#goToPage(page);
|
|
533
|
+
});
|
|
534
|
+
});
|
|
535
|
+
// Action button delegation — dispatches 'table-action' CustomEvent on the host
|
|
536
|
+
// element when any [data-action] element inside the table is clicked.
|
|
537
|
+
// This allows page-level scripts to handle action buttons without needing
|
|
538
|
+
// access to the closed shadow DOM.
|
|
539
|
+
const tableContent = this.shadowRoot.getElementById('tableContent');
|
|
540
|
+
if (tableContent) {
|
|
541
|
+
tableContent.addEventListener('click', (e) => {
|
|
542
|
+
const target = e.target.closest('[data-action]');
|
|
543
|
+
if (!target)
|
|
544
|
+
return;
|
|
545
|
+
const action = target.getAttribute('data-action');
|
|
546
|
+
// Collect all data-* attributes from the action element
|
|
547
|
+
const detail = { action: action };
|
|
548
|
+
for (const attr of Array.from(target.attributes)) {
|
|
549
|
+
if (attr.name.startsWith('data-') && attr.name !== 'data-action') {
|
|
550
|
+
// Convert data-user-id to userId style key
|
|
551
|
+
const key = attr.name.slice(5).replace(/-([a-z])/g, (_match, c) => c.toUpperCase());
|
|
552
|
+
detail[key] = attr.value;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
this.dispatchEvent(new CustomEvent('table-action', {
|
|
556
|
+
bubbles: true,
|
|
557
|
+
composed: true,
|
|
558
|
+
detail
|
|
559
|
+
}));
|
|
560
|
+
this.audit('table_action', detail);
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
// Register the custom element
|
|
566
|
+
customElements.define('secure-table', SecureTable);
|
|
567
|
+
//# sourceMappingURL=secure-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure-table.js","sourceRoot":"","sources":["../../../src/components/secure-table/secure-table.ts"],"names":[],"mappings":"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"}
|