@zvndev/yable-vanilla 0.1.0
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 +122 -0
- package/dist/index.cjs +572 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +74 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.js +549 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
import { createTable, functionalUpdate } from '@zvndev/yable-core';
|
|
2
|
+
export { aggregationFns, createColumnHelper, filterFns, functionalUpdate, sortingFns } from '@zvndev/yable-core';
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
|
|
6
|
+
// src/renderer.ts
|
|
7
|
+
function esc(value) {
|
|
8
|
+
const s = String(value ?? "");
|
|
9
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
10
|
+
}
|
|
11
|
+
function escAttr(value) {
|
|
12
|
+
const s = String(value ?? "");
|
|
13
|
+
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
14
|
+
}
|
|
15
|
+
function renderTable(table, opts = {}) {
|
|
16
|
+
const classes = [
|
|
17
|
+
"yable",
|
|
18
|
+
opts.theme && `yable-theme-${escAttr(opts.theme)}`,
|
|
19
|
+
opts.stickyHeader && "yable--sticky-header",
|
|
20
|
+
opts.striped && "yable--striped",
|
|
21
|
+
opts.bordered && "yable--bordered",
|
|
22
|
+
opts.compact && "yable--compact"
|
|
23
|
+
].filter(Boolean).join(" ");
|
|
24
|
+
const rows = table.getRowModel().rows;
|
|
25
|
+
let html = `<div class="${classes}" role="grid" aria-rowcount="${rows.length}" aria-colcount="${table.getVisibleLeafColumns().length}">`;
|
|
26
|
+
html += '<table class="yable-table">';
|
|
27
|
+
html += renderHeader(table);
|
|
28
|
+
html += renderBody(table, opts.clickableRows);
|
|
29
|
+
if (opts.footer) {
|
|
30
|
+
html += renderFooter(table);
|
|
31
|
+
}
|
|
32
|
+
html += "</table>";
|
|
33
|
+
if (rows.length === 0) {
|
|
34
|
+
html += `<div class="yable-empty"><div class="yable-empty-message">${esc(opts.emptyMessage ?? "No data")}</div></div>`;
|
|
35
|
+
}
|
|
36
|
+
html += "</div>";
|
|
37
|
+
return html;
|
|
38
|
+
}
|
|
39
|
+
function renderHeader(table) {
|
|
40
|
+
const headerGroups = table.getHeaderGroups();
|
|
41
|
+
let html = '<thead class="yable-thead">';
|
|
42
|
+
for (const headerGroup of headerGroups) {
|
|
43
|
+
html += `<tr class="yable-tr" data-yable-header-group="${escAttr(headerGroup.id)}">`;
|
|
44
|
+
for (const header of headerGroup.headers) {
|
|
45
|
+
html += renderHeaderCell(header);
|
|
46
|
+
}
|
|
47
|
+
html += "</tr>";
|
|
48
|
+
}
|
|
49
|
+
html += "</thead>";
|
|
50
|
+
return html;
|
|
51
|
+
}
|
|
52
|
+
function renderHeaderCell(header) {
|
|
53
|
+
if (header.isPlaceholder) {
|
|
54
|
+
return `<th class="yable-th" colspan="${header.colSpan}"></th>`;
|
|
55
|
+
}
|
|
56
|
+
const column = header.column;
|
|
57
|
+
const sortable = column.getCanSort();
|
|
58
|
+
const sortDir = column.getIsSorted();
|
|
59
|
+
const pinned = column.getIsPinned();
|
|
60
|
+
const classes = [
|
|
61
|
+
"yable-th",
|
|
62
|
+
sortable && "yable-th--sortable",
|
|
63
|
+
sortDir && `yable-th--sorted-${sortDir}`,
|
|
64
|
+
pinned && `yable-th--pinned-${pinned}`
|
|
65
|
+
].filter(Boolean).join(" ");
|
|
66
|
+
const style = pinned ? getPinStyle(column) : "";
|
|
67
|
+
const ariaSort = sortDir === "asc" ? "ascending" : sortDir === "desc" ? "descending" : sortable ? "none" : void 0;
|
|
68
|
+
const ariaSortAttr = ariaSort ? ` aria-sort="${ariaSort}"` : "";
|
|
69
|
+
const headerDef = column.columnDef.header;
|
|
70
|
+
const content = typeof headerDef === "function" ? String(headerDef(header.getContext())) : String(headerDef ?? column.id);
|
|
71
|
+
let sortIndicator = "";
|
|
72
|
+
if (sortable) {
|
|
73
|
+
if (sortDir) {
|
|
74
|
+
sortIndicator = `<span class="yable-sort-indicator" data-active="true" data-direction="${sortDir}" aria-hidden="true">${sortDir === "asc" ? "▲" : "▼"}</span>`;
|
|
75
|
+
} else {
|
|
76
|
+
sortIndicator = `<span class="yable-sort-indicator" aria-hidden="true">▲▼</span>`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
let resizeHandle = "";
|
|
80
|
+
if (column.getCanResize()) {
|
|
81
|
+
resizeHandle = `<div class="yable-resize-handle" data-yable-resize="${escAttr(column.id)}"></div>`;
|
|
82
|
+
}
|
|
83
|
+
return `<th class="${classes}"${ariaSortAttr}${style ? ` style="${style}"` : ""} data-yable-column="${escAttr(column.id)}" data-yable-sortable="${sortable}" colspan="${header.colSpan}">${esc(content)}${sortIndicator}${resizeHandle}</th>`;
|
|
84
|
+
}
|
|
85
|
+
function renderBody(table, clickableRows) {
|
|
86
|
+
const rows = table.getRowModel().rows;
|
|
87
|
+
let html = '<tbody class="yable-tbody">';
|
|
88
|
+
for (const row of rows) {
|
|
89
|
+
html += renderRow(table, row, clickableRows);
|
|
90
|
+
}
|
|
91
|
+
html += "</tbody>";
|
|
92
|
+
return html;
|
|
93
|
+
}
|
|
94
|
+
function renderRow(table, row, clickable) {
|
|
95
|
+
const isSelected = row.getIsSelected();
|
|
96
|
+
const isExpanded = row.getIsExpanded();
|
|
97
|
+
const classes = [
|
|
98
|
+
"yable-tr",
|
|
99
|
+
clickable && "yable-tr--clickable",
|
|
100
|
+
isSelected && "yable-tr--selected"
|
|
101
|
+
].filter(Boolean).join(" ");
|
|
102
|
+
let html = `<tr class="${classes}" data-yable-row="${escAttr(row.id)}"${isSelected ? ' aria-selected="true"' : ""}>`;
|
|
103
|
+
const cells = row.getVisibleCells();
|
|
104
|
+
for (const cell of cells) {
|
|
105
|
+
html += renderCell(table, cell);
|
|
106
|
+
}
|
|
107
|
+
html += "</tr>";
|
|
108
|
+
if (isExpanded) {
|
|
109
|
+
const colSpan = table.getVisibleLeafColumns().length;
|
|
110
|
+
html += `<tr class="yable-tr yable-tr--detail" data-yable-detail="${escAttr(row.id)}"><td class="yable-td yable-td--detail" colspan="${colSpan}"><div class="yable-detail-content" data-yable-detail-content="${escAttr(row.id)}"></div></td></tr>`;
|
|
111
|
+
}
|
|
112
|
+
return html;
|
|
113
|
+
}
|
|
114
|
+
function renderCell(table, cell) {
|
|
115
|
+
const column = cell.column;
|
|
116
|
+
const pinned = column.getIsPinned();
|
|
117
|
+
const isEditing = cell.getIsEditing();
|
|
118
|
+
const isAlwaysEditable = cell.getIsAlwaysEditable();
|
|
119
|
+
const classes = [
|
|
120
|
+
"yable-td",
|
|
121
|
+
pinned && `yable-td--pinned-${pinned}`,
|
|
122
|
+
(isEditing || isAlwaysEditable) && "yable-td--editing"
|
|
123
|
+
].filter(Boolean).join(" ");
|
|
124
|
+
const style = pinned ? getPinStyle(column) : "";
|
|
125
|
+
const editConfig = column.columnDef.editConfig;
|
|
126
|
+
if (isEditing || isAlwaysEditable) {
|
|
127
|
+
if (editConfig) {
|
|
128
|
+
const value2 = table.getPendingValue(cell.row.id, column.id) ?? cell.getValue();
|
|
129
|
+
return `<td class="${classes}"${style ? ` style="${style}"` : ""} data-yable-cell="${escAttr(column.id)}" data-yable-row="${escAttr(cell.row.id)}">${renderFormElement(editConfig, value2, cell.row.id, column.id)}</td>`;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const value = cell.renderValue();
|
|
133
|
+
return `<td class="${classes}"${style ? ` style="${style}"` : ""} data-yable-cell="${escAttr(column.id)}" data-yable-row="${escAttr(cell.row.id)}">${esc(value)}</td>`;
|
|
134
|
+
}
|
|
135
|
+
function renderFooter(table) {
|
|
136
|
+
const footerGroups = table.getFooterGroups();
|
|
137
|
+
if (!footerGroups.length) return "";
|
|
138
|
+
let html = '<tfoot class="yable-tfoot">';
|
|
139
|
+
for (const footerGroup of footerGroups) {
|
|
140
|
+
html += '<tr class="yable-tr">';
|
|
141
|
+
for (const header of footerGroup.headers) {
|
|
142
|
+
const footerDef = header.column.columnDef.footer;
|
|
143
|
+
const content = header.isPlaceholder ? "" : typeof footerDef === "function" ? String(footerDef(header.getContext())) : String(footerDef ?? "");
|
|
144
|
+
html += `<td class="yable-td" colspan="${header.colSpan}">${esc(content)}</td>`;
|
|
145
|
+
}
|
|
146
|
+
html += "</tr>";
|
|
147
|
+
}
|
|
148
|
+
html += "</tfoot>";
|
|
149
|
+
return html;
|
|
150
|
+
}
|
|
151
|
+
function renderFormElement(editConfig, value, rowId, columnId) {
|
|
152
|
+
const type = editConfig.type ?? "text";
|
|
153
|
+
switch (type) {
|
|
154
|
+
case "select":
|
|
155
|
+
return renderSelect(editConfig.options ?? [], value, rowId, columnId, editConfig.placeholder);
|
|
156
|
+
case "checkbox":
|
|
157
|
+
return `<input type="checkbox" class="yable-checkbox" data-yable-input="${escAttr(columnId)}" data-yable-input-row="${escAttr(rowId)}"${value ? " checked" : ""} />`;
|
|
158
|
+
case "toggle":
|
|
159
|
+
return `<input type="checkbox" role="switch" class="yable-toggle" data-yable-input="${escAttr(columnId)}" data-yable-input-row="${escAttr(rowId)}"${value ? " checked" : ""} aria-checked="${Boolean(value)}" />`;
|
|
160
|
+
case "date":
|
|
161
|
+
case "datetime-local":
|
|
162
|
+
case "time":
|
|
163
|
+
return `<input type="${esc(type)}" class="yable-input" data-yable-input="${escAttr(columnId)}" data-yable-input-row="${escAttr(rowId)}" value="${esc(formatDateValue(value, type))}" />`;
|
|
164
|
+
default:
|
|
165
|
+
return `<input type="${esc(type)}" class="yable-input" data-yable-input="${escAttr(columnId)}" data-yable-input-row="${escAttr(rowId)}" value="${esc(String(value ?? ""))}"${editConfig.placeholder ? ` placeholder="${esc(editConfig.placeholder)}"` : ""} />`;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function renderSelect(options, value, rowId, columnId, placeholder) {
|
|
169
|
+
let html = `<select class="yable-select" data-yable-input="${escAttr(columnId)}" data-yable-input-row="${escAttr(rowId)}">`;
|
|
170
|
+
if (placeholder) {
|
|
171
|
+
html += `<option value="" disabled>${esc(placeholder)}</option>`;
|
|
172
|
+
}
|
|
173
|
+
for (const opt of options) {
|
|
174
|
+
const selected = String(opt.value) === String(value) ? " selected" : "";
|
|
175
|
+
html += `<option value="${esc(opt.value)}"${selected}>${esc(opt.label)}</option>`;
|
|
176
|
+
}
|
|
177
|
+
html += "</select>";
|
|
178
|
+
return html;
|
|
179
|
+
}
|
|
180
|
+
function formatDateValue(value, type) {
|
|
181
|
+
if (!value) return "";
|
|
182
|
+
if (typeof value === "string") return value;
|
|
183
|
+
if (value instanceof Date) {
|
|
184
|
+
if (type === "date") return value.toISOString().split("T")[0];
|
|
185
|
+
if (type === "datetime-local") return value.toISOString().slice(0, 16);
|
|
186
|
+
if (type === "time") return value.toISOString().slice(11, 16);
|
|
187
|
+
}
|
|
188
|
+
return String(value);
|
|
189
|
+
}
|
|
190
|
+
function getPinStyle(column) {
|
|
191
|
+
const pinned = column.getIsPinned();
|
|
192
|
+
if (!pinned) return "";
|
|
193
|
+
const offset = column.getPinnedIndex() * 150;
|
|
194
|
+
return `position: sticky; ${pinned}: ${offset}px; z-index: 1;`;
|
|
195
|
+
}
|
|
196
|
+
function renderPagination(table, opts = {}) {
|
|
197
|
+
const { showPageSize = true, pageSizes = [10, 20, 50, 100], showInfo = true } = opts;
|
|
198
|
+
const { pageIndex, pageSize } = table.getState().pagination;
|
|
199
|
+
const pageCount = table.getPageCount();
|
|
200
|
+
const totalRows = table.getPrePaginationRowModel().rows.length;
|
|
201
|
+
const from = pageIndex * pageSize + 1;
|
|
202
|
+
const to = Math.min((pageIndex + 1) * pageSize, totalRows);
|
|
203
|
+
let html = '<div class="yable-pagination">';
|
|
204
|
+
if (showInfo) {
|
|
205
|
+
html += '<div class="yable-pagination-info">';
|
|
206
|
+
html += totalRows > 0 ? `<span>${from}\u2013${to} of ${totalRows}</span>` : "<span>No results</span>";
|
|
207
|
+
if (showPageSize) {
|
|
208
|
+
html += '<select class="yable-pagination-select" data-yable-pagesize>';
|
|
209
|
+
for (const size of pageSizes) {
|
|
210
|
+
html += `<option value="${size}"${size === pageSize ? " selected" : ""}>${size} rows</option>`;
|
|
211
|
+
}
|
|
212
|
+
html += "</select>";
|
|
213
|
+
}
|
|
214
|
+
html += "</div>";
|
|
215
|
+
}
|
|
216
|
+
html += '<div class="yable-pagination-pages">';
|
|
217
|
+
html += `<button class="yable-pagination-btn" data-yable-page="first"${!table.getCanPreviousPage() ? " disabled" : ""} aria-label="First page">«</button>`;
|
|
218
|
+
html += `<button class="yable-pagination-btn" data-yable-page="prev"${!table.getCanPreviousPage() ? " disabled" : ""} aria-label="Previous page">‹</button>`;
|
|
219
|
+
const pages = getPageNumbers(pageIndex, pageCount);
|
|
220
|
+
for (let i = 0; i < pages.length; i++) {
|
|
221
|
+
const page = pages[i];
|
|
222
|
+
if (page === -1) {
|
|
223
|
+
html += '<span class="yable-pagination-btn" style="cursor:default;opacity:0.5">...</span>';
|
|
224
|
+
} else {
|
|
225
|
+
html += `<button class="yable-pagination-btn" data-yable-page="${page}"${page === pageIndex ? ' data-active="true" aria-current="page"' : ""} aria-label="Page ${page + 1}">${page + 1}</button>`;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
html += `<button class="yable-pagination-btn" data-yable-page="next"${!table.getCanNextPage() ? " disabled" : ""} aria-label="Next page">›</button>`;
|
|
229
|
+
html += `<button class="yable-pagination-btn" data-yable-page="last"${!table.getCanNextPage() ? " disabled" : ""} aria-label="Last page">»</button>`;
|
|
230
|
+
html += "</div></div>";
|
|
231
|
+
return html;
|
|
232
|
+
}
|
|
233
|
+
function getPageNumbers(current, total) {
|
|
234
|
+
if (total <= 7) return Array.from({ length: total }, (_, i) => i);
|
|
235
|
+
const pages = [0];
|
|
236
|
+
if (current > 3) pages.push(-1);
|
|
237
|
+
const start = Math.max(1, current - 1);
|
|
238
|
+
const end = Math.min(total - 2, current + 1);
|
|
239
|
+
for (let i = start; i <= end; i++) pages.push(i);
|
|
240
|
+
if (current < total - 4) pages.push(-1);
|
|
241
|
+
pages.push(total - 1);
|
|
242
|
+
return pages;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/events.ts
|
|
246
|
+
function attachEventDelegation(root, table, handlers, onUpdate) {
|
|
247
|
+
const abortController = new AbortController();
|
|
248
|
+
const signal = abortController.signal;
|
|
249
|
+
root.addEventListener(
|
|
250
|
+
"click",
|
|
251
|
+
(e) => {
|
|
252
|
+
const target = e.target;
|
|
253
|
+
const pageBtn = target.closest("[data-yable-page]");
|
|
254
|
+
if (pageBtn) {
|
|
255
|
+
const page = pageBtn.dataset.yablePage;
|
|
256
|
+
if (page === "first") table.setPageIndex(0);
|
|
257
|
+
else if (page === "last") table.setPageIndex(table.getPageCount() - 1);
|
|
258
|
+
else if (page === "prev") table.previousPage();
|
|
259
|
+
else if (page === "next") table.nextPage();
|
|
260
|
+
else table.setPageIndex(Number(page));
|
|
261
|
+
onUpdate();
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const th = target.closest('[data-yable-sortable="true"]');
|
|
265
|
+
if (th) {
|
|
266
|
+
const columnId = th.dataset.yableColumn;
|
|
267
|
+
const column = table.getColumn(columnId);
|
|
268
|
+
if (column) {
|
|
269
|
+
column.toggleSorting();
|
|
270
|
+
onUpdate();
|
|
271
|
+
}
|
|
272
|
+
handlers["header:click"]?.({
|
|
273
|
+
type: "header:click",
|
|
274
|
+
columnId,
|
|
275
|
+
originalEvent: e
|
|
276
|
+
});
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const td = target.closest("[data-yable-cell]");
|
|
280
|
+
if (td) {
|
|
281
|
+
const columnId = td.dataset.yableCell;
|
|
282
|
+
const rowId = td.dataset.yableRow;
|
|
283
|
+
handlers["cell:click"]?.({
|
|
284
|
+
type: "cell:click",
|
|
285
|
+
rowId,
|
|
286
|
+
columnId,
|
|
287
|
+
originalEvent: e
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
const tr = target.closest("[data-yable-row]");
|
|
291
|
+
if (tr && !target.closest("input, select, button")) {
|
|
292
|
+
const rowId = tr.dataset.yableRow;
|
|
293
|
+
handlers["row:click"]?.({
|
|
294
|
+
type: "row:click",
|
|
295
|
+
rowId,
|
|
296
|
+
originalEvent: e
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
{ signal }
|
|
301
|
+
);
|
|
302
|
+
root.addEventListener(
|
|
303
|
+
"dblclick",
|
|
304
|
+
(e) => {
|
|
305
|
+
const target = e.target;
|
|
306
|
+
const td = target.closest("[data-yable-cell]");
|
|
307
|
+
if (td) {
|
|
308
|
+
const columnId = td.dataset.yableCell;
|
|
309
|
+
const rowId = td.dataset.yableRow;
|
|
310
|
+
handlers["cell:dblclick"]?.({
|
|
311
|
+
type: "cell:dblclick",
|
|
312
|
+
rowId,
|
|
313
|
+
columnId,
|
|
314
|
+
originalEvent: e
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
const tr = target.closest("[data-yable-row]");
|
|
318
|
+
if (tr) {
|
|
319
|
+
const rowId = tr.dataset.yableRow;
|
|
320
|
+
handlers["row:dblclick"]?.({
|
|
321
|
+
type: "row:dblclick",
|
|
322
|
+
rowId,
|
|
323
|
+
originalEvent: e
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
{ signal }
|
|
328
|
+
);
|
|
329
|
+
root.addEventListener(
|
|
330
|
+
"change",
|
|
331
|
+
(e) => {
|
|
332
|
+
const target = e.target;
|
|
333
|
+
const columnId = target.dataset.yableInput;
|
|
334
|
+
const rowId = target.dataset.yableInputRow;
|
|
335
|
+
if (!columnId || !rowId) return;
|
|
336
|
+
let value;
|
|
337
|
+
if (target instanceof HTMLInputElement && target.type === "checkbox") {
|
|
338
|
+
value = target.checked;
|
|
339
|
+
} else if (target instanceof HTMLInputElement && target.type === "number") {
|
|
340
|
+
value = Number(target.value);
|
|
341
|
+
} else {
|
|
342
|
+
value = target.value;
|
|
343
|
+
}
|
|
344
|
+
table.setPendingValue(rowId, columnId, value);
|
|
345
|
+
onUpdate();
|
|
346
|
+
},
|
|
347
|
+
{ signal }
|
|
348
|
+
);
|
|
349
|
+
root.addEventListener(
|
|
350
|
+
"blur",
|
|
351
|
+
(e) => {
|
|
352
|
+
const target = e.target;
|
|
353
|
+
if (target.dataset.yableInput && target.dataset.yableInputRow) {
|
|
354
|
+
const editing = table.getState().editing;
|
|
355
|
+
if (editing.activeCell) {
|
|
356
|
+
table.commitEdit();
|
|
357
|
+
onUpdate();
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
{ signal, capture: true }
|
|
362
|
+
);
|
|
363
|
+
root.addEventListener(
|
|
364
|
+
"change",
|
|
365
|
+
(e) => {
|
|
366
|
+
const target = e.target;
|
|
367
|
+
if (target.dataset.yablePagesize !== void 0) {
|
|
368
|
+
table.setPageSize(Number(target.value));
|
|
369
|
+
onUpdate();
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
{ signal }
|
|
373
|
+
);
|
|
374
|
+
root.addEventListener(
|
|
375
|
+
"mousedown",
|
|
376
|
+
(e) => {
|
|
377
|
+
const target = e.target;
|
|
378
|
+
if (target.classList.contains("yable-resize-handle")) {
|
|
379
|
+
const columnId = target.dataset.yableResize;
|
|
380
|
+
for (const headerGroup of table.getHeaderGroups()) {
|
|
381
|
+
for (const header of headerGroup.headers) {
|
|
382
|
+
if (header.column.id === columnId) {
|
|
383
|
+
const handler = header.getResizeHandler();
|
|
384
|
+
if (handler) {
|
|
385
|
+
handler(e);
|
|
386
|
+
onUpdate();
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
{ signal }
|
|
395
|
+
);
|
|
396
|
+
return () => abortController.abort();
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/createTableDOM.ts
|
|
400
|
+
function createTableDOM(options) {
|
|
401
|
+
const { element, initialState, ...tableOpts } = options;
|
|
402
|
+
const {
|
|
403
|
+
stickyHeader,
|
|
404
|
+
striped,
|
|
405
|
+
bordered,
|
|
406
|
+
compact,
|
|
407
|
+
theme,
|
|
408
|
+
clickableRows,
|
|
409
|
+
footer,
|
|
410
|
+
emptyMessage,
|
|
411
|
+
pagination: paginationOpts,
|
|
412
|
+
...coreOptions
|
|
413
|
+
} = tableOpts;
|
|
414
|
+
let state = {
|
|
415
|
+
sorting: [],
|
|
416
|
+
columnFilters: [],
|
|
417
|
+
globalFilter: "",
|
|
418
|
+
pagination: { pageIndex: 0, pageSize: 10 },
|
|
419
|
+
rowSelection: {},
|
|
420
|
+
columnVisibility: {},
|
|
421
|
+
columnOrder: [],
|
|
422
|
+
columnPinning: { left: [], right: [] },
|
|
423
|
+
columnSizing: {},
|
|
424
|
+
columnSizingInfo: {
|
|
425
|
+
startOffset: null,
|
|
426
|
+
startSize: null,
|
|
427
|
+
deltaOffset: null,
|
|
428
|
+
deltaPercentage: null,
|
|
429
|
+
isResizingColumn: false,
|
|
430
|
+
columnSizingStart: []
|
|
431
|
+
},
|
|
432
|
+
expanded: {},
|
|
433
|
+
rowPinning: { top: [], bottom: [] },
|
|
434
|
+
grouping: [],
|
|
435
|
+
editing: { activeCell: void 0, pendingValues: {} },
|
|
436
|
+
commits: { cells: {}, nextOpId: 1 },
|
|
437
|
+
keyboardNavigation: { focusedCell: null },
|
|
438
|
+
undoRedo: { undoStack: [], redoStack: [], maxSize: 50 },
|
|
439
|
+
fillHandle: { isDragging: false },
|
|
440
|
+
formulas: { enabled: false, formulas: {}, computedValues: {}, errors: {} },
|
|
441
|
+
rowDrag: { draggingRowId: null, overRowId: null, dropPosition: null },
|
|
442
|
+
pivot: {
|
|
443
|
+
enabled: false,
|
|
444
|
+
config: { rowFields: [], columnFields: [], valueFields: [] },
|
|
445
|
+
expandedRowGroups: {},
|
|
446
|
+
expandedColumnGroups: {}
|
|
447
|
+
},
|
|
448
|
+
...initialState
|
|
449
|
+
};
|
|
450
|
+
let displayOpts = {
|
|
451
|
+
stickyHeader,
|
|
452
|
+
striped,
|
|
453
|
+
bordered,
|
|
454
|
+
compact,
|
|
455
|
+
theme,
|
|
456
|
+
clickableRows,
|
|
457
|
+
footer,
|
|
458
|
+
emptyMessage
|
|
459
|
+
};
|
|
460
|
+
let paginationDisplayOpts = typeof paginationOpts === "object" ? paginationOpts : paginationOpts ? {} : void 0;
|
|
461
|
+
const handlers = {};
|
|
462
|
+
const coreTable = createTable({
|
|
463
|
+
...coreOptions,
|
|
464
|
+
state,
|
|
465
|
+
onStateChange: (updater) => {
|
|
466
|
+
state = functionalUpdate(updater, state);
|
|
467
|
+
render();
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
let cleanupEvents = null;
|
|
471
|
+
function render() {
|
|
472
|
+
coreTable.setOptions((prev) => ({
|
|
473
|
+
...prev,
|
|
474
|
+
...coreOptions,
|
|
475
|
+
state,
|
|
476
|
+
onStateChange: (updater) => {
|
|
477
|
+
state = functionalUpdate(updater, state);
|
|
478
|
+
render();
|
|
479
|
+
}
|
|
480
|
+
}));
|
|
481
|
+
cleanupEvents?.();
|
|
482
|
+
let html = renderTable(coreTable, displayOpts);
|
|
483
|
+
if (paginationDisplayOpts !== void 0) {
|
|
484
|
+
html += renderPagination(coreTable, paginationDisplayOpts);
|
|
485
|
+
}
|
|
486
|
+
element.innerHTML = html;
|
|
487
|
+
cleanupEvents = attachEventDelegation(element, coreTable, handlers, render);
|
|
488
|
+
}
|
|
489
|
+
render();
|
|
490
|
+
const instance = {
|
|
491
|
+
table: coreTable,
|
|
492
|
+
render,
|
|
493
|
+
setData(data) {
|
|
494
|
+
coreTable.setOptions((prev) => ({
|
|
495
|
+
...prev,
|
|
496
|
+
data,
|
|
497
|
+
state,
|
|
498
|
+
onStateChange: (updater) => {
|
|
499
|
+
state = functionalUpdate(updater, state);
|
|
500
|
+
render();
|
|
501
|
+
}
|
|
502
|
+
}));
|
|
503
|
+
render();
|
|
504
|
+
},
|
|
505
|
+
getState() {
|
|
506
|
+
return state;
|
|
507
|
+
},
|
|
508
|
+
setOptions(opts) {
|
|
509
|
+
const { element: _el, initialState: _is, ...rest } = opts;
|
|
510
|
+
const {
|
|
511
|
+
stickyHeader: sh,
|
|
512
|
+
striped: st,
|
|
513
|
+
bordered: bd,
|
|
514
|
+
compact: cp,
|
|
515
|
+
theme: th,
|
|
516
|
+
clickableRows: cr,
|
|
517
|
+
footer: ft,
|
|
518
|
+
emptyMessage: em,
|
|
519
|
+
pagination: pg,
|
|
520
|
+
...core
|
|
521
|
+
} = rest;
|
|
522
|
+
if (sh !== void 0 || st !== void 0 || bd !== void 0 || cp !== void 0 || th !== void 0 || cr !== void 0 || ft !== void 0 || em !== void 0) {
|
|
523
|
+
displayOpts = { ...displayOpts, stickyHeader: sh ?? displayOpts.stickyHeader, striped: st ?? displayOpts.striped, bordered: bd ?? displayOpts.bordered, compact: cp ?? displayOpts.compact, theme: th ?? displayOpts.theme, clickableRows: cr ?? displayOpts.clickableRows, footer: ft ?? displayOpts.footer, emptyMessage: em ?? displayOpts.emptyMessage };
|
|
524
|
+
}
|
|
525
|
+
if (pg !== void 0) {
|
|
526
|
+
paginationDisplayOpts = typeof pg === "object" ? pg : pg ? {} : void 0;
|
|
527
|
+
}
|
|
528
|
+
if (Object.keys(core).length > 0) {
|
|
529
|
+
Object.assign(coreOptions, core);
|
|
530
|
+
}
|
|
531
|
+
render();
|
|
532
|
+
},
|
|
533
|
+
on(event, handler) {
|
|
534
|
+
handlers[event] = handler;
|
|
535
|
+
},
|
|
536
|
+
off(event) {
|
|
537
|
+
delete handlers[event];
|
|
538
|
+
},
|
|
539
|
+
destroy() {
|
|
540
|
+
cleanupEvents?.();
|
|
541
|
+
element.innerHTML = "";
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
return instance;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export { createTableDOM, renderPagination, renderTable };
|
|
548
|
+
//# sourceMappingURL=index.js.map
|
|
549
|
+
//# sourceMappingURL=index.js.map
|