@rowakit/table 0.4.0 → 0.5.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 +136 -1416
- package/dist/index.cjs +1104 -626
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -4
- package/dist/index.d.ts +49 -4
- package/dist/index.js +1105 -627
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useRef, useEffect } from 'react';
|
|
1
|
+
import { useState, useRef, useEffect, useMemo } from 'react';
|
|
2
2
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/column-helpers.ts
|
|
@@ -103,20 +103,178 @@ var col = {
|
|
|
103
103
|
actions,
|
|
104
104
|
custom
|
|
105
105
|
};
|
|
106
|
-
function
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
106
|
+
function useColumnResizing(columns) {
|
|
107
|
+
const [columnWidths, setColumnWidths] = useState({});
|
|
108
|
+
const resizeRafRef = useRef(null);
|
|
109
|
+
const resizePendingRef = useRef(null);
|
|
110
|
+
const tableRef = useRef(null);
|
|
111
|
+
const isResizingRef = useRef(false);
|
|
112
|
+
const lastResizeEndTsRef = useRef(0);
|
|
113
|
+
const resizingColIdRef = useRef(null);
|
|
114
|
+
const scheduleColumnWidthUpdate = (colId, width) => {
|
|
115
|
+
resizePendingRef.current = { colId, width };
|
|
116
|
+
if (resizeRafRef.current != null) return;
|
|
117
|
+
resizeRafRef.current = requestAnimationFrame(() => {
|
|
118
|
+
resizeRafRef.current = null;
|
|
119
|
+
const pending = resizePendingRef.current;
|
|
120
|
+
if (!pending) return;
|
|
121
|
+
handleColumnResize(pending.colId, pending.width);
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
const handleColumnResize = (columnId, newWidth) => {
|
|
125
|
+
const minWidth = columns.find((c) => c.id === columnId)?.minWidth ?? 80;
|
|
126
|
+
const maxWidth = columns.find((c) => c.id === columnId)?.maxWidth;
|
|
127
|
+
let finalWidth = Math.max(minWidth, newWidth);
|
|
128
|
+
if (maxWidth) {
|
|
129
|
+
finalWidth = Math.min(finalWidth, maxWidth);
|
|
130
|
+
}
|
|
131
|
+
if (columnWidths[columnId] === finalWidth) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
setColumnWidths((prev) => ({
|
|
135
|
+
...prev,
|
|
136
|
+
[columnId]: finalWidth
|
|
137
|
+
}));
|
|
138
|
+
};
|
|
139
|
+
const autoFitColumnWidth = (columnId) => {
|
|
140
|
+
const tableEl = tableRef.current;
|
|
141
|
+
if (!tableEl) return;
|
|
142
|
+
const th = tableEl.querySelector(`th[data-col-id="${columnId}"]`);
|
|
143
|
+
if (!th) return;
|
|
144
|
+
const tds = Array.from(
|
|
145
|
+
tableEl.querySelectorAll(`td[data-col-id="${columnId}"]`)
|
|
146
|
+
);
|
|
147
|
+
const headerW = th.scrollWidth;
|
|
148
|
+
const cellsMaxW = tds.reduce((max, td) => Math.max(max, td.scrollWidth), 0);
|
|
149
|
+
const padding = 24;
|
|
150
|
+
const raw = Math.max(headerW, cellsMaxW) + padding;
|
|
151
|
+
const colDef = columns.find((c) => c.id === columnId);
|
|
152
|
+
const minW = colDef?.minWidth ?? 80;
|
|
153
|
+
const maxW = colDef?.maxWidth ?? 600;
|
|
154
|
+
const finalW = Math.max(minW, Math.min(raw, maxW));
|
|
155
|
+
setColumnWidths((prev) => ({ ...prev, [columnId]: finalW }));
|
|
156
|
+
};
|
|
157
|
+
const startColumnResize = (e, columnId) => {
|
|
158
|
+
e.preventDefault();
|
|
159
|
+
e.stopPropagation();
|
|
160
|
+
if (e.detail === 2) {
|
|
161
|
+
autoFitColumnWidth(columnId);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (e.pointerType === "mouse" && e.buttons !== 1) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const target = e.currentTarget;
|
|
168
|
+
const pointerId = e.pointerId;
|
|
169
|
+
try {
|
|
170
|
+
target.setPointerCapture(pointerId);
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
173
|
+
isResizingRef.current = true;
|
|
174
|
+
resizingColIdRef.current = columnId;
|
|
175
|
+
const startX = e.clientX;
|
|
176
|
+
const th = target.parentElement;
|
|
177
|
+
let startWidth = columnWidths[columnId] ?? th.offsetWidth;
|
|
178
|
+
const MIN_DRAG_WIDTH = 80;
|
|
179
|
+
if (startWidth < MIN_DRAG_WIDTH) {
|
|
180
|
+
const nextTh = th.nextElementSibling;
|
|
181
|
+
if (nextTh && nextTh.offsetWidth >= 50) {
|
|
182
|
+
startWidth = nextTh.offsetWidth;
|
|
183
|
+
} else {
|
|
184
|
+
startWidth = 100;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
document.body.classList.add("rowakit-resizing");
|
|
188
|
+
const handlePointerMove = (moveEvent) => {
|
|
189
|
+
const delta = moveEvent.clientX - startX;
|
|
190
|
+
const newWidth = startWidth + delta;
|
|
191
|
+
scheduleColumnWidthUpdate(columnId, newWidth);
|
|
192
|
+
};
|
|
193
|
+
const cleanupResize = () => {
|
|
194
|
+
target.removeEventListener("pointermove", handlePointerMove);
|
|
195
|
+
target.removeEventListener("pointerup", handlePointerUp);
|
|
196
|
+
target.removeEventListener("pointercancel", handlePointerCancel);
|
|
197
|
+
document.body.classList.remove("rowakit-resizing");
|
|
198
|
+
isResizingRef.current = false;
|
|
199
|
+
resizingColIdRef.current = null;
|
|
200
|
+
lastResizeEndTsRef.current = Date.now();
|
|
201
|
+
try {
|
|
202
|
+
target.releasePointerCapture(pointerId);
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const handlePointerUp = () => {
|
|
207
|
+
cleanupResize();
|
|
208
|
+
};
|
|
209
|
+
const handlePointerCancel = () => {
|
|
210
|
+
cleanupResize();
|
|
211
|
+
};
|
|
212
|
+
target.addEventListener("pointermove", handlePointerMove);
|
|
213
|
+
target.addEventListener("pointerup", handlePointerUp);
|
|
214
|
+
target.addEventListener("pointercancel", handlePointerCancel);
|
|
215
|
+
};
|
|
216
|
+
const handleColumnResizeDoubleClick = (e, columnId) => {
|
|
217
|
+
e.preventDefault();
|
|
218
|
+
e.stopPropagation();
|
|
219
|
+
autoFitColumnWidth(columnId);
|
|
220
|
+
};
|
|
221
|
+
return {
|
|
222
|
+
tableRef,
|
|
223
|
+
columnWidths,
|
|
224
|
+
setColumnWidths,
|
|
225
|
+
startColumnResize,
|
|
226
|
+
handleColumnResizeDoubleClick,
|
|
227
|
+
isResizingRef,
|
|
228
|
+
lastResizeEndTsRef,
|
|
229
|
+
resizingColIdRef
|
|
230
|
+
};
|
|
117
231
|
}
|
|
118
|
-
function
|
|
119
|
-
|
|
232
|
+
function useFetcherState(fetcher, query, setQuery) {
|
|
233
|
+
const [dataState, setDataState] = useState({
|
|
234
|
+
state: "idle",
|
|
235
|
+
items: [],
|
|
236
|
+
total: 0
|
|
237
|
+
});
|
|
238
|
+
const requestIdRef = useRef(0);
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
const currentRequestId = ++requestIdRef.current;
|
|
241
|
+
setDataState((prev) => ({ ...prev, state: "loading" }));
|
|
242
|
+
fetcher(query).then((result) => {
|
|
243
|
+
if (currentRequestId !== requestIdRef.current) return;
|
|
244
|
+
if (result.items.length === 0) {
|
|
245
|
+
setDataState({
|
|
246
|
+
state: "empty",
|
|
247
|
+
items: [],
|
|
248
|
+
total: result.total
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
setDataState({
|
|
253
|
+
state: "success",
|
|
254
|
+
items: result.items,
|
|
255
|
+
total: result.total
|
|
256
|
+
});
|
|
257
|
+
}).catch((error) => {
|
|
258
|
+
if (currentRequestId !== requestIdRef.current) return;
|
|
259
|
+
setDataState({
|
|
260
|
+
state: "error",
|
|
261
|
+
items: [],
|
|
262
|
+
total: 0,
|
|
263
|
+
error: error instanceof Error ? error.message : "Failed to load data"
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
}, [fetcher, query]);
|
|
267
|
+
const handleRetry = () => {
|
|
268
|
+
setQuery({ ...query });
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
dataState,
|
|
272
|
+
setDataState,
|
|
273
|
+
handleRetry,
|
|
274
|
+
isLoading: dataState.state === "loading",
|
|
275
|
+
isError: dataState.state === "error",
|
|
276
|
+
isEmpty: dataState.state === "empty"
|
|
277
|
+
};
|
|
120
278
|
}
|
|
121
279
|
function validateViewName(name) {
|
|
122
280
|
const trimmed = name.trim();
|
|
@@ -152,10 +310,7 @@ function getSavedViewsIndex() {
|
|
|
152
310
|
const key = localStorage.key(i);
|
|
153
311
|
if (key?.startsWith("rowakit-view-")) {
|
|
154
312
|
const name = key.substring("rowakit-view-".length);
|
|
155
|
-
rebuilt.push({
|
|
156
|
-
name,
|
|
157
|
-
updatedAt: Date.now()
|
|
158
|
-
});
|
|
313
|
+
rebuilt.push({ name, updatedAt: Date.now() });
|
|
159
314
|
}
|
|
160
315
|
}
|
|
161
316
|
} catch {
|
|
@@ -182,16 +337,206 @@ function loadSavedViewsFromStorage() {
|
|
|
182
337
|
const viewStr = localStorage.getItem(`rowakit-view-${entry.name}`);
|
|
183
338
|
if (viewStr) {
|
|
184
339
|
const state = JSON.parse(viewStr);
|
|
185
|
-
views.push({
|
|
186
|
-
name: entry.name,
|
|
187
|
-
state
|
|
188
|
-
});
|
|
340
|
+
views.push({ name: entry.name, state });
|
|
189
341
|
}
|
|
190
342
|
} catch {
|
|
191
343
|
}
|
|
192
344
|
}
|
|
193
345
|
return views;
|
|
194
346
|
}
|
|
347
|
+
function useSavedViews(options) {
|
|
348
|
+
const [savedViews, setSavedViews] = useState([]);
|
|
349
|
+
const [showSaveViewForm, setShowSaveViewForm] = useState(false);
|
|
350
|
+
const [saveViewInput, setSaveViewInput] = useState("");
|
|
351
|
+
const [saveViewError, setSaveViewError] = useState("");
|
|
352
|
+
const [overwriteConfirmName, setOverwriteConfirmName] = useState(null);
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
if (!options.enableSavedViews) return;
|
|
355
|
+
setSavedViews(loadSavedViewsFromStorage());
|
|
356
|
+
}, [options.enableSavedViews]);
|
|
357
|
+
const saveCurrentView = (name) => {
|
|
358
|
+
const viewState = {
|
|
359
|
+
page: options.query.page,
|
|
360
|
+
pageSize: options.query.pageSize,
|
|
361
|
+
sort: options.query.sort,
|
|
362
|
+
filters: options.query.filters,
|
|
363
|
+
columnWidths: options.enableColumnResizing ? options.columnWidths : void 0
|
|
364
|
+
};
|
|
365
|
+
setSavedViews((prev) => {
|
|
366
|
+
const filtered = prev.filter((v) => v.name !== name);
|
|
367
|
+
return [...filtered, { name, state: viewState }];
|
|
368
|
+
});
|
|
369
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
370
|
+
try {
|
|
371
|
+
localStorage.setItem(`rowakit-view-${name}`, JSON.stringify(viewState));
|
|
372
|
+
const index = getSavedViewsIndex();
|
|
373
|
+
const filtered = index.filter((v) => v.name !== name);
|
|
374
|
+
filtered.push({ name, updatedAt: Date.now() });
|
|
375
|
+
setSavedViewsIndex(filtered);
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
const loadSavedView = (name) => {
|
|
381
|
+
const view = savedViews.find((v) => v.name === name);
|
|
382
|
+
if (!view) return;
|
|
383
|
+
const { state } = view;
|
|
384
|
+
options.setQuery({
|
|
385
|
+
page: state.page,
|
|
386
|
+
pageSize: state.pageSize,
|
|
387
|
+
sort: state.sort,
|
|
388
|
+
filters: state.filters
|
|
389
|
+
});
|
|
390
|
+
options.setFilters(state.filters ?? {});
|
|
391
|
+
if (state.columnWidths && options.enableColumnResizing) {
|
|
392
|
+
options.setColumnWidths(state.columnWidths);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
const deleteSavedView = (name) => {
|
|
396
|
+
setSavedViews((prev) => prev.filter((v) => v.name !== name));
|
|
397
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
398
|
+
try {
|
|
399
|
+
localStorage.removeItem(`rowakit-view-${name}`);
|
|
400
|
+
const index = getSavedViewsIndex();
|
|
401
|
+
const filtered = index.filter((v) => v.name !== name);
|
|
402
|
+
setSavedViewsIndex(filtered);
|
|
403
|
+
} catch {
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const resetTableState = () => {
|
|
408
|
+
options.setQuery({
|
|
409
|
+
page: 1,
|
|
410
|
+
pageSize: options.defaultPageSize
|
|
411
|
+
});
|
|
412
|
+
options.setFilters({});
|
|
413
|
+
options.setColumnWidths({});
|
|
414
|
+
};
|
|
415
|
+
const shouldShowReset = useMemo(() => {
|
|
416
|
+
if (!options.enableSavedViews) return false;
|
|
417
|
+
return Boolean(options.query.page > 1 || options.query.sort || options.query.filters && Object.keys(options.query.filters).length > 0);
|
|
418
|
+
}, [options.enableSavedViews, options.query.page, options.query.sort, options.query.filters]);
|
|
419
|
+
const openSaveViewForm = () => {
|
|
420
|
+
setShowSaveViewForm(true);
|
|
421
|
+
setSaveViewInput("");
|
|
422
|
+
setSaveViewError("");
|
|
423
|
+
setOverwriteConfirmName(null);
|
|
424
|
+
};
|
|
425
|
+
const cancelSaveViewForm = () => {
|
|
426
|
+
setShowSaveViewForm(false);
|
|
427
|
+
setSaveViewInput("");
|
|
428
|
+
setSaveViewError("");
|
|
429
|
+
setOverwriteConfirmName(null);
|
|
430
|
+
};
|
|
431
|
+
const onSaveViewInputChange = (e) => {
|
|
432
|
+
setSaveViewInput(e.target.value);
|
|
433
|
+
setSaveViewError("");
|
|
434
|
+
};
|
|
435
|
+
const attemptSave = () => {
|
|
436
|
+
const validation = validateViewName(saveViewInput);
|
|
437
|
+
if (!validation.valid) {
|
|
438
|
+
setSaveViewError(validation.error || "Invalid name");
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
const trimmed = saveViewInput.trim();
|
|
442
|
+
if (savedViews.some((v) => v.name === trimmed)) {
|
|
443
|
+
setOverwriteConfirmName(trimmed);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
saveCurrentView(trimmed);
|
|
447
|
+
cancelSaveViewForm();
|
|
448
|
+
};
|
|
449
|
+
const onSaveViewInputKeyDown = (e) => {
|
|
450
|
+
if (e.key !== "Enter") return;
|
|
451
|
+
attemptSave();
|
|
452
|
+
};
|
|
453
|
+
const confirmOverwrite = () => {
|
|
454
|
+
if (!overwriteConfirmName) return;
|
|
455
|
+
saveCurrentView(overwriteConfirmName);
|
|
456
|
+
cancelSaveViewForm();
|
|
457
|
+
};
|
|
458
|
+
const cancelOverwrite = () => {
|
|
459
|
+
setOverwriteConfirmName(null);
|
|
460
|
+
};
|
|
461
|
+
return {
|
|
462
|
+
savedViews,
|
|
463
|
+
showSaveViewForm,
|
|
464
|
+
saveViewInput,
|
|
465
|
+
saveViewError,
|
|
466
|
+
overwriteConfirmName,
|
|
467
|
+
openSaveViewForm,
|
|
468
|
+
cancelSaveViewForm,
|
|
469
|
+
onSaveViewInputChange,
|
|
470
|
+
onSaveViewInputKeyDown,
|
|
471
|
+
attemptSave,
|
|
472
|
+
confirmOverwrite,
|
|
473
|
+
cancelOverwrite,
|
|
474
|
+
loadSavedView,
|
|
475
|
+
deleteSavedView,
|
|
476
|
+
resetTableState,
|
|
477
|
+
shouldShowReset
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/hooks/useSortingState.ts
|
|
482
|
+
function useSortingState(query, setQuery) {
|
|
483
|
+
const handleSort = (field, isMultiSort = false) => {
|
|
484
|
+
setQuery((prev) => {
|
|
485
|
+
const currentSorts = prev.sorts || [];
|
|
486
|
+
const existingSort = currentSorts.find((s) => s.field === field);
|
|
487
|
+
if (!isMultiSort) {
|
|
488
|
+
if (existingSort?.priority === 0) {
|
|
489
|
+
if (existingSort.direction === "asc") {
|
|
490
|
+
return {
|
|
491
|
+
...prev,
|
|
492
|
+
sorts: [{ field, direction: "desc", priority: 0 }],
|
|
493
|
+
page: 1
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
const { sorts: _removed, ...rest } = prev;
|
|
497
|
+
return {
|
|
498
|
+
...rest,
|
|
499
|
+
page: 1
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
...prev,
|
|
504
|
+
sorts: [{ field, direction: "asc", priority: 0 }],
|
|
505
|
+
page: 1
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
if (existingSort) {
|
|
509
|
+
const newSorts2 = currentSorts.map((s) => {
|
|
510
|
+
if (s.field === field) {
|
|
511
|
+
const newDirection = s.direction === "asc" ? "desc" : "asc";
|
|
512
|
+
return { ...s, direction: newDirection };
|
|
513
|
+
}
|
|
514
|
+
return s;
|
|
515
|
+
});
|
|
516
|
+
return { ...prev, sorts: newSorts2, page: 1 };
|
|
517
|
+
}
|
|
518
|
+
const nextPriority = currentSorts.length;
|
|
519
|
+
const newSorts = [...currentSorts, { field, direction: "asc", priority: nextPriority }];
|
|
520
|
+
return { ...prev, sorts: newSorts, page: 1 };
|
|
521
|
+
});
|
|
522
|
+
};
|
|
523
|
+
const getSortIndicator = (field) => {
|
|
524
|
+
const sorts = query.sorts || [];
|
|
525
|
+
const sort = sorts.find((s) => s.field === field);
|
|
526
|
+
if (!sort) {
|
|
527
|
+
return "";
|
|
528
|
+
}
|
|
529
|
+
const directionIcon = sort.direction === "asc" ? " \u2191" : " \u2193";
|
|
530
|
+
const priorityLabel = sort.priority === 0 ? "" : ` [${sort.priority + 1}]`;
|
|
531
|
+
return directionIcon + priorityLabel;
|
|
532
|
+
};
|
|
533
|
+
const getSortPriority = (field) => {
|
|
534
|
+
const sorts = query.sorts || [];
|
|
535
|
+
const sort = sorts.find((s) => s.field === field);
|
|
536
|
+
return sort ? sort.priority : null;
|
|
537
|
+
};
|
|
538
|
+
return { handleSort, getSortIndicator, getSortPriority };
|
|
539
|
+
}
|
|
195
540
|
function parseUrlState(params, defaultPageSize, pageSizeOptions) {
|
|
196
541
|
const pageStr = params.get("page");
|
|
197
542
|
let page = 1;
|
|
@@ -212,10 +557,22 @@ function parseUrlState(params, defaultPageSize, pageSizeOptions) {
|
|
|
212
557
|
}
|
|
213
558
|
}
|
|
214
559
|
const result = { page, pageSize };
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
560
|
+
const sortsStr = params.get("sorts");
|
|
561
|
+
if (sortsStr) {
|
|
562
|
+
try {
|
|
563
|
+
const parsed = JSON.parse(sortsStr);
|
|
564
|
+
if (Array.isArray(parsed) && parsed.every((s) => typeof s.field === "string" && (s.direction === "asc" || s.direction === "desc") && typeof s.priority === "number")) {
|
|
565
|
+
result.sorts = parsed;
|
|
566
|
+
}
|
|
567
|
+
} catch {
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (!result.sorts) {
|
|
571
|
+
const sortField = params.get("sortField");
|
|
572
|
+
const sortDir = params.get("sortDirection");
|
|
573
|
+
if (sortField && (sortDir === "asc" || sortDir === "desc")) {
|
|
574
|
+
result.sort = { field: sortField, direction: sortDir };
|
|
575
|
+
}
|
|
219
576
|
}
|
|
220
577
|
const filtersStr = params.get("filters");
|
|
221
578
|
if (filtersStr) {
|
|
@@ -253,7 +610,9 @@ function serializeUrlState(query, filters, columnWidths, defaultPageSize, enable
|
|
|
253
610
|
if (query.pageSize !== defaultPageSize) {
|
|
254
611
|
params.set("pageSize", String(query.pageSize));
|
|
255
612
|
}
|
|
256
|
-
if (query.
|
|
613
|
+
if (query.sorts && query.sorts.length > 0) {
|
|
614
|
+
params.set("sorts", JSON.stringify(query.sorts));
|
|
615
|
+
} else if (query.sort) {
|
|
257
616
|
params.set("sortField", query.sort.field);
|
|
258
617
|
params.set("sortDirection", query.sort.direction);
|
|
259
618
|
}
|
|
@@ -270,140 +629,22 @@ function serializeUrlState(query, filters, columnWidths, defaultPageSize, enable
|
|
|
270
629
|
}
|
|
271
630
|
return params.toString();
|
|
272
631
|
}
|
|
273
|
-
function
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
return column.format(value);
|
|
279
|
-
}
|
|
280
|
-
return String(value ?? "");
|
|
281
|
-
}
|
|
282
|
-
case "date": {
|
|
283
|
-
const value = row[column.field];
|
|
284
|
-
if (column.format) {
|
|
285
|
-
return column.format(value);
|
|
286
|
-
}
|
|
287
|
-
if (value instanceof Date) {
|
|
288
|
-
return value.toLocaleDateString();
|
|
289
|
-
}
|
|
290
|
-
if (typeof value === "string" || typeof value === "number") {
|
|
291
|
-
return new Date(value).toLocaleDateString();
|
|
292
|
-
}
|
|
293
|
-
return "";
|
|
294
|
-
}
|
|
295
|
-
case "boolean": {
|
|
296
|
-
const value = row[column.field];
|
|
297
|
-
if (column.format) {
|
|
298
|
-
return column.format(Boolean(value));
|
|
299
|
-
}
|
|
300
|
-
return value ? "Yes" : "No";
|
|
301
|
-
}
|
|
302
|
-
case "badge": {
|
|
303
|
-
const value = row[column.field];
|
|
304
|
-
const valueStr = String(value ?? "");
|
|
305
|
-
const mapped = column.map?.[valueStr];
|
|
306
|
-
const label = mapped?.label ?? valueStr;
|
|
307
|
-
const tone = mapped?.tone ?? "neutral";
|
|
308
|
-
return /* @__PURE__ */ jsx("span", { className: `rowakit-badge rowakit-badge-${tone}`, children: label });
|
|
309
|
-
}
|
|
310
|
-
case "number": {
|
|
311
|
-
const value = row[column.field];
|
|
312
|
-
const numValue = Number(value ?? 0);
|
|
313
|
-
if (column.format) {
|
|
314
|
-
if (typeof column.format === "function") {
|
|
315
|
-
return column.format(numValue, row);
|
|
316
|
-
}
|
|
317
|
-
return new Intl.NumberFormat(void 0, column.format).format(numValue);
|
|
318
|
-
}
|
|
319
|
-
return numValue.toLocaleString();
|
|
320
|
-
}
|
|
321
|
-
case "actions": {
|
|
322
|
-
const columnWithActions = column;
|
|
323
|
-
if (!Array.isArray(columnWithActions.actions)) {
|
|
324
|
-
return null;
|
|
325
|
-
}
|
|
326
|
-
return /* @__PURE__ */ jsx("div", { className: "rowakit-table-actions", children: columnWithActions.actions.map((action) => {
|
|
327
|
-
const isDisabled = isLoading || action.disabled === true || typeof action.disabled === "function" && action.disabled(row);
|
|
328
|
-
const handleClick = () => {
|
|
329
|
-
if (isDisabled || action.loading) {
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
if (action.confirm) {
|
|
333
|
-
setConfirmState({ action, row });
|
|
334
|
-
} else {
|
|
335
|
-
void action.onClick(row);
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
return /* @__PURE__ */ jsxs(
|
|
339
|
-
"button",
|
|
340
|
-
{
|
|
341
|
-
onClick: handleClick,
|
|
342
|
-
disabled: isDisabled || action.loading,
|
|
343
|
-
type: "button",
|
|
344
|
-
className: "rowakit-button rowakit-button-secondary",
|
|
345
|
-
children: [
|
|
346
|
-
action.icon && typeof action.icon === "string" ? /* @__PURE__ */ jsx("span", { children: action.icon }) : action.icon,
|
|
347
|
-
action.label
|
|
348
|
-
]
|
|
349
|
-
},
|
|
350
|
-
action.id
|
|
351
|
-
);
|
|
352
|
-
}) });
|
|
353
|
-
}
|
|
354
|
-
case "custom": {
|
|
355
|
-
return column.render(row);
|
|
356
|
-
}
|
|
357
|
-
default: {
|
|
358
|
-
const _exhaustive = column;
|
|
359
|
-
return _exhaustive;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
function RowaKitTable({
|
|
364
|
-
fetcher,
|
|
632
|
+
function useUrlSync({
|
|
633
|
+
syncToUrl,
|
|
634
|
+
enableColumnResizing,
|
|
635
|
+
defaultPageSize,
|
|
636
|
+
pageSizeOptions,
|
|
365
637
|
columns,
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
syncToUrl = false,
|
|
373
|
-
enableSavedViews = false
|
|
638
|
+
query,
|
|
639
|
+
setQuery,
|
|
640
|
+
filters,
|
|
641
|
+
setFilters,
|
|
642
|
+
columnWidths,
|
|
643
|
+
setColumnWidths
|
|
374
644
|
}) {
|
|
375
|
-
const [dataState, setDataState] = useState({
|
|
376
|
-
state: "idle",
|
|
377
|
-
items: [],
|
|
378
|
-
total: 0
|
|
379
|
-
});
|
|
380
|
-
const [query, setQuery] = useState({
|
|
381
|
-
page: 1,
|
|
382
|
-
pageSize: defaultPageSize
|
|
383
|
-
});
|
|
384
|
-
const [filters, setFilters] = useState({});
|
|
385
|
-
const [columnWidths, setColumnWidths] = useState({});
|
|
386
|
-
const resizeRafRef = useRef(null);
|
|
387
|
-
const resizePendingRef = useRef(null);
|
|
388
|
-
const tableRef = useRef(null);
|
|
389
|
-
const isResizingRef = useRef(false);
|
|
390
|
-
const lastResizeEndTsRef = useRef(0);
|
|
391
|
-
const resizingColIdRef = useRef(null);
|
|
392
645
|
const didHydrateUrlRef = useRef(false);
|
|
393
646
|
const didSkipInitialUrlSyncRef = useRef(false);
|
|
394
647
|
const urlSyncDebounceRef = useRef(null);
|
|
395
|
-
const [savedViews, setSavedViews] = useState([]);
|
|
396
|
-
const [showSaveViewForm, setShowSaveViewForm] = useState(false);
|
|
397
|
-
const [saveViewInput, setSaveViewInput] = useState("");
|
|
398
|
-
const [saveViewError, setSaveViewError] = useState("");
|
|
399
|
-
const [overwriteConfirmName, setOverwriteConfirmName] = useState(null);
|
|
400
|
-
useEffect(() => {
|
|
401
|
-
if (!enableSavedViews) return;
|
|
402
|
-
const views = loadSavedViewsFromStorage();
|
|
403
|
-
setSavedViews(views);
|
|
404
|
-
}, [enableSavedViews]);
|
|
405
|
-
const [confirmState, setConfirmState] = useState(null);
|
|
406
|
-
const requestIdRef = useRef(0);
|
|
407
648
|
useEffect(() => {
|
|
408
649
|
if (!syncToUrl) {
|
|
409
650
|
didSkipInitialUrlSyncRef.current = false;
|
|
@@ -420,7 +661,14 @@ function RowaKitTable({
|
|
|
420
661
|
const urlStr = serializeUrlState(query, filters, columnWidths, defaultPageSize, enableColumnResizing);
|
|
421
662
|
const qs = urlStr ? `?${urlStr}` : "";
|
|
422
663
|
window.history.replaceState(null, "", `${window.location.pathname}${qs}${window.location.hash}`);
|
|
423
|
-
}, [
|
|
664
|
+
}, [
|
|
665
|
+
query,
|
|
666
|
+
filters,
|
|
667
|
+
syncToUrl,
|
|
668
|
+
enableColumnResizing,
|
|
669
|
+
defaultPageSize,
|
|
670
|
+
columnWidths
|
|
671
|
+
]);
|
|
424
672
|
useEffect(() => {
|
|
425
673
|
if (!syncToUrl || !enableColumnResizing) return;
|
|
426
674
|
if (!didSkipInitialUrlSyncRef.current) return;
|
|
@@ -439,7 +687,14 @@ function RowaKitTable({
|
|
|
439
687
|
urlSyncDebounceRef.current = null;
|
|
440
688
|
}
|
|
441
689
|
};
|
|
442
|
-
}, [
|
|
690
|
+
}, [
|
|
691
|
+
columnWidths,
|
|
692
|
+
syncToUrl,
|
|
693
|
+
enableColumnResizing,
|
|
694
|
+
query,
|
|
695
|
+
filters,
|
|
696
|
+
defaultPageSize
|
|
697
|
+
]);
|
|
443
698
|
useEffect(() => {
|
|
444
699
|
if (!syncToUrl) {
|
|
445
700
|
didHydrateUrlRef.current = false;
|
|
@@ -453,6 +708,7 @@ function RowaKitTable({
|
|
|
453
708
|
page: parsed.page,
|
|
454
709
|
pageSize: parsed.pageSize,
|
|
455
710
|
sort: parsed.sort,
|
|
711
|
+
sorts: parsed.sorts,
|
|
456
712
|
filters: parsed.filters
|
|
457
713
|
});
|
|
458
714
|
if (parsed.filters) {
|
|
@@ -475,256 +731,438 @@ function RowaKitTable({
|
|
|
475
731
|
}
|
|
476
732
|
setColumnWidths(clamped);
|
|
477
733
|
}
|
|
478
|
-
}, [
|
|
734
|
+
}, [
|
|
735
|
+
syncToUrl,
|
|
736
|
+
defaultPageSize,
|
|
737
|
+
enableColumnResizing,
|
|
738
|
+
pageSizeOptions,
|
|
739
|
+
columns,
|
|
740
|
+
setQuery,
|
|
741
|
+
setFilters,
|
|
742
|
+
setColumnWidths
|
|
743
|
+
]);
|
|
744
|
+
}
|
|
745
|
+
var FOCUSABLE_SELECTORS = [
|
|
746
|
+
"button",
|
|
747
|
+
"[href]",
|
|
748
|
+
"input",
|
|
749
|
+
"select",
|
|
750
|
+
"textarea",
|
|
751
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
752
|
+
].join(",");
|
|
753
|
+
function useFocusTrap(ref, options = {}) {
|
|
754
|
+
const { onEscape, autoFocus = true } = options;
|
|
755
|
+
const firstFocusableRef = useRef(null);
|
|
756
|
+
const lastFocusableRef = useRef(null);
|
|
479
757
|
useEffect(() => {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
758
|
+
const modalEl = ref.current;
|
|
759
|
+
if (!modalEl) return;
|
|
760
|
+
const getFocusableElements = () => {
|
|
761
|
+
const elements = Array.from(modalEl.querySelectorAll(FOCUSABLE_SELECTORS));
|
|
762
|
+
return elements.filter((el) => !el.hasAttribute("disabled") && el.offsetParent !== null);
|
|
763
|
+
};
|
|
764
|
+
let focusableElements = getFocusableElements();
|
|
765
|
+
if (focusableElements.length === 0) return;
|
|
766
|
+
firstFocusableRef.current = focusableElements[0] || null;
|
|
767
|
+
lastFocusableRef.current = focusableElements[focusableElements.length - 1] || null;
|
|
768
|
+
if (autoFocus && firstFocusableRef.current) {
|
|
769
|
+
firstFocusableRef.current.focus();
|
|
488
770
|
}
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const currentRequestId = ++requestIdRef.current;
|
|
499
|
-
setDataState((prev) => ({ ...prev, state: "loading" }));
|
|
500
|
-
fetcher(query).then((result) => {
|
|
501
|
-
if (currentRequestId !== requestIdRef.current) {
|
|
771
|
+
const handleKeyDown = (e) => {
|
|
772
|
+
focusableElements = getFocusableElements();
|
|
773
|
+
if (focusableElements.length === 0) return;
|
|
774
|
+
const activeEl = document.activeElement;
|
|
775
|
+
const firstEl = focusableElements[0] || null;
|
|
776
|
+
const lastEl = focusableElements[focusableElements.length - 1] || null;
|
|
777
|
+
if (e.key === "Escape") {
|
|
778
|
+
e.preventDefault();
|
|
779
|
+
onEscape?.();
|
|
502
780
|
return;
|
|
503
781
|
}
|
|
504
|
-
if (
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
782
|
+
if (e.key === "Tab") {
|
|
783
|
+
if (e.shiftKey) {
|
|
784
|
+
if (activeEl === firstEl && lastEl) {
|
|
785
|
+
e.preventDefault();
|
|
786
|
+
lastEl.focus();
|
|
787
|
+
}
|
|
788
|
+
} else {
|
|
789
|
+
if (activeEl === lastEl && firstEl) {
|
|
790
|
+
e.preventDefault();
|
|
791
|
+
firstEl.focus();
|
|
792
|
+
}
|
|
793
|
+
}
|
|
516
794
|
}
|
|
517
|
-
}
|
|
518
|
-
|
|
795
|
+
};
|
|
796
|
+
modalEl.addEventListener("keydown", handleKeyDown);
|
|
797
|
+
return () => {
|
|
798
|
+
modalEl.removeEventListener("keydown", handleKeyDown);
|
|
799
|
+
};
|
|
800
|
+
}, [ref, onEscape, autoFocus]);
|
|
801
|
+
}
|
|
802
|
+
function RowSelectionHeaderCell(props) {
|
|
803
|
+
const checkboxRef = useRef(null);
|
|
804
|
+
useEffect(() => {
|
|
805
|
+
if (!checkboxRef.current) return;
|
|
806
|
+
checkboxRef.current.indeterminate = props.indeterminate;
|
|
807
|
+
}, [props.indeterminate]);
|
|
808
|
+
return /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsx(
|
|
809
|
+
"input",
|
|
810
|
+
{
|
|
811
|
+
ref: checkboxRef,
|
|
812
|
+
type: "checkbox",
|
|
813
|
+
"aria-label": "Select all rows",
|
|
814
|
+
disabled: props.disabled,
|
|
815
|
+
checked: props.checked,
|
|
816
|
+
onChange: (e) => props.onChange(e.target.checked)
|
|
817
|
+
}
|
|
818
|
+
) });
|
|
819
|
+
}
|
|
820
|
+
function RowSelectionCell(props) {
|
|
821
|
+
return /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx(
|
|
822
|
+
"input",
|
|
823
|
+
{
|
|
824
|
+
type: "checkbox",
|
|
825
|
+
"aria-label": `Select row ${props.rowKey}`,
|
|
826
|
+
disabled: props.disabled,
|
|
827
|
+
checked: props.checked,
|
|
828
|
+
onChange: (e) => props.onChange(e.target.checked)
|
|
829
|
+
}
|
|
830
|
+
) });
|
|
831
|
+
}
|
|
832
|
+
function BulkActionBar(props) {
|
|
833
|
+
if (props.selectedCount <= 0) return null;
|
|
834
|
+
return /* @__PURE__ */ jsxs("div", { className: "rowakit-bulk-action-bar", children: [
|
|
835
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
836
|
+
props.selectedCount,
|
|
837
|
+
" selected"
|
|
838
|
+
] }),
|
|
839
|
+
props.actions.map((action) => /* @__PURE__ */ jsx(
|
|
840
|
+
"button",
|
|
841
|
+
{
|
|
842
|
+
type: "button",
|
|
843
|
+
className: "rowakit-button rowakit-button-secondary",
|
|
844
|
+
onClick: () => props.onActionClick(action.id),
|
|
845
|
+
children: action.label
|
|
846
|
+
},
|
|
847
|
+
action.id
|
|
848
|
+
))
|
|
849
|
+
] });
|
|
850
|
+
}
|
|
851
|
+
function downloadBlob(blob, filename) {
|
|
852
|
+
if (typeof window === "undefined") return;
|
|
853
|
+
if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function") return;
|
|
854
|
+
const url = URL.createObjectURL(blob);
|
|
855
|
+
try {
|
|
856
|
+
const a = document.createElement("a");
|
|
857
|
+
a.href = url;
|
|
858
|
+
a.download = filename;
|
|
859
|
+
a.rel = "noopener noreferrer";
|
|
860
|
+
a.click();
|
|
861
|
+
} finally {
|
|
862
|
+
URL.revokeObjectURL(url);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
function openUrl(url) {
|
|
866
|
+
if (typeof window === "undefined") return;
|
|
867
|
+
if (typeof window.open === "function") {
|
|
868
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
try {
|
|
872
|
+
window.location.assign(url);
|
|
873
|
+
} catch {
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function ExportButton(props) {
|
|
877
|
+
const [isExporting, setIsExporting] = useState(false);
|
|
878
|
+
const [error, setError] = useState(null);
|
|
879
|
+
const onClick = async () => {
|
|
880
|
+
if (isExporting) return;
|
|
881
|
+
setIsExporting(true);
|
|
882
|
+
setError(null);
|
|
883
|
+
try {
|
|
884
|
+
const snapshot = { ...props.query };
|
|
885
|
+
const result = await props.exporter(snapshot);
|
|
886
|
+
if (result instanceof Blob) {
|
|
887
|
+
downloadBlob(result, "rowakit-export.csv");
|
|
519
888
|
return;
|
|
520
889
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
});
|
|
527
|
-
});
|
|
528
|
-
}, [fetcher, query]);
|
|
529
|
-
const handleRetry = () => {
|
|
530
|
-
setQuery({ ...query });
|
|
531
|
-
};
|
|
532
|
-
const handlePreviousPage = () => {
|
|
533
|
-
if (query.page > 1) {
|
|
534
|
-
setQuery((prev) => ({ ...prev, page: prev.page - 1 }));
|
|
890
|
+
openUrl(result.url);
|
|
891
|
+
} catch (e) {
|
|
892
|
+
setError(e instanceof Error ? e.message : "Export failed");
|
|
893
|
+
} finally {
|
|
894
|
+
setIsExporting(false);
|
|
535
895
|
}
|
|
536
896
|
};
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
897
|
+
return /* @__PURE__ */ jsxs("div", { className: "rowakit-export", children: [
|
|
898
|
+
/* @__PURE__ */ jsx(
|
|
899
|
+
"button",
|
|
900
|
+
{
|
|
901
|
+
type: "button",
|
|
902
|
+
className: "rowakit-button rowakit-button-secondary",
|
|
903
|
+
onClick,
|
|
904
|
+
disabled: isExporting,
|
|
905
|
+
children: isExporting ? "Exporting\u2026" : "Export CSV"
|
|
906
|
+
}
|
|
907
|
+
),
|
|
908
|
+
error && /* @__PURE__ */ jsx("div", { className: "rowakit-export-error", children: error })
|
|
909
|
+
] });
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// src/state/selection.ts
|
|
913
|
+
function toggleSelectionKey(selected, key) {
|
|
914
|
+
if (selected.includes(key)) {
|
|
915
|
+
return selected.filter((k) => k !== key);
|
|
916
|
+
}
|
|
917
|
+
return [...selected, key];
|
|
918
|
+
}
|
|
919
|
+
function isAllSelected(selected, pageKeys) {
|
|
920
|
+
if (pageKeys.length === 0) return false;
|
|
921
|
+
return pageKeys.every((k) => selected.includes(k));
|
|
922
|
+
}
|
|
923
|
+
function isIndeterminate(selected, pageKeys) {
|
|
924
|
+
if (pageKeys.length === 0) return false;
|
|
925
|
+
const selectedCount = pageKeys.filter((k) => selected.includes(k)).length;
|
|
926
|
+
return selectedCount > 0 && selectedCount < pageKeys.length;
|
|
927
|
+
}
|
|
928
|
+
function selectAll(pageKeys) {
|
|
929
|
+
return [...pageKeys];
|
|
930
|
+
}
|
|
931
|
+
function clearSelection() {
|
|
932
|
+
return [];
|
|
933
|
+
}
|
|
934
|
+
function getRowKey(row, rowKey) {
|
|
935
|
+
if (typeof rowKey === "function") {
|
|
936
|
+
return rowKey(row);
|
|
937
|
+
}
|
|
938
|
+
if (rowKey) {
|
|
939
|
+
return String(row[rowKey]);
|
|
940
|
+
}
|
|
941
|
+
if (row && typeof row === "object" && "id" in row) {
|
|
942
|
+
return String(row.id);
|
|
943
|
+
}
|
|
944
|
+
return String(row);
|
|
945
|
+
}
|
|
946
|
+
function getHeaderLabel(column) {
|
|
947
|
+
return column.header ?? column.id;
|
|
948
|
+
}
|
|
949
|
+
function renderCell(column, row, isLoading, setConfirmState) {
|
|
950
|
+
switch (column.kind) {
|
|
951
|
+
case "text": {
|
|
952
|
+
const value = row[column.field];
|
|
953
|
+
if (column.format) {
|
|
954
|
+
return column.format(value);
|
|
955
|
+
}
|
|
956
|
+
return String(value ?? "");
|
|
541
957
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
const handleSort = (field) => {
|
|
547
|
-
setQuery((prev) => {
|
|
548
|
-
if (prev.sort?.field !== field) {
|
|
549
|
-
return { ...prev, sort: { field, direction: "asc" }, page: 1 };
|
|
958
|
+
case "date": {
|
|
959
|
+
const value = row[column.field];
|
|
960
|
+
if (column.format) {
|
|
961
|
+
return column.format(value);
|
|
550
962
|
}
|
|
551
|
-
if (
|
|
552
|
-
return
|
|
963
|
+
if (value instanceof Date) {
|
|
964
|
+
return value.toLocaleDateString();
|
|
965
|
+
}
|
|
966
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
967
|
+
return new Date(value).toLocaleDateString();
|
|
553
968
|
}
|
|
554
|
-
const { sort: _sort, ...rest } = prev;
|
|
555
|
-
return { ...rest, page: 1 };
|
|
556
|
-
});
|
|
557
|
-
};
|
|
558
|
-
const getSortIndicator = (field) => {
|
|
559
|
-
if (!query.sort || query.sort.field !== field) {
|
|
560
969
|
return "";
|
|
561
970
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
resizeRafRef.current = null;
|
|
569
|
-
const pending = resizePendingRef.current;
|
|
570
|
-
if (!pending) return;
|
|
571
|
-
handleColumnResize(pending.colId, pending.width);
|
|
572
|
-
});
|
|
573
|
-
};
|
|
574
|
-
const handleColumnResize = (columnId, newWidth) => {
|
|
575
|
-
const minWidth = columns.find((c) => c.id === columnId)?.minWidth ?? 80;
|
|
576
|
-
const maxWidth = columns.find((c) => c.id === columnId)?.maxWidth;
|
|
577
|
-
let finalWidth = Math.max(minWidth, newWidth);
|
|
578
|
-
if (maxWidth) {
|
|
579
|
-
finalWidth = Math.min(finalWidth, maxWidth);
|
|
580
|
-
}
|
|
581
|
-
if (columnWidths[columnId] === finalWidth) {
|
|
582
|
-
return;
|
|
971
|
+
case "boolean": {
|
|
972
|
+
const value = row[column.field];
|
|
973
|
+
if (column.format) {
|
|
974
|
+
return column.format(Boolean(value));
|
|
975
|
+
}
|
|
976
|
+
return value ? "Yes" : "No";
|
|
583
977
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
if (!tableEl) return;
|
|
592
|
-
const th = tableEl.querySelector(`th[data-col-id="${columnId}"]`);
|
|
593
|
-
if (!th) return;
|
|
594
|
-
const tds = Array.from(
|
|
595
|
-
tableEl.querySelectorAll(`td[data-col-id="${columnId}"]`)
|
|
596
|
-
);
|
|
597
|
-
const headerW = th.scrollWidth;
|
|
598
|
-
const cellsMaxW = tds.reduce((max, td) => Math.max(max, td.scrollWidth), 0);
|
|
599
|
-
const padding = 24;
|
|
600
|
-
const raw = Math.max(headerW, cellsMaxW) + padding;
|
|
601
|
-
const colDef = columns.find((c) => c.id === columnId);
|
|
602
|
-
const minW = colDef?.minWidth ?? 80;
|
|
603
|
-
const maxW = colDef?.maxWidth ?? 600;
|
|
604
|
-
const finalW = Math.max(minW, Math.min(raw, maxW));
|
|
605
|
-
setColumnWidths((prev) => ({ ...prev, [columnId]: finalW }));
|
|
606
|
-
};
|
|
607
|
-
const startColumnResize = (e, columnId) => {
|
|
608
|
-
e.preventDefault();
|
|
609
|
-
e.stopPropagation();
|
|
610
|
-
if (e.detail === 2) {
|
|
611
|
-
autoFitColumnWidth(columnId);
|
|
612
|
-
return;
|
|
978
|
+
case "badge": {
|
|
979
|
+
const value = row[column.field];
|
|
980
|
+
const valueStr = String(value ?? "");
|
|
981
|
+
const mapped = column.map?.[valueStr];
|
|
982
|
+
const label = mapped?.label ?? valueStr;
|
|
983
|
+
const tone = mapped?.tone ?? "neutral";
|
|
984
|
+
return /* @__PURE__ */ jsx("span", { className: `rowakit-badge rowakit-badge-${tone}`, children: label });
|
|
613
985
|
}
|
|
614
|
-
|
|
615
|
-
|
|
986
|
+
case "number": {
|
|
987
|
+
const value = row[column.field];
|
|
988
|
+
const numValue = Number(value ?? 0);
|
|
989
|
+
if (column.format) {
|
|
990
|
+
if (typeof column.format === "function") {
|
|
991
|
+
return column.format(numValue, row);
|
|
992
|
+
}
|
|
993
|
+
return new Intl.NumberFormat(void 0, column.format).format(numValue);
|
|
994
|
+
}
|
|
995
|
+
return numValue.toLocaleString();
|
|
616
996
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
997
|
+
case "actions": {
|
|
998
|
+
const columnWithActions = column;
|
|
999
|
+
if (!Array.isArray(columnWithActions.actions)) {
|
|
1000
|
+
return null;
|
|
1001
|
+
}
|
|
1002
|
+
return /* @__PURE__ */ jsx("div", { className: "rowakit-table-actions", children: columnWithActions.actions.map((action) => {
|
|
1003
|
+
const isDisabled = isLoading || action.disabled === true || typeof action.disabled === "function" && action.disabled(row);
|
|
1004
|
+
const handleClick = () => {
|
|
1005
|
+
if (isDisabled || action.loading) {
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
if (action.confirm) {
|
|
1009
|
+
setConfirmState({ action, row });
|
|
1010
|
+
} else {
|
|
1011
|
+
void action.onClick(row);
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
return /* @__PURE__ */ jsxs(
|
|
1015
|
+
"button",
|
|
1016
|
+
{
|
|
1017
|
+
onClick: handleClick,
|
|
1018
|
+
disabled: isDisabled || action.loading,
|
|
1019
|
+
type: "button",
|
|
1020
|
+
className: "rowakit-button rowakit-button-secondary",
|
|
1021
|
+
children: [
|
|
1022
|
+
action.icon && typeof action.icon === "string" ? /* @__PURE__ */ jsx("span", { children: action.icon }) : action.icon,
|
|
1023
|
+
action.label
|
|
1024
|
+
]
|
|
1025
|
+
},
|
|
1026
|
+
action.id
|
|
1027
|
+
);
|
|
1028
|
+
}) });
|
|
622
1029
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
const startX = e.clientX;
|
|
626
|
-
const th = target.parentElement;
|
|
627
|
-
let startWidth = columnWidths[columnId] ?? th.offsetWidth;
|
|
628
|
-
const MIN_DRAG_WIDTH = 80;
|
|
629
|
-
if (startWidth < MIN_DRAG_WIDTH) {
|
|
630
|
-
const nextTh = th.nextElementSibling;
|
|
631
|
-
if (nextTh && nextTh.offsetWidth >= 50) {
|
|
632
|
-
startWidth = nextTh.offsetWidth;
|
|
633
|
-
} else {
|
|
634
|
-
startWidth = 100;
|
|
635
|
-
}
|
|
1030
|
+
case "custom": {
|
|
1031
|
+
return column.render(row);
|
|
636
1032
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
1033
|
+
default: {
|
|
1034
|
+
const _exhaustive = column;
|
|
1035
|
+
return _exhaustive;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
function RowaKitTable({
|
|
1040
|
+
fetcher,
|
|
1041
|
+
columns,
|
|
1042
|
+
defaultPageSize = 20,
|
|
1043
|
+
pageSizeOptions = [10, 20, 50],
|
|
1044
|
+
rowKey,
|
|
1045
|
+
className = "",
|
|
1046
|
+
enableFilters = false,
|
|
1047
|
+
enableColumnResizing = false,
|
|
1048
|
+
syncToUrl = false,
|
|
1049
|
+
enableSavedViews = false,
|
|
1050
|
+
enableRowSelection = false,
|
|
1051
|
+
onSelectionChange,
|
|
1052
|
+
bulkActions,
|
|
1053
|
+
exporter
|
|
1054
|
+
}) {
|
|
1055
|
+
const [query, setQuery] = useState({
|
|
1056
|
+
page: 1,
|
|
1057
|
+
pageSize: defaultPageSize
|
|
1058
|
+
});
|
|
1059
|
+
const [filters, setFilters] = useState({});
|
|
1060
|
+
const [confirmState, setConfirmState] = useState(null);
|
|
1061
|
+
const [selectedKeys, setSelectedKeys] = useState([]);
|
|
1062
|
+
const [bulkConfirmState, setBulkConfirmState] = useState(null);
|
|
1063
|
+
const confirmModalRef = useRef(null);
|
|
1064
|
+
const bulkConfirmModalRef = useRef(null);
|
|
1065
|
+
const {
|
|
1066
|
+
tableRef,
|
|
1067
|
+
columnWidths,
|
|
1068
|
+
setColumnWidths,
|
|
1069
|
+
startColumnResize,
|
|
1070
|
+
handleColumnResizeDoubleClick,
|
|
1071
|
+
isResizingRef,
|
|
1072
|
+
lastResizeEndTsRef,
|
|
1073
|
+
resizingColIdRef
|
|
1074
|
+
} = useColumnResizing(columns);
|
|
1075
|
+
useUrlSync({
|
|
1076
|
+
syncToUrl,
|
|
1077
|
+
enableColumnResizing,
|
|
1078
|
+
defaultPageSize,
|
|
1079
|
+
pageSizeOptions,
|
|
1080
|
+
columns,
|
|
1081
|
+
query,
|
|
1082
|
+
setQuery,
|
|
1083
|
+
filters,
|
|
1084
|
+
setFilters,
|
|
1085
|
+
columnWidths,
|
|
1086
|
+
setColumnWidths
|
|
1087
|
+
});
|
|
1088
|
+
const { dataState, handleRetry, isLoading, isError, isEmpty } = useFetcherState(fetcher, query, setQuery);
|
|
1089
|
+
const { handleSort, getSortIndicator } = useSortingState(query, setQuery);
|
|
1090
|
+
const pageRowKeys = dataState.items.map((row) => getRowKey(row, rowKey));
|
|
1091
|
+
const headerChecked = isAllSelected(selectedKeys, pageRowKeys);
|
|
1092
|
+
const headerIndeterminate = isIndeterminate(selectedKeys, pageRowKeys);
|
|
1093
|
+
useEffect(() => {
|
|
1094
|
+
if (!enableRowSelection) return;
|
|
1095
|
+
setSelectedKeys(clearSelection());
|
|
1096
|
+
}, [enableRowSelection, query.page, dataState.items]);
|
|
1097
|
+
useEffect(() => {
|
|
1098
|
+
if (!enableRowSelection || !onSelectionChange) return;
|
|
1099
|
+
onSelectionChange(selectedKeys);
|
|
1100
|
+
}, [enableRowSelection, onSelectionChange, selectedKeys]);
|
|
1101
|
+
const {
|
|
1102
|
+
savedViews,
|
|
1103
|
+
showSaveViewForm,
|
|
1104
|
+
saveViewInput,
|
|
1105
|
+
saveViewError,
|
|
1106
|
+
overwriteConfirmName,
|
|
1107
|
+
openSaveViewForm,
|
|
1108
|
+
cancelSaveViewForm,
|
|
1109
|
+
onSaveViewInputChange,
|
|
1110
|
+
onSaveViewInputKeyDown,
|
|
1111
|
+
attemptSave,
|
|
1112
|
+
confirmOverwrite,
|
|
1113
|
+
cancelOverwrite,
|
|
1114
|
+
loadSavedView,
|
|
1115
|
+
deleteSavedView,
|
|
1116
|
+
resetTableState
|
|
1117
|
+
} = useSavedViews({
|
|
1118
|
+
enableSavedViews,
|
|
1119
|
+
enableColumnResizing,
|
|
1120
|
+
defaultPageSize,
|
|
1121
|
+
query,
|
|
1122
|
+
setQuery,
|
|
1123
|
+
setFilters,
|
|
1124
|
+
columnWidths,
|
|
1125
|
+
setColumnWidths
|
|
1126
|
+
});
|
|
1127
|
+
useFocusTrap(confirmModalRef, {
|
|
1128
|
+
onEscape: () => setConfirmState(null),
|
|
1129
|
+
autoFocus: true
|
|
1130
|
+
});
|
|
1131
|
+
useFocusTrap(bulkConfirmModalRef, {
|
|
1132
|
+
onEscape: () => setBulkConfirmState(null),
|
|
1133
|
+
autoFocus: true
|
|
1134
|
+
});
|
|
1135
|
+
useEffect(() => {
|
|
1136
|
+
if (!enableFilters) return;
|
|
1137
|
+
const activeFilters = {};
|
|
1138
|
+
let hasFilters = false;
|
|
1139
|
+
for (const [field, value] of Object.entries(filters)) {
|
|
1140
|
+
if (value !== void 0) {
|
|
1141
|
+
activeFilters[field] = value;
|
|
1142
|
+
hasFilters = true;
|
|
691
1143
|
}
|
|
692
1144
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
setFilters(state.filters ?? {});
|
|
705
|
-
if (state.columnWidths && enableColumnResizing) {
|
|
706
|
-
setColumnWidths(state.columnWidths);
|
|
1145
|
+
const filtersToSend = hasFilters ? activeFilters : void 0;
|
|
1146
|
+
setQuery((prev) => ({
|
|
1147
|
+
...prev,
|
|
1148
|
+
filters: filtersToSend,
|
|
1149
|
+
page: 1
|
|
1150
|
+
// Reset page to 1 when filters change
|
|
1151
|
+
}));
|
|
1152
|
+
}, [filters, enableFilters]);
|
|
1153
|
+
const handlePreviousPage = () => {
|
|
1154
|
+
if (query.page > 1) {
|
|
1155
|
+
setQuery((prev) => ({ ...prev, page: prev.page - 1 }));
|
|
707
1156
|
}
|
|
708
1157
|
};
|
|
709
|
-
const
|
|
710
|
-
|
|
711
|
-
if (
|
|
712
|
-
|
|
713
|
-
localStorage.removeItem(`rowakit-view-${name}`);
|
|
714
|
-
const index = getSavedViewsIndex();
|
|
715
|
-
const filtered = index.filter((v) => v.name !== name);
|
|
716
|
-
setSavedViewsIndex(filtered);
|
|
717
|
-
} catch {
|
|
718
|
-
}
|
|
1158
|
+
const handleNextPage = () => {
|
|
1159
|
+
const totalPages2 = Math.ceil(dataState.total / query.pageSize);
|
|
1160
|
+
if (query.page < totalPages2) {
|
|
1161
|
+
setQuery((prev) => ({ ...prev, page: prev.page + 1 }));
|
|
719
1162
|
}
|
|
720
1163
|
};
|
|
721
|
-
const
|
|
722
|
-
setQuery({
|
|
723
|
-
page: 1,
|
|
724
|
-
pageSize: defaultPageSize
|
|
725
|
-
});
|
|
726
|
-
setFilters({});
|
|
727
|
-
setColumnWidths({});
|
|
1164
|
+
const handlePageSizeChange = (newPageSize) => {
|
|
1165
|
+
setQuery({ ...query, pageSize: newPageSize, page: 1 });
|
|
728
1166
|
};
|
|
729
1167
|
const transformFilterValueForColumn = (column, value) => {
|
|
730
1168
|
if (!value || column?.kind !== "number") {
|
|
@@ -770,12 +1208,10 @@ function RowaKitTable({
|
|
|
770
1208
|
const handleClearAllFilters = () => {
|
|
771
1209
|
setFilters({});
|
|
772
1210
|
};
|
|
773
|
-
const isLoading = dataState.state === "loading";
|
|
774
|
-
const isError = dataState.state === "error";
|
|
775
|
-
const isEmpty = dataState.state === "empty";
|
|
776
1211
|
const totalPages = Math.ceil(dataState.total / query.pageSize);
|
|
777
1212
|
const canGoPrevious = query.page > 1 && !isLoading;
|
|
778
1213
|
const canGoNext = query.page < totalPages && !isLoading;
|
|
1214
|
+
const tableColumnCount = columns.length + (enableRowSelection ? 1 : 0);
|
|
779
1215
|
const hasActiveFilters = enableFilters && Object.values(filters).some((v) => v !== void 0);
|
|
780
1216
|
const containerClass = [
|
|
781
1217
|
"rowakit-table",
|
|
@@ -783,16 +1219,29 @@ function RowaKitTable({
|
|
|
783
1219
|
className
|
|
784
1220
|
].filter(Boolean).join(" ");
|
|
785
1221
|
return /* @__PURE__ */ jsxs("div", { className: containerClass, children: [
|
|
1222
|
+
enableRowSelection && bulkActions && bulkActions.length > 0 && selectedKeys.length > 0 && /* @__PURE__ */ jsx(
|
|
1223
|
+
BulkActionBar,
|
|
1224
|
+
{
|
|
1225
|
+
selectedCount: selectedKeys.length,
|
|
1226
|
+
actions: bulkActions,
|
|
1227
|
+
onActionClick: (actionId) => {
|
|
1228
|
+
const action = bulkActions.find((a) => a.id === actionId);
|
|
1229
|
+
if (!action) return;
|
|
1230
|
+
const snapshot = [...selectedKeys];
|
|
1231
|
+
if (action.confirm) {
|
|
1232
|
+
setBulkConfirmState({ action, selectedKeys: snapshot });
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
action.onClick(snapshot);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
),
|
|
1239
|
+
exporter && /* @__PURE__ */ jsx(ExportButton, { exporter, query }),
|
|
786
1240
|
enableSavedViews && /* @__PURE__ */ jsxs("div", { className: "rowakit-saved-views-group", children: [
|
|
787
1241
|
!showSaveViewForm ? /* @__PURE__ */ jsx(
|
|
788
1242
|
"button",
|
|
789
1243
|
{
|
|
790
|
-
onClick:
|
|
791
|
-
setShowSaveViewForm(true);
|
|
792
|
-
setSaveViewInput("");
|
|
793
|
-
setSaveViewError("");
|
|
794
|
-
setOverwriteConfirmName(null);
|
|
795
|
-
},
|
|
1244
|
+
onClick: openSaveViewForm,
|
|
796
1245
|
className: "rowakit-saved-view-button",
|
|
797
1246
|
type: "button",
|
|
798
1247
|
children: "Save View"
|
|
@@ -806,13 +1255,7 @@ function RowaKitTable({
|
|
|
806
1255
|
/* @__PURE__ */ jsx(
|
|
807
1256
|
"button",
|
|
808
1257
|
{
|
|
809
|
-
onClick:
|
|
810
|
-
saveCurrentView(overwriteConfirmName);
|
|
811
|
-
setShowSaveViewForm(false);
|
|
812
|
-
setSaveViewInput("");
|
|
813
|
-
setSaveViewError("");
|
|
814
|
-
setOverwriteConfirmName(null);
|
|
815
|
-
},
|
|
1258
|
+
onClick: confirmOverwrite,
|
|
816
1259
|
className: "rowakit-saved-view-button",
|
|
817
1260
|
type: "button",
|
|
818
1261
|
children: "Overwrite"
|
|
@@ -821,9 +1264,7 @@ function RowaKitTable({
|
|
|
821
1264
|
/* @__PURE__ */ jsx(
|
|
822
1265
|
"button",
|
|
823
1266
|
{
|
|
824
|
-
onClick:
|
|
825
|
-
setOverwriteConfirmName(null);
|
|
826
|
-
},
|
|
1267
|
+
onClick: cancelOverwrite,
|
|
827
1268
|
className: "rowakit-saved-view-button",
|
|
828
1269
|
type: "button",
|
|
829
1270
|
children: "Cancel"
|
|
@@ -835,27 +1276,8 @@ function RowaKitTable({
|
|
|
835
1276
|
{
|
|
836
1277
|
type: "text",
|
|
837
1278
|
value: saveViewInput,
|
|
838
|
-
onChange:
|
|
839
|
-
|
|
840
|
-
setSaveViewError("");
|
|
841
|
-
},
|
|
842
|
-
onKeyDown: (e) => {
|
|
843
|
-
if (e.key === "Enter") {
|
|
844
|
-
const validation = validateViewName(saveViewInput);
|
|
845
|
-
if (!validation.valid) {
|
|
846
|
-
setSaveViewError(validation.error || "Invalid name");
|
|
847
|
-
return;
|
|
848
|
-
}
|
|
849
|
-
if (savedViews.some((v) => v.name === saveViewInput.trim())) {
|
|
850
|
-
setOverwriteConfirmName(saveViewInput.trim());
|
|
851
|
-
} else {
|
|
852
|
-
saveCurrentView(saveViewInput.trim());
|
|
853
|
-
setShowSaveViewForm(false);
|
|
854
|
-
setSaveViewInput("");
|
|
855
|
-
setSaveViewError("");
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
},
|
|
1279
|
+
onChange: onSaveViewInputChange,
|
|
1280
|
+
onKeyDown: onSaveViewInputKeyDown,
|
|
859
1281
|
placeholder: "Enter view name...",
|
|
860
1282
|
className: "rowakit-save-view-input"
|
|
861
1283
|
}
|
|
@@ -864,21 +1286,7 @@ function RowaKitTable({
|
|
|
864
1286
|
/* @__PURE__ */ jsx(
|
|
865
1287
|
"button",
|
|
866
1288
|
{
|
|
867
|
-
onClick:
|
|
868
|
-
const validation = validateViewName(saveViewInput);
|
|
869
|
-
if (!validation.valid) {
|
|
870
|
-
setSaveViewError(validation.error || "Invalid name");
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
if (savedViews.some((v) => v.name === saveViewInput.trim())) {
|
|
874
|
-
setOverwriteConfirmName(saveViewInput.trim());
|
|
875
|
-
} else {
|
|
876
|
-
saveCurrentView(saveViewInput.trim());
|
|
877
|
-
setShowSaveViewForm(false);
|
|
878
|
-
setSaveViewInput("");
|
|
879
|
-
setSaveViewError("");
|
|
880
|
-
}
|
|
881
|
-
},
|
|
1289
|
+
onClick: attemptSave,
|
|
882
1290
|
className: "rowakit-saved-view-button",
|
|
883
1291
|
type: "button",
|
|
884
1292
|
children: "Save"
|
|
@@ -887,11 +1295,7 @@ function RowaKitTable({
|
|
|
887
1295
|
/* @__PURE__ */ jsx(
|
|
888
1296
|
"button",
|
|
889
1297
|
{
|
|
890
|
-
onClick:
|
|
891
|
-
setShowSaveViewForm(false);
|
|
892
|
-
setSaveViewInput("");
|
|
893
|
-
setSaveViewError("");
|
|
894
|
-
},
|
|
1298
|
+
onClick: cancelSaveViewForm,
|
|
895
1299
|
className: "rowakit-saved-view-button",
|
|
896
1300
|
type: "button",
|
|
897
1301
|
children: "Cancel"
|
|
@@ -940,167 +1344,143 @@ function RowaKitTable({
|
|
|
940
1344
|
) }),
|
|
941
1345
|
/* @__PURE__ */ jsxs("table", { ref: tableRef, children: [
|
|
942
1346
|
/* @__PURE__ */ jsxs("thead", { children: [
|
|
943
|
-
/* @__PURE__ */
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
const isResizable = enableColumnResizing && column.kind !== "actions";
|
|
947
|
-
const actualWidth = columnWidths[column.id] ?? column.width;
|
|
948
|
-
return /* @__PURE__ */ jsxs(
|
|
949
|
-
"th",
|
|
1347
|
+
/* @__PURE__ */ jsxs("tr", { children: [
|
|
1348
|
+
enableRowSelection && /* @__PURE__ */ jsx(
|
|
1349
|
+
RowSelectionHeaderCell,
|
|
950
1350
|
{
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
onKeyDown: isSortable ? (e) => {
|
|
960
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
961
|
-
e.preventDefault();
|
|
962
|
-
handleSort(String(field));
|
|
1351
|
+
checked: headerChecked,
|
|
1352
|
+
indeterminate: headerIndeterminate,
|
|
1353
|
+
disabled: isLoading || pageRowKeys.length === 0,
|
|
1354
|
+
onChange: (checked) => {
|
|
1355
|
+
if (checked) {
|
|
1356
|
+
setSelectedKeys(selectAll(pageRowKeys));
|
|
1357
|
+
} else {
|
|
1358
|
+
setSelectedKeys(clearSelection());
|
|
963
1359
|
}
|
|
964
|
-
} : void 0,
|
|
965
|
-
"aria-sort": isSortable && query.sort?.field === String(field) ? query.sort.direction === "asc" ? "ascending" : "descending" : void 0,
|
|
966
|
-
style: {
|
|
967
|
-
width: actualWidth != null ? `${actualWidth}px` : void 0,
|
|
968
|
-
textAlign: column.align,
|
|
969
|
-
position: isResizable ? "relative" : void 0
|
|
970
|
-
},
|
|
971
|
-
className: [
|
|
972
|
-
column.truncate ? "rowakit-cell-truncate" : "",
|
|
973
|
-
resizingColIdRef.current === column.id ? "resizing" : ""
|
|
974
|
-
// PRD-01
|
|
975
|
-
].filter(Boolean).join(" ") || void 0,
|
|
976
|
-
children: [
|
|
977
|
-
getHeaderLabel(column),
|
|
978
|
-
isSortable && getSortIndicator(String(field)),
|
|
979
|
-
isResizable && /* @__PURE__ */ jsx(
|
|
980
|
-
"div",
|
|
981
|
-
{
|
|
982
|
-
className: "rowakit-column-resize-handle",
|
|
983
|
-
onPointerDown: (e) => startColumnResize(e, column.id),
|
|
984
|
-
onDoubleClick: (e) => handleColumnResizeDoubleClick(e, column.id),
|
|
985
|
-
title: "Drag to resize | Double-click to auto-fit content"
|
|
986
|
-
}
|
|
987
|
-
)
|
|
988
|
-
]
|
|
989
|
-
},
|
|
990
|
-
column.id
|
|
991
|
-
);
|
|
992
|
-
}) }),
|
|
993
|
-
enableFilters && /* @__PURE__ */ jsx("tr", { className: "rowakit-table-filter-row", children: columns.map((column) => {
|
|
994
|
-
const field = column.kind === "actions" || column.kind === "custom" ? "" : String(column.field);
|
|
995
|
-
const canFilter = field && column.kind !== "actions";
|
|
996
|
-
if (!canFilter) {
|
|
997
|
-
return /* @__PURE__ */ jsx("th", {}, column.id);
|
|
998
|
-
}
|
|
999
|
-
const filterValue = filters[field];
|
|
1000
|
-
if (column.kind === "badge") {
|
|
1001
|
-
const options = column.map ? Object.keys(column.map) : [];
|
|
1002
|
-
return /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsxs(
|
|
1003
|
-
"select",
|
|
1004
|
-
{
|
|
1005
|
-
className: "rowakit-filter-select",
|
|
1006
|
-
value: filterValue?.op === "equals" ? String(filterValue.value ?? "") : "",
|
|
1007
|
-
onChange: (e) => {
|
|
1008
|
-
const value = e.target.value;
|
|
1009
|
-
if (value === "") {
|
|
1010
|
-
handleClearFilter(field);
|
|
1011
|
-
} else {
|
|
1012
|
-
handleFilterChange(field, { op: "equals", value });
|
|
1013
|
-
}
|
|
1014
|
-
},
|
|
1015
|
-
children: [
|
|
1016
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "All" }),
|
|
1017
|
-
options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
|
|
1018
|
-
]
|
|
1019
1360
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1361
|
+
}
|
|
1362
|
+
),
|
|
1363
|
+
columns.map((column) => {
|
|
1364
|
+
const isSortable = column.kind !== "actions" && (column.kind === "custom" ? false : column.sortable === true);
|
|
1365
|
+
const field = column.kind === "actions" ? "" : column.kind === "custom" ? column.field : column.field;
|
|
1366
|
+
const isResizable = enableColumnResizing && column.kind !== "actions";
|
|
1367
|
+
const actualWidth = columnWidths[column.id] ?? column.width;
|
|
1368
|
+
return /* @__PURE__ */ jsxs(
|
|
1369
|
+
"th",
|
|
1025
1370
|
{
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1371
|
+
"data-col-id": column.id,
|
|
1372
|
+
onClick: isSortable ? (e) => {
|
|
1373
|
+
if (isResizingRef.current) return;
|
|
1374
|
+
if (Date.now() - lastResizeEndTsRef.current < 150) return;
|
|
1375
|
+
const isMultiSort = e.ctrlKey || e.metaKey;
|
|
1376
|
+
handleSort(String(field), isMultiSort);
|
|
1377
|
+
} : void 0,
|
|
1378
|
+
role: isSortable ? "button" : void 0,
|
|
1379
|
+
tabIndex: isSortable ? 0 : void 0,
|
|
1380
|
+
onKeyDown: isSortable ? (e) => {
|
|
1381
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1382
|
+
e.preventDefault();
|
|
1383
|
+
const isMultiSort = e.shiftKey;
|
|
1384
|
+
handleSort(String(field), isMultiSort);
|
|
1034
1385
|
}
|
|
1386
|
+
} : void 0,
|
|
1387
|
+
"aria-sort": isSortable && (query.sorts?.find((s) => s.field === String(field))?.priority === 0 || query.sort?.field === String(field)) ? (query.sorts?.find((s) => s.field === String(field))?.direction ?? query.sort?.direction) === "asc" ? "ascending" : "descending" : void 0,
|
|
1388
|
+
style: {
|
|
1389
|
+
width: actualWidth != null ? `${actualWidth}px` : void 0,
|
|
1390
|
+
textAlign: column.align,
|
|
1391
|
+
position: isResizable ? "relative" : void 0
|
|
1035
1392
|
},
|
|
1393
|
+
className: [
|
|
1394
|
+
column.truncate ? "rowakit-cell-truncate" : "",
|
|
1395
|
+
resizingColIdRef.current === column.id ? "resizing" : ""
|
|
1396
|
+
// PRD-01
|
|
1397
|
+
].filter(Boolean).join(" ") || void 0,
|
|
1036
1398
|
children: [
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
/* @__PURE__ */ jsx(
|
|
1399
|
+
getHeaderLabel(column),
|
|
1400
|
+
isSortable && getSortIndicator(String(field)),
|
|
1401
|
+
isResizable && /* @__PURE__ */ jsx(
|
|
1402
|
+
"div",
|
|
1403
|
+
{
|
|
1404
|
+
className: "rowakit-column-resize-handle",
|
|
1405
|
+
onPointerDown: (e) => startColumnResize(e, column.id),
|
|
1406
|
+
onDoubleClick: (e) => handleColumnResizeDoubleClick(e, column.id),
|
|
1407
|
+
title: "Drag to resize | Double-click to auto-fit content"
|
|
1408
|
+
}
|
|
1409
|
+
)
|
|
1040
1410
|
]
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1411
|
+
},
|
|
1412
|
+
column.id
|
|
1413
|
+
);
|
|
1414
|
+
})
|
|
1415
|
+
] }),
|
|
1416
|
+
enableFilters && /* @__PURE__ */ jsxs("tr", { className: "rowakit-table-filter-row", children: [
|
|
1417
|
+
enableRowSelection && /* @__PURE__ */ jsx("th", {}),
|
|
1418
|
+
columns.map((column) => {
|
|
1419
|
+
const field = column.kind === "actions" || column.kind === "custom" ? "" : String(column.field);
|
|
1420
|
+
const canFilter = field && column.kind !== "actions";
|
|
1421
|
+
if (!canFilter) {
|
|
1422
|
+
return /* @__PURE__ */ jsx("th", {}, column.id);
|
|
1423
|
+
}
|
|
1424
|
+
const filterValue = filters[field];
|
|
1425
|
+
if (column.kind === "badge") {
|
|
1426
|
+
const options = column.map ? Object.keys(column.map) : [];
|
|
1427
|
+
return /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsxs(
|
|
1428
|
+
"select",
|
|
1050
1429
|
{
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
placeholder: "From",
|
|
1054
|
-
value: fromValue,
|
|
1430
|
+
className: "rowakit-filter-select",
|
|
1431
|
+
value: filterValue?.op === "equals" ? String(filterValue.value ?? "") : "",
|
|
1055
1432
|
onChange: (e) => {
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
if (!from && !to) {
|
|
1433
|
+
const value = e.target.value;
|
|
1434
|
+
if (value === "") {
|
|
1059
1435
|
handleClearFilter(field);
|
|
1060
1436
|
} else {
|
|
1061
|
-
handleFilterChange(field, { op: "
|
|
1437
|
+
handleFilterChange(field, { op: "equals", value });
|
|
1062
1438
|
}
|
|
1063
|
-
}
|
|
1439
|
+
},
|
|
1440
|
+
children: [
|
|
1441
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "All" }),
|
|
1442
|
+
options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
|
|
1443
|
+
]
|
|
1064
1444
|
}
|
|
1065
|
-
),
|
|
1066
|
-
|
|
1067
|
-
|
|
1445
|
+
) }, column.id);
|
|
1446
|
+
}
|
|
1447
|
+
if (column.kind === "boolean") {
|
|
1448
|
+
return /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsxs(
|
|
1449
|
+
"select",
|
|
1068
1450
|
{
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
placeholder: "To",
|
|
1072
|
-
value: toValue,
|
|
1451
|
+
className: "rowakit-filter-select",
|
|
1452
|
+
value: filterValue?.op === "equals" && typeof filterValue.value === "boolean" ? String(filterValue.value) : "",
|
|
1073
1453
|
onChange: (e) => {
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
if (!from && !to) {
|
|
1454
|
+
const value = e.target.value;
|
|
1455
|
+
if (value === "") {
|
|
1077
1456
|
handleClearFilter(field);
|
|
1078
1457
|
} else {
|
|
1079
|
-
handleFilterChange(field, { op: "
|
|
1458
|
+
handleFilterChange(field, { op: "equals", value: value === "true" });
|
|
1080
1459
|
}
|
|
1081
|
-
}
|
|
1460
|
+
},
|
|
1461
|
+
children: [
|
|
1462
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "All" }),
|
|
1463
|
+
/* @__PURE__ */ jsx("option", { value: "true", children: "True" }),
|
|
1464
|
+
/* @__PURE__ */ jsx("option", { value: "false", children: "False" })
|
|
1465
|
+
]
|
|
1082
1466
|
}
|
|
1083
|
-
)
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
const toValue = filterValue?.op === "range" ? String(filterValue.value.to ?? "") : "";
|
|
1090
|
-
const showRangeUI = !filterValue || filterValue.op === "range";
|
|
1091
|
-
if (showRangeUI) {
|
|
1092
|
-
return /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsxs("div", { className: "rowakit-filter-number-range", children: [
|
|
1467
|
+
) }, column.id);
|
|
1468
|
+
}
|
|
1469
|
+
if (column.kind === "date") {
|
|
1470
|
+
const fromValue = filterValue?.op === "range" ? filterValue.value.from ?? "" : "";
|
|
1471
|
+
const toValue = filterValue?.op === "range" ? filterValue.value.to ?? "" : "";
|
|
1472
|
+
return /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsxs("div", { className: "rowakit-filter-date-range", children: [
|
|
1093
1473
|
/* @__PURE__ */ jsx(
|
|
1094
1474
|
"input",
|
|
1095
1475
|
{
|
|
1096
|
-
type: "
|
|
1476
|
+
type: "date",
|
|
1097
1477
|
className: "rowakit-filter-input",
|
|
1098
|
-
placeholder: "
|
|
1478
|
+
placeholder: "From",
|
|
1099
1479
|
value: fromValue,
|
|
1100
1480
|
onChange: (e) => {
|
|
1101
|
-
const from = e.target.value
|
|
1102
|
-
const to = toValue
|
|
1103
|
-
if (from
|
|
1481
|
+
const from = e.target.value || void 0;
|
|
1482
|
+
const to = toValue || void 0;
|
|
1483
|
+
if (!from && !to) {
|
|
1104
1484
|
handleClearFilter(field);
|
|
1105
1485
|
} else {
|
|
1106
1486
|
handleFilterChange(field, { op: "range", value: { from, to } });
|
|
@@ -1111,14 +1491,14 @@ function RowaKitTable({
|
|
|
1111
1491
|
/* @__PURE__ */ jsx(
|
|
1112
1492
|
"input",
|
|
1113
1493
|
{
|
|
1114
|
-
type: "
|
|
1494
|
+
type: "date",
|
|
1115
1495
|
className: "rowakit-filter-input",
|
|
1116
|
-
placeholder: "
|
|
1496
|
+
placeholder: "To",
|
|
1117
1497
|
value: toValue,
|
|
1118
1498
|
onChange: (e) => {
|
|
1119
|
-
const to = e.target.value
|
|
1120
|
-
const from = fromValue
|
|
1121
|
-
if (from
|
|
1499
|
+
const to = e.target.value || void 0;
|
|
1500
|
+
const from = fromValue || void 0;
|
|
1501
|
+
if (!from && !to) {
|
|
1122
1502
|
handleClearFilter(field);
|
|
1123
1503
|
} else {
|
|
1124
1504
|
handleFilterChange(field, { op: "range", value: { from, to } });
|
|
@@ -1128,39 +1508,85 @@ function RowaKitTable({
|
|
|
1128
1508
|
)
|
|
1129
1509
|
] }) }, column.id);
|
|
1130
1510
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1511
|
+
const isNumberColumn = column.kind === "number";
|
|
1512
|
+
if (isNumberColumn) {
|
|
1513
|
+
const fromValue = filterValue?.op === "range" ? String(filterValue.value.from ?? "") : filterValue?.op === "equals" && typeof filterValue.value === "number" ? String(filterValue.value) : "";
|
|
1514
|
+
const toValue = filterValue?.op === "range" ? String(filterValue.value.to ?? "") : "";
|
|
1515
|
+
const showRangeUI = !filterValue || filterValue.op === "range";
|
|
1516
|
+
if (showRangeUI) {
|
|
1517
|
+
return /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsxs("div", { className: "rowakit-filter-number-range", children: [
|
|
1518
|
+
/* @__PURE__ */ jsx(
|
|
1519
|
+
"input",
|
|
1520
|
+
{
|
|
1521
|
+
type: "number",
|
|
1522
|
+
className: "rowakit-filter-input",
|
|
1523
|
+
placeholder: "Min",
|
|
1524
|
+
value: fromValue,
|
|
1525
|
+
onChange: (e) => {
|
|
1526
|
+
const from = e.target.value ? Number(e.target.value) : void 0;
|
|
1527
|
+
const to = toValue ? Number(toValue) : void 0;
|
|
1528
|
+
if (from === void 0 && to === void 0) {
|
|
1529
|
+
handleClearFilter(field);
|
|
1530
|
+
} else {
|
|
1531
|
+
handleFilterChange(field, { op: "range", value: { from, to } });
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
),
|
|
1536
|
+
/* @__PURE__ */ jsx(
|
|
1537
|
+
"input",
|
|
1538
|
+
{
|
|
1539
|
+
type: "number",
|
|
1540
|
+
className: "rowakit-filter-input",
|
|
1541
|
+
placeholder: "Max",
|
|
1542
|
+
value: toValue,
|
|
1543
|
+
onChange: (e) => {
|
|
1544
|
+
const to = e.target.value ? Number(e.target.value) : void 0;
|
|
1545
|
+
const from = fromValue ? Number(fromValue) : void 0;
|
|
1546
|
+
if (from === void 0 && to === void 0) {
|
|
1547
|
+
handleClearFilter(field);
|
|
1548
|
+
} else {
|
|
1549
|
+
handleFilterChange(field, { op: "range", value: { from, to } });
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
)
|
|
1554
|
+
] }) }, column.id);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
return /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsx(
|
|
1558
|
+
"input",
|
|
1559
|
+
{
|
|
1560
|
+
type: isNumberColumn ? "number" : "text",
|
|
1561
|
+
className: "rowakit-filter-input",
|
|
1562
|
+
placeholder: `Filter ${getHeaderLabel(column)}...`,
|
|
1563
|
+
value: filterValue?.op === "contains" ? filterValue.value : filterValue?.op === "equals" && typeof filterValue.value === "string" ? filterValue.value : filterValue?.op === "equals" && typeof filterValue.value === "number" ? String(filterValue.value) : "",
|
|
1564
|
+
onChange: (e) => {
|
|
1565
|
+
const rawValue = e.target.value;
|
|
1566
|
+
if (rawValue === "") {
|
|
1148
1567
|
handleClearFilter(field);
|
|
1568
|
+
} else if (isNumberColumn) {
|
|
1569
|
+
const numValue = Number(rawValue);
|
|
1570
|
+
if (!isNaN(numValue)) {
|
|
1571
|
+
handleFilterChange(field, { op: "equals", value: numValue });
|
|
1572
|
+
} else {
|
|
1573
|
+
handleClearFilter(field);
|
|
1574
|
+
}
|
|
1575
|
+
} else {
|
|
1576
|
+
handleFilterChange(field, { op: "contains", value: rawValue });
|
|
1149
1577
|
}
|
|
1150
|
-
} else {
|
|
1151
|
-
handleFilterChange(field, { op: "contains", value: rawValue });
|
|
1152
1578
|
}
|
|
1153
1579
|
}
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1580
|
+
) }, column.id);
|
|
1581
|
+
})
|
|
1582
|
+
] })
|
|
1157
1583
|
] }),
|
|
1158
1584
|
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
1159
|
-
isLoading && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan:
|
|
1585
|
+
isLoading && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan: tableColumnCount, className: "rowakit-table-loading", children: [
|
|
1160
1586
|
/* @__PURE__ */ jsx("div", { className: "rowakit-table-loading-spinner" }),
|
|
1161
1587
|
/* @__PURE__ */ jsx("span", { children: "Loading..." })
|
|
1162
1588
|
] }) }),
|
|
1163
|
-
isError && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan:
|
|
1589
|
+
isError && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", { colSpan: tableColumnCount, className: "rowakit-table-error", children: [
|
|
1164
1590
|
/* @__PURE__ */ jsx("div", { className: "rowakit-table-error-message", children: dataState.error ?? "An error occurred" }),
|
|
1165
1591
|
/* @__PURE__ */ jsx(
|
|
1166
1592
|
"button",
|
|
@@ -1172,29 +1598,42 @@ function RowaKitTable({
|
|
|
1172
1598
|
}
|
|
1173
1599
|
)
|
|
1174
1600
|
] }) }),
|
|
1175
|
-
isEmpty && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan:
|
|
1601
|
+
isEmpty && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: tableColumnCount, className: "rowakit-table-empty", children: "No data" }) }),
|
|
1176
1602
|
dataState.state === "success" && dataState.items.map((row) => {
|
|
1177
1603
|
const key = getRowKey(row, rowKey);
|
|
1178
|
-
return /* @__PURE__ */
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
column.truncate ? "rowakit-cell-truncate" : ""
|
|
1182
|
-
].filter(Boolean).join(" ") || void 0;
|
|
1183
|
-
const actualWidth = columnWidths[column.id] ?? column.width;
|
|
1184
|
-
return /* @__PURE__ */ jsx(
|
|
1185
|
-
"td",
|
|
1604
|
+
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
1605
|
+
enableRowSelection && /* @__PURE__ */ jsx(
|
|
1606
|
+
RowSelectionCell,
|
|
1186
1607
|
{
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1608
|
+
rowKey: key,
|
|
1609
|
+
disabled: isLoading,
|
|
1610
|
+
checked: selectedKeys.includes(key),
|
|
1611
|
+
onChange: () => {
|
|
1612
|
+
setSelectedKeys((prev) => toggleSelectionKey(prev, key));
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
),
|
|
1616
|
+
columns.map((column) => {
|
|
1617
|
+
const cellClass = [
|
|
1618
|
+
column.kind === "number" ? "rowakit-cell-number" : "",
|
|
1619
|
+
column.truncate ? "rowakit-cell-truncate" : ""
|
|
1620
|
+
].filter(Boolean).join(" ") || void 0;
|
|
1621
|
+
const actualWidth = columnWidths[column.id] ?? column.width;
|
|
1622
|
+
return /* @__PURE__ */ jsx(
|
|
1623
|
+
"td",
|
|
1624
|
+
{
|
|
1625
|
+
"data-col-id": column.id,
|
|
1626
|
+
className: cellClass,
|
|
1627
|
+
style: {
|
|
1628
|
+
width: actualWidth != null ? `${actualWidth}px` : void 0,
|
|
1629
|
+
textAlign: column.align || (column.kind === "number" ? "right" : void 0)
|
|
1630
|
+
},
|
|
1631
|
+
children: renderCell(column, row, isLoading, setConfirmState)
|
|
1192
1632
|
},
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
}) }, key);
|
|
1633
|
+
column.id
|
|
1634
|
+
);
|
|
1635
|
+
})
|
|
1636
|
+
] }, key);
|
|
1198
1637
|
})
|
|
1199
1638
|
] })
|
|
1200
1639
|
] }),
|
|
@@ -1249,6 +1688,7 @@ function RowaKitTable({
|
|
|
1249
1688
|
confirmState && /* @__PURE__ */ jsx(
|
|
1250
1689
|
"div",
|
|
1251
1690
|
{
|
|
1691
|
+
ref: confirmModalRef,
|
|
1252
1692
|
className: "rowakit-modal-backdrop",
|
|
1253
1693
|
onClick: () => setConfirmState(null),
|
|
1254
1694
|
role: "dialog",
|
|
@@ -1286,13 +1726,51 @@ function RowaKitTable({
|
|
|
1286
1726
|
] })
|
|
1287
1727
|
] })
|
|
1288
1728
|
}
|
|
1729
|
+
),
|
|
1730
|
+
bulkConfirmState && /* @__PURE__ */ jsx(
|
|
1731
|
+
"div",
|
|
1732
|
+
{
|
|
1733
|
+
ref: bulkConfirmModalRef,
|
|
1734
|
+
className: "rowakit-modal-backdrop",
|
|
1735
|
+
onClick: () => setBulkConfirmState(null),
|
|
1736
|
+
role: "dialog",
|
|
1737
|
+
"aria-modal": "true",
|
|
1738
|
+
"aria-labelledby": "bulk-confirm-dialog-title",
|
|
1739
|
+
children: /* @__PURE__ */ jsxs("div", { className: "rowakit-modal", onClick: (e) => e.stopPropagation(), children: [
|
|
1740
|
+
/* @__PURE__ */ jsx("h2", { id: "bulk-confirm-dialog-title", className: "rowakit-modal-title", children: bulkConfirmState.action.confirm?.title ?? "Confirm Action" }),
|
|
1741
|
+
/* @__PURE__ */ jsx("p", { className: "rowakit-modal-content", children: bulkConfirmState.action.confirm?.description ?? "Are you sure you want to perform this action? This action cannot be undone." }),
|
|
1742
|
+
/* @__PURE__ */ jsxs("div", { className: "rowakit-modal-actions", children: [
|
|
1743
|
+
/* @__PURE__ */ jsx(
|
|
1744
|
+
"button",
|
|
1745
|
+
{
|
|
1746
|
+
onClick: () => setBulkConfirmState(null),
|
|
1747
|
+
className: "rowakit-button rowakit-button-secondary",
|
|
1748
|
+
type: "button",
|
|
1749
|
+
children: "Cancel"
|
|
1750
|
+
}
|
|
1751
|
+
),
|
|
1752
|
+
/* @__PURE__ */ jsx(
|
|
1753
|
+
"button",
|
|
1754
|
+
{
|
|
1755
|
+
onClick: () => {
|
|
1756
|
+
bulkConfirmState.action.onClick(bulkConfirmState.selectedKeys);
|
|
1757
|
+
setBulkConfirmState(null);
|
|
1758
|
+
},
|
|
1759
|
+
className: "rowakit-button rowakit-button-danger",
|
|
1760
|
+
type: "button",
|
|
1761
|
+
children: "Confirm"
|
|
1762
|
+
}
|
|
1763
|
+
)
|
|
1764
|
+
] })
|
|
1765
|
+
] })
|
|
1766
|
+
}
|
|
1289
1767
|
)
|
|
1290
1768
|
] });
|
|
1291
1769
|
}
|
|
1292
1770
|
var SmartTable = RowaKitTable;
|
|
1293
1771
|
|
|
1294
1772
|
// src/index.ts
|
|
1295
|
-
var VERSION = "0.
|
|
1773
|
+
var VERSION = "0.5.0" ;
|
|
1296
1774
|
|
|
1297
1775
|
export { RowaKitTable, SmartTable, VERSION, col };
|
|
1298
1776
|
//# sourceMappingURL=index.js.map
|