@prairielearn/ui 1.1.2 → 1.3.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/CHANGELOG.md +20 -0
- package/dist/components/CategoricalColumnFilter.d.ts.map +1 -1
- package/dist/components/CategoricalColumnFilter.js +13 -5
- package/dist/components/CategoricalColumnFilter.js.map +1 -1
- package/dist/components/ColumnManager.d.ts +2 -1
- package/dist/components/ColumnManager.d.ts.map +1 -1
- package/dist/components/ColumnManager.js +13 -28
- package/dist/components/ColumnManager.js.map +1 -1
- package/dist/components/MultiSelectColumnFilter.d.ts +25 -0
- package/dist/components/MultiSelectColumnFilter.d.ts.map +1 -0
- package/dist/components/MultiSelectColumnFilter.js +41 -0
- package/dist/components/MultiSelectColumnFilter.js.map +1 -0
- package/dist/components/NumericInputColumnFilter.d.ts +42 -0
- package/dist/components/NumericInputColumnFilter.d.ts.map +1 -0
- package/dist/components/NumericInputColumnFilter.js +79 -0
- package/dist/components/NumericInputColumnFilter.js.map +1 -0
- package/dist/components/TanstackTable.css +49 -0
- package/dist/components/TanstackTable.d.ts +8 -1
- package/dist/components/TanstackTable.d.ts.map +1 -1
- package/dist/components/TanstackTable.js +78 -46
- package/dist/components/TanstackTable.js.map +1 -1
- package/dist/components/TanstackTableDownloadButton.d.ts.map +1 -1
- package/dist/components/TanstackTableDownloadButton.js +3 -1
- package/dist/components/TanstackTableDownloadButton.js.map +1 -1
- package/dist/components/useShiftClickCheckbox.d.ts +26 -0
- package/dist/components/useShiftClickCheckbox.d.ts.map +1 -0
- package/dist/components/useShiftClickCheckbox.js +59 -0
- package/dist/components/useShiftClickCheckbox.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/src/components/CategoricalColumnFilter.tsx +57 -27
- package/src/components/ColumnManager.tsx +32 -57
- package/src/components/MultiSelectColumnFilter.tsx +103 -0
- package/src/components/NumericInputColumnFilter.test.ts +102 -0
- package/src/components/NumericInputColumnFilter.tsx +153 -0
- package/src/components/TanstackTable.css +49 -0
- package/src/components/TanstackTable.tsx +193 -116
- package/src/components/TanstackTableDownloadButton.tsx +27 -1
- package/src/components/useShiftClickCheckbox.tsx +67 -0
- package/src/index.ts +12 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TanstackTable.d.ts","sourceRoot":"","sources":["../../src/components/TanstackTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAsB,KAAK,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"TanstackTable.d.ts","sourceRoot":"","sources":["../../src/components/TanstackTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAsB,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAK9C,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,kCAAkC,CAAC;AA0F1C,UAAU,kBAAkB,CAAC,YAAY;IACvC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;KAAE,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAC7B,UAAU,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;CAC1B;AAID;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,EAC1C,KAAK,EACL,KAAK,EACL,OAA4B,EAC5B,SAAc,EACd,cAAsC,EACtC,UAA8B,GAC/B,EAAE,kBAAkB,CAAC,YAAY,CAAC,eAuYlC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,EAC9C,KAAK,EACL,KAAK,EACL,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,qBAA4B,GAC7B,EAAE;IACD,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACnC,YAAY,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAClC,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IACvE,qBAAqB,CAAC,EAAE,IAAI,CAAC,gCAAgC,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9F,eAmFA;AAED,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,MAAM,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B,eAOA"}
|
|
@@ -3,6 +3,8 @@ import { flexRender } from '@tanstack/react-table';
|
|
|
3
3
|
import { notUndefined, useVirtualizer } from '@tanstack/react-virtual';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
5
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
6
|
+
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
|
|
7
|
+
import Tooltip from 'react-bootstrap/Tooltip';
|
|
6
8
|
import { ColumnManager } from './ColumnManager.js';
|
|
7
9
|
import { TanstackTableDownloadButton, } from './TanstackTableDownloadButton.js';
|
|
8
10
|
function SortIcon({ sortMethod }) {
|
|
@@ -140,6 +142,42 @@ export function TanstackTable({ table, title, filters = DEFAULT_FILTER_MAP, rowH
|
|
|
140
142
|
useEffect(() => {
|
|
141
143
|
document.body.classList.toggle('no-user-select', isTableResizing);
|
|
142
144
|
}, [isTableResizing]);
|
|
145
|
+
// Dismiss popovers when their triggering element scrolls out of view
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
const handleScroll = () => {
|
|
148
|
+
const scrollElement = parentRef.current;
|
|
149
|
+
if (!scrollElement)
|
|
150
|
+
return;
|
|
151
|
+
// Find and check all open popovers
|
|
152
|
+
const popovers = document.querySelectorAll('.popover.show');
|
|
153
|
+
popovers.forEach((popover) => {
|
|
154
|
+
// Find the trigger element for this popover
|
|
155
|
+
const triggerElement = document.querySelector(`[aria-describedby="${popover.id}"]`);
|
|
156
|
+
if (!triggerElement)
|
|
157
|
+
return;
|
|
158
|
+
// Check if the trigger element is still visible in the scroll container
|
|
159
|
+
const scrollRect = scrollElement.getBoundingClientRect();
|
|
160
|
+
const triggerRect = triggerElement.getBoundingClientRect();
|
|
161
|
+
// Check if trigger is outside the visible scroll area
|
|
162
|
+
const isOutOfView = triggerRect.bottom < scrollRect.top ||
|
|
163
|
+
triggerRect.top > scrollRect.bottom ||
|
|
164
|
+
triggerRect.right < scrollRect.left ||
|
|
165
|
+
triggerRect.left > scrollRect.right;
|
|
166
|
+
if (isOutOfView) {
|
|
167
|
+
// Use Bootstrap's Popover API to properly hide it
|
|
168
|
+
const popoverInstance = window.bootstrap?.Popover?.getInstance(triggerElement);
|
|
169
|
+
if (popoverInstance) {
|
|
170
|
+
popoverInstance.hide();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
const scrollElement = parentRef.current;
|
|
176
|
+
if (scrollElement) {
|
|
177
|
+
scrollElement.addEventListener('scroll', handleScroll);
|
|
178
|
+
return () => scrollElement.removeEventListener('scroll', handleScroll);
|
|
179
|
+
}
|
|
180
|
+
}, []);
|
|
143
181
|
// Helper function to get aria-sort value
|
|
144
182
|
const getAriaSort = (sortDirection) => {
|
|
145
183
|
switch (sortDirection) {
|
|
@@ -164,7 +202,7 @@ export function TanstackTable({ table, title, filters = DEFAULT_FILTER_MAP, rowH
|
|
|
164
202
|
}, children: _jsx("div", { ref: tableRef, style: {
|
|
165
203
|
position: 'relative',
|
|
166
204
|
width: `max(${table.getTotalSize()}px, 100%)`,
|
|
167
|
-
}, children: _jsxs("table", { class: "table table-hover mb-0
|
|
205
|
+
}, children: _jsxs("table", { class: "table table-hover mb-0", style: { tableLayout: 'fixed' }, "aria-label": title, role: "grid", children: [_jsx("thead", { children: headerGroups.map((headerGroup) => (_jsx("tr", { children: headerGroup.headers.map((header, index) => {
|
|
168
206
|
const isPinned = header.column.getIsPinned();
|
|
169
207
|
const sortDirection = header.column.getIsSorted();
|
|
170
208
|
const canSort = header.column.getCanSort();
|
|
@@ -182,7 +220,9 @@ export function TanstackTable({ table, title, filters = DEFAULT_FILTER_MAP, rowH
|
|
|
182
220
|
left: isPinned === 'left' ? header.getStart() : undefined,
|
|
183
221
|
boxShadow: 'inset 0 calc(-1 * var(--bs-border-width)) 0 0 rgba(0, 0, 0, 1), inset 0 var(--bs-border-width) 0 0 var(--bs-border-color)',
|
|
184
222
|
};
|
|
185
|
-
return (_jsxs("th", { class: clsx(isPinned === 'left' && 'bg-light'), style: style, "aria-sort": canSort ? getAriaSort(sortDirection) : undefined, role: "columnheader", children: [_jsxs("div", { class:
|
|
223
|
+
return (_jsxs("th", { class: clsx(isPinned === 'left' && 'bg-light'), style: style, "aria-sort": canSort ? getAriaSort(sortDirection) : undefined, role: "columnheader", children: [_jsxs("div", { class: clsx('d-flex align-items-center', canSort || canFilter
|
|
224
|
+
? 'justify-content-between'
|
|
225
|
+
: 'justify-content-center'), children: [_jsxs("button", { class: clsx('text-nowrap text-start', canSort || canFilter ? 'flex-grow-1' : ''), style: {
|
|
186
226
|
cursor: canSort ? 'pointer' : 'default',
|
|
187
227
|
overflow: 'hidden',
|
|
188
228
|
textOverflow: 'ellipsis',
|
|
@@ -200,42 +240,43 @@ export function TanstackTable({ table, title, filters = DEFAULT_FILTER_MAP, rowH
|
|
|
200
240
|
}
|
|
201
241
|
: undefined, children: [header.isPlaceholder
|
|
202
242
|
? null
|
|
203
|
-
: flexRender(header.column.columnDef.header, header.getContext()), canSort && (
|
|
243
|
+
: flexRender(header.column.columnDef.header, header.getContext()), canSort && (_jsxs("span", { class: "visually-hidden", children: [", ", getAriaSort(sortDirection), ", click to sort"] }))] }), (canSort || canFilter) && (_jsxs("div", { class: "d-flex align-items-center", children: [canSort && (_jsx("button", { type: "button", class: "btn btn-link text-muted p-0", "aria-label": `Sort ${columnName.toLowerCase()}`, title: `Sort ${columnName.toLowerCase()}`, onClick: header.column.getToggleSortingHandler(), children: _jsx(SortIcon, { sortMethod: sortDirection || false }) })), canFilter && filters[header.column.id]?.({ header })] }))] }), tableRect?.width &&
|
|
204
244
|
tableRect.width > table.getTotalSize() &&
|
|
205
245
|
index === headerGroup.headers.length - 1 ? null : (_jsx(ResizeHandle, { header: header, setColumnSizing: table.setColumnSizing }))] }, header.id));
|
|
206
246
|
}) }, headerGroup.id))) }), _jsxs("tbody", { children: [before > 0 && (_jsx("tr", { tabIndex: -1, children: _jsx("td", { colSpan: headerGroups[0].headers.length, style: { height: before } }) })), virtualRows.map((virtualRow) => {
|
|
207
247
|
const row = rows[virtualRow.index];
|
|
208
248
|
const visibleCells = getVisibleCells(row);
|
|
209
249
|
const rowIdx = virtualRow.index;
|
|
210
|
-
return (_jsx("tr", { style: { height: rowHeight }, children: visibleCells.map((cell, colIdx) =>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
: undefined,
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
250
|
+
return (_jsx("tr", { style: { height: rowHeight }, children: visibleCells.map((cell, colIdx) => {
|
|
251
|
+
const canSort = cell.column.getCanSort();
|
|
252
|
+
const canFilter = cell.column.getCanFilter();
|
|
253
|
+
return (_jsx("td", {
|
|
254
|
+
// You can tab to the most-recently focused cell.
|
|
255
|
+
tabIndex: focusedCell.row === rowIdx && focusedCell.col === colIdx ? 0 : -1, "data-grid-cell-row": rowIdx, "data-grid-cell-col": colIdx, class: clsx(!canSort && !canFilter && 'text-center'), style: {
|
|
256
|
+
width: cell.column.id === lastColumnId
|
|
257
|
+
? `max(100%, ${cell.column.getSize()}px)`
|
|
258
|
+
: cell.column.getSize(),
|
|
259
|
+
position: cell.column.getIsPinned() === 'left' ? 'sticky' : undefined,
|
|
260
|
+
left: cell.column.getIsPinned() === 'left'
|
|
261
|
+
? cell.column.getStart()
|
|
262
|
+
: undefined,
|
|
263
|
+
whiteSpace: 'nowrap',
|
|
264
|
+
overflow: 'hidden',
|
|
265
|
+
textOverflow: 'ellipsis',
|
|
266
|
+
}, onFocus: () => setFocusedCell({ row: rowIdx, col: colIdx }), onKeyDown: (e) => handleGridKeyDown(e, rowIdx, colIdx), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
|
|
267
|
+
}) }, row.id));
|
|
268
|
+
}), after > 0 && (_jsx("tr", { tabIndex: -1, children: _jsx("td", { colSpan: headerGroups[0].headers.length, style: { height: after } }) }))] })] }) }) }), table.getVisibleLeafColumns().length === 0 || displayedCount === 0 ? (_jsx("div", { children: _jsx("div", { class: "d-flex flex-column justify-content-center align-items-center p-4", style: {
|
|
225
269
|
position: 'absolute',
|
|
226
270
|
top: 0,
|
|
227
271
|
left: 0,
|
|
228
272
|
right: 0,
|
|
229
273
|
bottom: 0,
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
bottom: 0,
|
|
237
|
-
background: 'var(--bs-body-bg)',
|
|
238
|
-
}, role: "status", "aria-live": "polite", children: totalCount > 0 ? noResultsState : emptyState }))] }));
|
|
274
|
+
// Allow pointer events (e.g. scrolling) to reach the underlying table.
|
|
275
|
+
pointerEvents: 'none',
|
|
276
|
+
}, role: "status", "aria-live": "polite", children: _jsx("div", { class: "col-lg-6", style: {
|
|
277
|
+
// Allow selecting and interacting with the empty state content.
|
|
278
|
+
pointerEvents: 'auto',
|
|
279
|
+
}, children: table.getVisibleLeafColumns().length === 0 ? (_jsx(TanstackTableEmptyState, { iconName: "bi-eye-slash", children: "No columns selected. Use the View menu to show columns." })) : displayedCount === 0 ? (totalCount > 0 ? (noResultsState) : (emptyState)) : null }) }) })) : null] }));
|
|
239
280
|
}
|
|
240
281
|
/**
|
|
241
282
|
* A generic component that wraps the TanstackTable component in a card.
|
|
@@ -243,6 +284,7 @@ export function TanstackTable({ table, title, filters = DEFAULT_FILTER_MAP, rowH
|
|
|
243
284
|
* @param params.table - The table model
|
|
244
285
|
* @param params.title - The title of the card
|
|
245
286
|
* @param params.headerButtons - The buttons to display in the header
|
|
287
|
+
* @param params.columnManagerButtons - The buttons to display next to the column manager (View button)
|
|
246
288
|
* @param params.globalFilter - State management for the global filter
|
|
247
289
|
* @param params.globalFilter.value
|
|
248
290
|
* @param params.globalFilter.setValue
|
|
@@ -250,21 +292,8 @@ export function TanstackTable({ table, title, filters = DEFAULT_FILTER_MAP, rowH
|
|
|
250
292
|
* @param params.tableOptions - Specific options for the table. See {@link TanstackTableProps} for more details.
|
|
251
293
|
* @param params.downloadButtonOptions - Specific options for the download button. See {@link TanstackTableDownloadButtonProps} for more details.
|
|
252
294
|
*/
|
|
253
|
-
export function TanstackTableCard({ table, title, headerButtons, globalFilter, tableOptions, downloadButtonOptions = null, }) {
|
|
295
|
+
export function TanstackTableCard({ table, title, headerButtons, columnManagerButtons, globalFilter, tableOptions, downloadButtonOptions = null, }) {
|
|
254
296
|
const searchInputRef = useRef(null);
|
|
255
|
-
// Track screen size for aria-hidden
|
|
256
|
-
const mediaQuery = typeof window !== 'undefined' ? window.matchMedia('(min-width: 768px)') : null;
|
|
257
|
-
const [isMediumOrLarger, setIsMediumOrLarger] = useState(false);
|
|
258
|
-
useEffect(() => {
|
|
259
|
-
// TODO: This is a workaround to avoid a hydration mismatch.
|
|
260
|
-
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
|
|
261
|
-
setIsMediumOrLarger(mediaQuery?.matches ?? true);
|
|
262
|
-
}, [mediaQuery]);
|
|
263
|
-
useEffect(() => {
|
|
264
|
-
const handler = (e) => setIsMediumOrLarger(e.matches);
|
|
265
|
-
mediaQuery?.addEventListener('change', handler);
|
|
266
|
-
return () => mediaQuery?.removeEventListener('change', handler);
|
|
267
|
-
}, [mediaQuery]);
|
|
268
297
|
// Focus the search input when Ctrl+F is pressed
|
|
269
298
|
useEffect(() => {
|
|
270
299
|
function onKeyDown(event) {
|
|
@@ -280,10 +309,13 @@ export function TanstackTableCard({ table, title, headerButtons, globalFilter, t
|
|
|
280
309
|
}, []);
|
|
281
310
|
const displayedCount = table.getRowModel().rows.length;
|
|
282
311
|
const totalCount = table.getCoreRowModel().rows.length;
|
|
283
|
-
return (_jsxs("div", { class: "card d-flex flex-column h-100", children: [_jsx("div", { class: "card-header bg-primary text-white", children: _jsxs("div", { class: "d-flex align-items-center justify-content-between gap-2", children: [_jsx("div", { children: title }), _jsxs("div", { class: "d-flex gap-2", children: [headerButtons, downloadButtonOptions && (_jsx(TanstackTableDownloadButton, { table: table, ...downloadButtonOptions }))] })] }) }), _jsxs("div", { class: "card-body d-flex flex-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
312
|
+
return (_jsxs("div", { class: "card d-flex flex-column h-100", children: [_jsx("div", { class: "card-header bg-primary text-white", children: _jsxs("div", { class: "d-flex align-items-center justify-content-between gap-2", children: [_jsx("div", { children: title }), _jsxs("div", { class: "d-flex gap-2", children: [headerButtons, downloadButtonOptions && (_jsx(TanstackTableDownloadButton, { table: table, ...downloadButtonOptions }))] })] }) }), _jsxs("div", { class: "card-body d-flex flex-row flex-wrap flex-grow-0 align-items-center gap-2", children: [_jsxs("div", { class: "flex-grow-1 flex-lg-grow-0 col-xl-6 col-lg-7 d-flex flex-row gap-2", children: [_jsxs("div", { class: "position-relative flex-grow-1", children: [_jsx("input", { ref: searchInputRef, type: "text", class: "form-control tanstack-table-search-input tanstack-table-focusable-shadow", "aria-label": globalFilter.placeholder, placeholder: globalFilter.placeholder, value: globalFilter.value, autoComplete: "off", onInput: (e) => {
|
|
313
|
+
if (!(e.target instanceof HTMLInputElement))
|
|
314
|
+
return;
|
|
315
|
+
globalFilter.setValue(e.target.value);
|
|
316
|
+
} }), globalFilter.value && (_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Clear search" }), children: _jsx("button", { type: "button", class: "btn btn-link tanstack-table-clear-search", "aria-label": "Clear search", onClick: () => globalFilter.setValue(''), children: _jsx("i", { class: "bi bi-x-circle-fill", "aria-hidden": "true" }) }) }))] }), _jsxs("div", { class: "d-none d-md-block", children: [_jsx(ColumnManager, { table: table, id: "column-manager-button-wide" }), columnManagerButtons] })] }), _jsxs("div", { class: "d-block d-md-none", children: [_jsx(ColumnManager, { table: table, id: "column-manager-button-narrow" }), columnManagerButtons] }), _jsx("div", { class: "flex-lg-grow-1 d-flex flex-row justify-content-end", children: _jsxs("div", { class: "text-muted text-nowrap", children: ["Showing ", displayedCount, " of ", totalCount, " ", title.toLowerCase()] }) })] }), _jsx("div", { class: "flex-grow-1", children: _jsx(TanstackTable, { table: table, title: title, ...tableOptions }) })] }));
|
|
317
|
+
}
|
|
318
|
+
export function TanstackTableEmptyState({ iconName, children, }) {
|
|
319
|
+
return (_jsxs("div", { class: "d-flex flex-column justify-content-center align-items-center text-muted", children: [_jsx("i", { class: clsx('bi', iconName, 'display-4 mb-2'), "aria-hidden": "true" }), _jsx("div", { children: children })] }));
|
|
288
320
|
}
|
|
289
321
|
//# sourceMappingURL=TanstackTable.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TanstackTable.js","sourceRoot":"","sources":["../../src/components/TanstackTable.tsx"],"names":[],"mappings":"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","sourcesContent":["import { flexRender } from '@tanstack/react-table';\nimport { notUndefined, useVirtualizer } from '@tanstack/react-virtual';\nimport type { Header, Row, SortDirection, Table } from '@tanstack/table-core';\nimport clsx from 'clsx';\nimport { useEffect, useRef, useState } from 'preact/hooks';\nimport type { JSX } from 'preact/jsx-runtime';\n\nimport { ColumnManager } from './ColumnManager.js';\nimport {\n TanstackTableDownloadButton,\n type TanstackTableDownloadButtonProps,\n} from './TanstackTableDownloadButton.js';\n\nfunction SortIcon({ sortMethod }: { sortMethod: false | SortDirection }) {\n if (sortMethod === 'asc') {\n return <i class=\"bi bi-sort-up-alt\" aria-hidden=\"true\" />;\n } else if (sortMethod === 'desc') {\n return <i class=\"bi bi-sort-down\" aria-hidden=\"true\" />;\n } else {\n return <i class=\"bi bi-arrow-down-up opacity-75 text-muted\" aria-hidden=\"true\" />;\n }\n}\n\nfunction ResizeHandle<RowDataModel>({\n header,\n setColumnSizing,\n}: {\n header: Header<RowDataModel, unknown>;\n setColumnSizing: Table<RowDataModel>['setColumnSizing'];\n}) {\n const minSize = header.column.columnDef.minSize ?? 0;\n const maxSize = header.column.columnDef.maxSize ?? 0;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n e.preventDefault();\n const currentSize = header.getSize();\n const increment = e.shiftKey ? 20 : 5; // Larger increment with Shift key\n const newSize =\n e.key === 'ArrowLeft'\n ? Math.max(minSize, currentSize - increment)\n : Math.min(maxSize, currentSize + increment);\n\n setColumnSizing((prevSizing) => ({\n ...prevSizing,\n [header.column.id]: newSize,\n }));\n } else if (e.key === 'Home') {\n e.preventDefault();\n header.column.resetSize();\n }\n };\n\n const columnName =\n typeof header.column.columnDef.header === 'string'\n ? header.column.columnDef.header\n : header.column.id;\n\n return (\n <div class=\"py-1 h-100\" style={{ position: 'absolute', right: 0, top: 0, width: '4px' }}>\n {/* separator role is focusable, so these jsx-a11y-x rules are false positives.\n https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/separator_role#focusable_separator\n */}\n {/* eslint-disable-next-line jsx-a11y-x/no-noninteractive-element-interactions */}\n <div\n role=\"separator\"\n aria-label={`Resize '${columnName}' column`}\n aria-valuetext={`${header.getSize()}px`}\n aria-orientation=\"vertical\"\n aria-valuemin={minSize}\n aria-valuemax={maxSize}\n aria-valuenow={header.getSize()}\n // eslint-disable-next-line jsx-a11y-x/no-noninteractive-tabindex\n tabIndex={0}\n class=\"h-100\"\n style={{\n background: header.column.getIsResizing() ? 'var(--bs-primary)' : 'var(--bs-gray-400)',\n cursor: 'col-resize',\n transition: 'background-color 0.2s',\n }}\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n onKeyDown={handleKeyDown}\n />\n </div>\n );\n}\n\nconst DefaultNoResultsState = (\n <>\n <i class=\"bi bi-search display-4 mb-2\" aria-hidden=\"true\" />\n <p class=\"mb-0\">No results found matching your search criteria.</p>\n </>\n);\n\nconst DefaultEmptyState = (\n <>\n <i class=\"bi bi-eye-slash display-4 mb-2\" aria-hidden=\"true\" />\n <p class=\"mb-0\">No results found.</p>\n </>\n);\n\ninterface TanstackTableProps<RowDataModel> {\n table: Table<RowDataModel>;\n title: string;\n filters?: Record<string, (props: { header: Header<RowDataModel, unknown> }) => JSX.Element>;\n rowHeight?: number;\n noResultsState?: JSX.Element;\n emptyState?: JSX.Element;\n}\n\nconst DEFAULT_FILTER_MAP = {};\n\n/**\n * A generic component that renders a full-width, resizeable Tanstack Table.\n * @param params\n * @param params.table - The table model\n * @param params.title - The title of the table\n * @param params.filters - The filters for the table\n * @param params.rowHeight - The height of the rows in the table\n * @param params.noResultsState - The no results state for the table\n * @param params.emptyState - The empty state for the table\n */\nexport function TanstackTable<RowDataModel>({\n table,\n title,\n filters = DEFAULT_FILTER_MAP,\n rowHeight = 42,\n noResultsState = DefaultNoResultsState,\n emptyState = DefaultEmptyState,\n}: TanstackTableProps<RowDataModel>) {\n const parentRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLDivElement>(null);\n const rows = [...table.getTopRows(), ...table.getCenterRows()];\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => parentRef.current,\n estimateSize: () => rowHeight,\n overscan: 10,\n });\n\n // Track focused cell for grid navigation\n const [focusedCell, setFocusedCell] = useState<{ row: number; col: number }>({ row: 0, col: 0 });\n\n const getVisibleCells = (row: Row<RowDataModel>) => [\n ...row.getLeftVisibleCells(),\n ...row.getCenterVisibleCells(),\n ];\n\n const handleGridKeyDown = (e: KeyboardEvent, rowIdx: number, colIdx: number) => {\n const rowLength = getVisibleCells(rows[rowIdx]).length;\n const adjacentCells: Record<KeyboardEvent['key'], { row: number; col: number }> = {\n ArrowDown: {\n row: Math.min(rows.length - 1, rowIdx + 1),\n col: colIdx,\n },\n ArrowUp: {\n row: Math.max(0, rowIdx - 1),\n col: colIdx,\n },\n ArrowRight: {\n row: rowIdx,\n col: Math.min(rowLength - 1, colIdx + 1),\n },\n ArrowLeft: {\n row: rowIdx,\n col: Math.max(0, colIdx - 1),\n },\n };\n\n const next = adjacentCells[e.key];\n\n if (!next) {\n return;\n }\n\n setFocusedCell({ row: next.row, col: next.col });\n // If we are on the leftmost column, we should allow left scrolling.\n if (colIdx === 0 && e.key === 'ArrowLeft') {\n return;\n }\n\n // If we are on the top row, we should allow up scrolling.\n if (rowIdx === 0 && e.key === 'ArrowUp') {\n return;\n }\n\n // If we are on the rightmost column, we should allow right scrolling.\n if (colIdx === rowLength - 1 && e.key === 'ArrowRight') {\n return;\n }\n\n e.preventDefault();\n };\n\n useEffect(() => {\n const selector = `[data-grid-cell-row=\"${focusedCell.row}\"][data-grid-cell-col=\"${focusedCell.col}\"]`;\n const cell = tableRef.current?.querySelector(selector) as HTMLElement | null;\n if (!cell) return;\n\n // eslint-disable-next-line react-you-might-not-need-an-effect/no-chain-state-updates\n cell.focus();\n }, [focusedCell]);\n\n const virtualRows = rowVirtualizer.getVirtualItems();\n const [before, after] =\n virtualRows.length > 0\n ? [\n notUndefined(virtualRows[0]).start - rowVirtualizer.options.scrollMargin,\n rowVirtualizer.getTotalSize() - notUndefined(virtualRows.at(-1)).end,\n ]\n : [0, 0];\n const headerGroups = table.getHeaderGroups();\n const isTableResizing = headerGroups.some((headerGroup) =>\n headerGroup.headers.some((header) => header.column.getIsResizing()),\n );\n const lastColumnId = table.getAllLeafColumns()[table.getAllLeafColumns().length - 1].id;\n\n const tableRect = tableRef.current?.getBoundingClientRect();\n\n // We toggle this here instead of in the parent since this component logically manages all UI for the table.\n // eslint-disable-next-line react-you-might-not-need-an-effect/no-manage-parent\n useEffect(() => {\n document.body.classList.toggle('no-user-select', isTableResizing);\n }, [isTableResizing]);\n\n // Helper function to get aria-sort value\n const getAriaSort = (sortDirection: false | SortDirection) => {\n switch (sortDirection) {\n case 'asc':\n return 'ascending';\n case 'desc':\n return 'descending';\n default:\n return 'none';\n }\n };\n\n const displayedCount = table.getRowModel().rows.length;\n const totalCount = table.getCoreRowModel().rows.length;\n\n return (\n <div style={{ position: 'relative' }} class=\"d-flex flex-column h-100\">\n <div\n ref={parentRef}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n overflow: 'auto',\n overflowAnchor: 'none',\n }}\n >\n <div\n ref={tableRef}\n style={{\n position: 'relative',\n width: `max(${table.getTotalSize()}px, 100%)`,\n }}\n >\n <table\n class=\"table table-hover mb-0 border border-top-0\"\n style={{ tableLayout: 'fixed' }}\n aria-label={title}\n role=\"grid\"\n >\n <thead>\n {headerGroups.map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header, index) => {\n const isPinned = header.column.getIsPinned();\n const sortDirection = header.column.getIsSorted();\n const canSort = header.column.getCanSort();\n const canFilter = header.column.getCanFilter();\n const columnName =\n typeof header.column.columnDef.header === 'string'\n ? header.column.columnDef.header\n : header.column.id;\n\n const style: JSX.CSSProperties = {\n width:\n header.column.id === lastColumnId\n ? `max(100%, ${header.getSize()}px)`\n : header.getSize(),\n position: 'sticky',\n top: 0,\n zIndex: isPinned === 'left' ? 2 : 1,\n left: isPinned === 'left' ? header.getStart() : undefined,\n boxShadow:\n 'inset 0 calc(-1 * var(--bs-border-width)) 0 0 rgba(0, 0, 0, 1), inset 0 var(--bs-border-width) 0 0 var(--bs-border-color)',\n };\n\n return (\n <th\n key={header.id}\n class={clsx(isPinned === 'left' && 'bg-light')}\n style={style}\n aria-sort={canSort ? getAriaSort(sortDirection) : undefined}\n role=\"columnheader\"\n >\n <div class=\"d-flex align-items-center justify-content-between gap-2\">\n <button\n class=\"text-nowrap flex-grow-1 text-start\"\n style={{\n cursor: canSort ? 'pointer' : 'default',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n background: 'transparent',\n border: 'none',\n }}\n type=\"button\"\n aria-label={\n canSort\n ? `'${columnName}' column, current sort is ${getAriaSort(sortDirection)}`\n : undefined\n }\n onClick={canSort ? header.column.getToggleSortingHandler() : undefined}\n onKeyDown={\n canSort\n ? (e) => {\n const handleSort = header.column.getToggleSortingHandler();\n if (e.key === 'Enter' && handleSort) {\n e.preventDefault();\n handleSort(e);\n }\n }\n : undefined\n }\n >\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n {canSort && (\n <span class=\"ms-2\" aria-hidden=\"true\">\n <SortIcon sortMethod={sortDirection || false} />\n </span>\n )}\n {canSort && (\n <span class=\"visually-hidden\">\n , {getAriaSort(sortDirection)}, click to sort\n </span>\n )}\n </button>\n\n {canFilter && filters[header.column.id]?.({ header })}\n </div>\n {tableRect?.width &&\n tableRect.width > table.getTotalSize() &&\n index === headerGroup.headers.length - 1 ? null : (\n <ResizeHandle header={header} setColumnSizing={table.setColumnSizing} />\n )}\n </th>\n );\n })}\n </tr>\n ))}\n </thead>\n <tbody>\n {before > 0 && (\n <tr tabIndex={-1}>\n <td colSpan={headerGroups[0].headers.length} style={{ height: before }} />\n </tr>\n )}\n {virtualRows.map((virtualRow) => {\n const row = rows[virtualRow.index];\n const visibleCells = getVisibleCells(row);\n const rowIdx = virtualRow.index;\n\n return (\n <tr key={row.id} style={{ height: rowHeight }}>\n {visibleCells.map((cell, colIdx) => (\n <td\n key={cell.id}\n // You can tab to the most-recently focused cell.\n tabIndex={focusedCell.row === rowIdx && focusedCell.col === colIdx ? 0 : -1}\n // We store this so you can navigate around the grid.\n data-grid-cell-row={rowIdx}\n data-grid-cell-col={colIdx}\n style={{\n width:\n cell.column.id === lastColumnId\n ? `max(100%, ${cell.column.getSize()}px)`\n : cell.column.getSize(),\n position: cell.column.getIsPinned() === 'left' ? 'sticky' : undefined,\n left:\n cell.column.getIsPinned() === 'left'\n ? cell.column.getStart()\n : undefined,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n onFocus={() => setFocusedCell({ row: rowIdx, col: colIdx })}\n onKeyDown={(e) => handleGridKeyDown(e, rowIdx, colIdx)}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n ))}\n </tr>\n );\n })}\n {after > 0 && (\n <tr tabIndex={-1}>\n <td colSpan={headerGroups[0].headers.length} style={{ height: after }} />\n </tr>\n )}\n </tbody>\n </table>\n </div>\n </div>\n\n {table.getVisibleLeafColumns().length === 0 && (\n <div>\n <div\n class=\"d-flex flex-column justify-content-center align-items-center text-muted py-4\"\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background: 'var(--bs-body-bg)',\n }}\n role=\"status\"\n aria-live=\"polite\"\n >\n <i class=\"bi bi-eye-slash display-4 mb-2\" aria-hidden=\"true\" />\n <p class=\"mb-0\">No columns selected. Use the View menu to show columns.</p>\n </div>\n </div>\n )}\n {displayedCount === 0 && (\n <div\n class=\"d-flex flex-column justify-content-center align-items-center text-muted py-4\"\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background: 'var(--bs-body-bg)',\n }}\n role=\"status\"\n aria-live=\"polite\"\n >\n {totalCount > 0 ? noResultsState : emptyState}\n </div>\n )}\n </div>\n );\n}\n\n/**\n * A generic component that wraps the TanstackTable component in a card.\n * @param params\n * @param params.table - The table model\n * @param params.title - The title of the card\n * @param params.headerButtons - The buttons to display in the header\n * @param params.globalFilter - State management for the global filter\n * @param params.globalFilter.value\n * @param params.globalFilter.setValue\n * @param params.globalFilter.placeholder\n * @param params.tableOptions - Specific options for the table. See {@link TanstackTableProps} for more details.\n * @param params.downloadButtonOptions - Specific options for the download button. See {@link TanstackTableDownloadButtonProps} for more details.\n */\nexport function TanstackTableCard<RowDataModel>({\n table,\n title,\n headerButtons,\n globalFilter,\n tableOptions,\n downloadButtonOptions = null,\n}: {\n table: Table<RowDataModel>;\n title: string;\n headerButtons: JSX.Element;\n globalFilter: {\n value: string;\n setValue: (value: string) => void;\n placeholder: string;\n };\n tableOptions: Partial<Omit<TanstackTableProps<RowDataModel>, 'table'>>;\n downloadButtonOptions?: Omit<TanstackTableDownloadButtonProps<RowDataModel>, 'table'> | null;\n}) {\n const searchInputRef = useRef<HTMLInputElement>(null);\n\n // Track screen size for aria-hidden\n const mediaQuery = typeof window !== 'undefined' ? window.matchMedia('(min-width: 768px)') : null;\n const [isMediumOrLarger, setIsMediumOrLarger] = useState(false);\n\n useEffect(() => {\n // TODO: This is a workaround to avoid a hydration mismatch.\n // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect\n setIsMediumOrLarger(mediaQuery?.matches ?? true);\n }, [mediaQuery]);\n\n useEffect(() => {\n const handler = (e: MediaQueryListEvent) => setIsMediumOrLarger(e.matches);\n mediaQuery?.addEventListener('change', handler);\n return () => mediaQuery?.removeEventListener('change', handler);\n }, [mediaQuery]);\n\n // Focus the search input when Ctrl+F is pressed\n useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'f') {\n if (searchInputRef.current && searchInputRef.current !== document.activeElement) {\n searchInputRef.current.focus();\n event.preventDefault();\n }\n }\n }\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, []);\n\n const displayedCount = table.getRowModel().rows.length;\n const totalCount = table.getCoreRowModel().rows.length;\n\n return (\n <div class=\"card d-flex flex-column h-100\">\n <div class=\"card-header bg-primary text-white\">\n <div class=\"d-flex align-items-center justify-content-between gap-2\">\n <div>{title}</div>\n <div class=\"d-flex gap-2\">\n {headerButtons}\n\n {downloadButtonOptions && (\n <TanstackTableDownloadButton table={table} {...downloadButtonOptions} />\n )}\n </div>\n </div>\n </div>\n <div class=\"card-body d-flex flex-column\">\n <div class=\"d-flex flex-row flex-wrap align-items-center mb-3 gap-2\">\n <div class=\"flex-grow-1 flex-lg-grow-0 col-xl-6 col-lg-7 d-flex flex-row gap-2\">\n <div class=\"input-group\">\n <input\n ref={searchInputRef}\n type=\"text\"\n class=\"form-control\"\n aria-label={globalFilter.placeholder}\n placeholder={globalFilter.placeholder}\n value={globalFilter.value}\n onInput={(e) => {\n if (!(e.target instanceof HTMLInputElement)) return;\n globalFilter.setValue(e.target.value);\n }}\n />\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n aria-label=\"Clear search\"\n title=\"Clear search\"\n data-bs-toggle=\"tooltip\"\n onClick={() => globalFilter.setValue('')}\n >\n <i class=\"bi bi-x-circle\" aria-hidden=\"true\" />\n </button>\n </div>\n {/* We do this instead of CSS properties for the accessibility checker.\n We can't have two elements with the same id of 'column-manager-button'. */}\n {isMediumOrLarger && <ColumnManager table={table} />}\n </div>\n {/* We do this instead of CSS properties for the accessibility checker.\n We can't have two elements with the same id of 'column-manager-button'. */}\n {!isMediumOrLarger && <ColumnManager table={table} />}\n <div class=\"flex-lg-grow-1 d-flex flex-row justify-content-end\">\n <div class=\"text-muted text-nowrap\">\n Showing {displayedCount} of {totalCount} {title.toLowerCase()}\n </div>\n </div>\n </div>\n <div class=\"flex-grow-1\">\n <TanstackTable table={table} title={title} {...tableOptions} />\n </div>\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"TanstackTable.js","sourceRoot":"","sources":["../../src/components/TanstackTable.tsx"],"names":[],"mappings":"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","sourcesContent":["import { flexRender } from '@tanstack/react-table';\nimport { notUndefined, useVirtualizer } from '@tanstack/react-virtual';\nimport type { Header, Row, SortDirection, Table } from '@tanstack/table-core';\nimport clsx from 'clsx';\nimport type { ComponentChildren } from 'preact';\nimport { useEffect, useRef, useState } from 'preact/hooks';\nimport type { JSX } from 'preact/jsx-runtime';\nimport OverlayTrigger from 'react-bootstrap/OverlayTrigger';\nimport Tooltip from 'react-bootstrap/Tooltip';\n\nimport { ColumnManager } from './ColumnManager.js';\nimport {\n TanstackTableDownloadButton,\n type TanstackTableDownloadButtonProps,\n} from './TanstackTableDownloadButton.js';\n\nfunction SortIcon({ sortMethod }: { sortMethod: false | SortDirection }) {\n if (sortMethod === 'asc') {\n return <i class=\"bi bi-sort-up-alt\" aria-hidden=\"true\" />;\n } else if (sortMethod === 'desc') {\n return <i class=\"bi bi-sort-down\" aria-hidden=\"true\" />;\n } else {\n return <i class=\"bi bi-arrow-down-up opacity-75 text-muted\" aria-hidden=\"true\" />;\n }\n}\n\nfunction ResizeHandle<RowDataModel>({\n header,\n setColumnSizing,\n}: {\n header: Header<RowDataModel, unknown>;\n setColumnSizing: Table<RowDataModel>['setColumnSizing'];\n}) {\n const minSize = header.column.columnDef.minSize ?? 0;\n const maxSize = header.column.columnDef.maxSize ?? 0;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n e.preventDefault();\n const currentSize = header.getSize();\n const increment = e.shiftKey ? 20 : 5; // Larger increment with Shift key\n const newSize =\n e.key === 'ArrowLeft'\n ? Math.max(minSize, currentSize - increment)\n : Math.min(maxSize, currentSize + increment);\n\n setColumnSizing((prevSizing) => ({\n ...prevSizing,\n [header.column.id]: newSize,\n }));\n } else if (e.key === 'Home') {\n e.preventDefault();\n header.column.resetSize();\n }\n };\n\n const columnName =\n typeof header.column.columnDef.header === 'string'\n ? header.column.columnDef.header\n : header.column.id;\n\n return (\n <div class=\"py-1 h-100\" style={{ position: 'absolute', right: 0, top: 0, width: '4px' }}>\n {/* separator role is focusable, so these jsx-a11y-x rules are false positives.\n https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/separator_role#focusable_separator\n */}\n {/* eslint-disable-next-line jsx-a11y-x/no-noninteractive-element-interactions */}\n <div\n role=\"separator\"\n aria-label={`Resize '${columnName}' column`}\n aria-valuetext={`${header.getSize()}px`}\n aria-orientation=\"vertical\"\n aria-valuemin={minSize}\n aria-valuemax={maxSize}\n aria-valuenow={header.getSize()}\n // eslint-disable-next-line jsx-a11y-x/no-noninteractive-tabindex\n tabIndex={0}\n class=\"h-100\"\n style={{\n background: header.column.getIsResizing() ? 'var(--bs-primary)' : 'var(--bs-gray-400)',\n cursor: 'col-resize',\n transition: 'background-color 0.2s',\n }}\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n onKeyDown={handleKeyDown}\n />\n </div>\n );\n}\n\nconst DefaultNoResultsState = (\n <>\n <i class=\"bi bi-search display-4 mb-2\" aria-hidden=\"true\" />\n <p class=\"mb-0\">No results found matching your search criteria.</p>\n </>\n);\n\nconst DefaultEmptyState = (\n <>\n <i class=\"bi bi-eye-slash display-4 mb-2\" aria-hidden=\"true\" />\n <p class=\"mb-0\">No results found.</p>\n </>\n);\n\ninterface TanstackTableProps<RowDataModel> {\n table: Table<RowDataModel>;\n title: string;\n filters?: Record<string, (props: { header: Header<RowDataModel, unknown> }) => JSX.Element>;\n rowHeight?: number;\n noResultsState?: JSX.Element;\n emptyState?: JSX.Element;\n}\n\nconst DEFAULT_FILTER_MAP = {};\n\n/**\n * A generic component that renders a full-width, resizeable Tanstack Table.\n * @param params\n * @param params.table - The table model\n * @param params.title - The title of the table\n * @param params.filters - The filters for the table\n * @param params.rowHeight - The height of the rows in the table\n * @param params.noResultsState - The no results state for the table\n * @param params.emptyState - The empty state for the table\n */\nexport function TanstackTable<RowDataModel>({\n table,\n title,\n filters = DEFAULT_FILTER_MAP,\n rowHeight = 42,\n noResultsState = DefaultNoResultsState,\n emptyState = DefaultEmptyState,\n}: TanstackTableProps<RowDataModel>) {\n const parentRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLDivElement>(null);\n const rows = [...table.getTopRows(), ...table.getCenterRows()];\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => parentRef.current,\n estimateSize: () => rowHeight,\n overscan: 10,\n });\n\n // Track focused cell for grid navigation\n const [focusedCell, setFocusedCell] = useState<{ row: number; col: number }>({ row: 0, col: 0 });\n\n const getVisibleCells = (row: Row<RowDataModel>) => [\n ...row.getLeftVisibleCells(),\n ...row.getCenterVisibleCells(),\n ];\n\n const handleGridKeyDown = (e: KeyboardEvent, rowIdx: number, colIdx: number) => {\n const rowLength = getVisibleCells(rows[rowIdx]).length;\n const adjacentCells: Record<KeyboardEvent['key'], { row: number; col: number }> = {\n ArrowDown: {\n row: Math.min(rows.length - 1, rowIdx + 1),\n col: colIdx,\n },\n ArrowUp: {\n row: Math.max(0, rowIdx - 1),\n col: colIdx,\n },\n ArrowRight: {\n row: rowIdx,\n col: Math.min(rowLength - 1, colIdx + 1),\n },\n ArrowLeft: {\n row: rowIdx,\n col: Math.max(0, colIdx - 1),\n },\n };\n\n const next = adjacentCells[e.key];\n\n if (!next) {\n return;\n }\n\n setFocusedCell({ row: next.row, col: next.col });\n // If we are on the leftmost column, we should allow left scrolling.\n if (colIdx === 0 && e.key === 'ArrowLeft') {\n return;\n }\n\n // If we are on the top row, we should allow up scrolling.\n if (rowIdx === 0 && e.key === 'ArrowUp') {\n return;\n }\n\n // If we are on the rightmost column, we should allow right scrolling.\n if (colIdx === rowLength - 1 && e.key === 'ArrowRight') {\n return;\n }\n\n e.preventDefault();\n };\n\n useEffect(() => {\n const selector = `[data-grid-cell-row=\"${focusedCell.row}\"][data-grid-cell-col=\"${focusedCell.col}\"]`;\n const cell = tableRef.current?.querySelector(selector) as HTMLElement | null;\n if (!cell) return;\n\n // eslint-disable-next-line react-you-might-not-need-an-effect/no-chain-state-updates\n cell.focus();\n }, [focusedCell]);\n\n const virtualRows = rowVirtualizer.getVirtualItems();\n const [before, after] =\n virtualRows.length > 0\n ? [\n notUndefined(virtualRows[0]).start - rowVirtualizer.options.scrollMargin,\n rowVirtualizer.getTotalSize() - notUndefined(virtualRows.at(-1)).end,\n ]\n : [0, 0];\n const headerGroups = table.getHeaderGroups();\n const isTableResizing = headerGroups.some((headerGroup) =>\n headerGroup.headers.some((header) => header.column.getIsResizing()),\n );\n const lastColumnId = table.getAllLeafColumns()[table.getAllLeafColumns().length - 1].id;\n\n const tableRect = tableRef.current?.getBoundingClientRect();\n\n // We toggle this here instead of in the parent since this component logically manages all UI for the table.\n // eslint-disable-next-line react-you-might-not-need-an-effect/no-manage-parent\n useEffect(() => {\n document.body.classList.toggle('no-user-select', isTableResizing);\n }, [isTableResizing]);\n\n // Dismiss popovers when their triggering element scrolls out of view\n useEffect(() => {\n const handleScroll = () => {\n const scrollElement = parentRef.current;\n if (!scrollElement) return;\n\n // Find and check all open popovers\n const popovers = document.querySelectorAll('.popover.show');\n popovers.forEach((popover) => {\n // Find the trigger element for this popover\n const triggerElement = document.querySelector(`[aria-describedby=\"${popover.id}\"]`);\n if (!triggerElement) return;\n\n // Check if the trigger element is still visible in the scroll container\n const scrollRect = scrollElement.getBoundingClientRect();\n const triggerRect = triggerElement.getBoundingClientRect();\n\n // Check if trigger is outside the visible scroll area\n const isOutOfView =\n triggerRect.bottom < scrollRect.top ||\n triggerRect.top > scrollRect.bottom ||\n triggerRect.right < scrollRect.left ||\n triggerRect.left > scrollRect.right;\n\n if (isOutOfView) {\n // Use Bootstrap's Popover API to properly hide it\n const popoverInstance = (window as any).bootstrap?.Popover?.getInstance(triggerElement);\n if (popoverInstance) {\n popoverInstance.hide();\n }\n }\n });\n };\n\n const scrollElement = parentRef.current;\n if (scrollElement) {\n scrollElement.addEventListener('scroll', handleScroll);\n return () => scrollElement.removeEventListener('scroll', handleScroll);\n }\n }, []);\n\n // Helper function to get aria-sort value\n const getAriaSort = (sortDirection: false | SortDirection) => {\n switch (sortDirection) {\n case 'asc':\n return 'ascending';\n case 'desc':\n return 'descending';\n default:\n return 'none';\n }\n };\n\n const displayedCount = table.getRowModel().rows.length;\n const totalCount = table.getCoreRowModel().rows.length;\n\n return (\n <div style={{ position: 'relative' }} class=\"d-flex flex-column h-100\">\n <div\n ref={parentRef}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n overflow: 'auto',\n overflowAnchor: 'none',\n }}\n >\n <div\n ref={tableRef}\n style={{\n position: 'relative',\n width: `max(${table.getTotalSize()}px, 100%)`,\n }}\n >\n <table\n class=\"table table-hover mb-0\"\n style={{ tableLayout: 'fixed' }}\n aria-label={title}\n role=\"grid\"\n >\n <thead>\n {headerGroups.map((headerGroup) => (\n <tr key={headerGroup.id}>\n {headerGroup.headers.map((header, index) => {\n const isPinned = header.column.getIsPinned();\n const sortDirection = header.column.getIsSorted();\n const canSort = header.column.getCanSort();\n const canFilter = header.column.getCanFilter();\n const columnName =\n typeof header.column.columnDef.header === 'string'\n ? header.column.columnDef.header\n : header.column.id;\n\n const style: JSX.CSSProperties = {\n width:\n header.column.id === lastColumnId\n ? `max(100%, ${header.getSize()}px)`\n : header.getSize(),\n position: 'sticky',\n top: 0,\n zIndex: isPinned === 'left' ? 2 : 1,\n left: isPinned === 'left' ? header.getStart() : undefined,\n boxShadow:\n 'inset 0 calc(-1 * var(--bs-border-width)) 0 0 rgba(0, 0, 0, 1), inset 0 var(--bs-border-width) 0 0 var(--bs-border-color)',\n };\n\n return (\n <th\n key={header.id}\n class={clsx(isPinned === 'left' && 'bg-light')}\n style={style}\n aria-sort={canSort ? getAriaSort(sortDirection) : undefined}\n role=\"columnheader\"\n >\n <div\n class={clsx(\n 'd-flex align-items-center',\n canSort || canFilter\n ? 'justify-content-between'\n : 'justify-content-center',\n )}\n >\n <button\n class={clsx(\n 'text-nowrap text-start',\n canSort || canFilter ? 'flex-grow-1' : '',\n )}\n style={{\n cursor: canSort ? 'pointer' : 'default',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n background: 'transparent',\n border: 'none',\n }}\n type=\"button\"\n aria-label={\n canSort\n ? `'${columnName}' column, current sort is ${getAriaSort(sortDirection)}`\n : undefined\n }\n onClick={canSort ? header.column.getToggleSortingHandler() : undefined}\n onKeyDown={\n canSort\n ? (e) => {\n const handleSort = header.column.getToggleSortingHandler();\n if (e.key === 'Enter' && handleSort) {\n e.preventDefault();\n handleSort(e);\n }\n }\n : undefined\n }\n >\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n {canSort && (\n <span class=\"visually-hidden\">\n , {getAriaSort(sortDirection)}, click to sort\n </span>\n )}\n </button>\n\n {(canSort || canFilter) && (\n <div class=\"d-flex align-items-center\">\n {canSort && (\n <button\n type=\"button\"\n class=\"btn btn-link text-muted p-0\"\n aria-label={`Sort ${columnName.toLowerCase()}`}\n title={`Sort ${columnName.toLowerCase()}`}\n onClick={header.column.getToggleSortingHandler()}\n >\n <SortIcon sortMethod={sortDirection || false} />\n </button>\n )}\n {canFilter && filters[header.column.id]?.({ header })}\n </div>\n )}\n </div>\n {tableRect?.width &&\n tableRect.width > table.getTotalSize() &&\n index === headerGroup.headers.length - 1 ? null : (\n <ResizeHandle header={header} setColumnSizing={table.setColumnSizing} />\n )}\n </th>\n );\n })}\n </tr>\n ))}\n </thead>\n <tbody>\n {before > 0 && (\n <tr tabIndex={-1}>\n <td colSpan={headerGroups[0].headers.length} style={{ height: before }} />\n </tr>\n )}\n {virtualRows.map((virtualRow) => {\n const row = rows[virtualRow.index];\n const visibleCells = getVisibleCells(row);\n const rowIdx = virtualRow.index;\n\n return (\n <tr key={row.id} style={{ height: rowHeight }}>\n {visibleCells.map((cell, colIdx) => {\n const canSort = cell.column.getCanSort();\n const canFilter = cell.column.getCanFilter();\n\n return (\n <td\n key={cell.id}\n // You can tab to the most-recently focused cell.\n tabIndex={\n focusedCell.row === rowIdx && focusedCell.col === colIdx ? 0 : -1\n }\n // We store this so you can navigate around the grid.\n data-grid-cell-row={rowIdx}\n data-grid-cell-col={colIdx}\n class={clsx(!canSort && !canFilter && 'text-center')}\n style={{\n width:\n cell.column.id === lastColumnId\n ? `max(100%, ${cell.column.getSize()}px)`\n : cell.column.getSize(),\n position: cell.column.getIsPinned() === 'left' ? 'sticky' : undefined,\n left:\n cell.column.getIsPinned() === 'left'\n ? cell.column.getStart()\n : undefined,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n onFocus={() => setFocusedCell({ row: rowIdx, col: colIdx })}\n onKeyDown={(e) => handleGridKeyDown(e, rowIdx, colIdx)}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </td>\n );\n })}\n </tr>\n );\n })}\n {after > 0 && (\n <tr tabIndex={-1}>\n <td colSpan={headerGroups[0].headers.length} style={{ height: after }} />\n </tr>\n )}\n </tbody>\n </table>\n </div>\n </div>\n {table.getVisibleLeafColumns().length === 0 || displayedCount === 0 ? (\n <div>\n <div\n class=\"d-flex flex-column justify-content-center align-items-center p-4\"\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n // Allow pointer events (e.g. scrolling) to reach the underlying table.\n pointerEvents: 'none',\n }}\n role=\"status\"\n aria-live=\"polite\"\n >\n <div\n class=\"col-lg-6\"\n style={{\n // Allow selecting and interacting with the empty state content.\n pointerEvents: 'auto',\n }}\n >\n {table.getVisibleLeafColumns().length === 0 ? (\n <TanstackTableEmptyState iconName=\"bi-eye-slash\">\n No columns selected. Use the View menu to show columns.\n </TanstackTableEmptyState>\n ) : displayedCount === 0 ? (\n totalCount > 0 ? (\n noResultsState\n ) : (\n emptyState\n )\n ) : null}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\n/**\n * A generic component that wraps the TanstackTable component in a card.\n * @param params\n * @param params.table - The table model\n * @param params.title - The title of the card\n * @param params.headerButtons - The buttons to display in the header\n * @param params.columnManagerButtons - The buttons to display next to the column manager (View button)\n * @param params.globalFilter - State management for the global filter\n * @param params.globalFilter.value\n * @param params.globalFilter.setValue\n * @param params.globalFilter.placeholder\n * @param params.tableOptions - Specific options for the table. See {@link TanstackTableProps} for more details.\n * @param params.downloadButtonOptions - Specific options for the download button. See {@link TanstackTableDownloadButtonProps} for more details.\n */\nexport function TanstackTableCard<RowDataModel>({\n table,\n title,\n headerButtons,\n columnManagerButtons,\n globalFilter,\n tableOptions,\n downloadButtonOptions = null,\n}: {\n table: Table<RowDataModel>;\n title: string;\n headerButtons: JSX.Element;\n columnManagerButtons?: JSX.Element;\n globalFilter: {\n value: string;\n setValue: (value: string) => void;\n placeholder: string;\n };\n tableOptions: Partial<Omit<TanstackTableProps<RowDataModel>, 'table'>>;\n downloadButtonOptions?: Omit<TanstackTableDownloadButtonProps<RowDataModel>, 'table'> | null;\n}) {\n const searchInputRef = useRef<HTMLInputElement>(null);\n\n // Focus the search input when Ctrl+F is pressed\n useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'f') {\n if (searchInputRef.current && searchInputRef.current !== document.activeElement) {\n searchInputRef.current.focus();\n event.preventDefault();\n }\n }\n }\n document.addEventListener('keydown', onKeyDown);\n return () => document.removeEventListener('keydown', onKeyDown);\n }, []);\n\n const displayedCount = table.getRowModel().rows.length;\n const totalCount = table.getCoreRowModel().rows.length;\n\n return (\n <div class=\"card d-flex flex-column h-100\">\n <div class=\"card-header bg-primary text-white\">\n <div class=\"d-flex align-items-center justify-content-between gap-2\">\n <div>{title}</div>\n <div class=\"d-flex gap-2\">\n {headerButtons}\n\n {downloadButtonOptions && (\n <TanstackTableDownloadButton table={table} {...downloadButtonOptions} />\n )}\n </div>\n </div>\n </div>\n <div class=\"card-body d-flex flex-row flex-wrap flex-grow-0 align-items-center gap-2\">\n <div class=\"flex-grow-1 flex-lg-grow-0 col-xl-6 col-lg-7 d-flex flex-row gap-2\">\n <div class=\"position-relative flex-grow-1\">\n <input\n ref={searchInputRef}\n type=\"text\"\n class=\"form-control tanstack-table-search-input tanstack-table-focusable-shadow\"\n aria-label={globalFilter.placeholder}\n placeholder={globalFilter.placeholder}\n value={globalFilter.value}\n autoComplete=\"off\"\n onInput={(e) => {\n if (!(e.target instanceof HTMLInputElement)) return;\n globalFilter.setValue(e.target.value);\n }}\n />\n {globalFilter.value && (\n <OverlayTrigger overlay={<Tooltip>Clear search</Tooltip>}>\n <button\n type=\"button\"\n class=\"btn btn-link tanstack-table-clear-search\"\n aria-label=\"Clear search\"\n onClick={() => globalFilter.setValue('')}\n >\n <i class=\"bi bi-x-circle-fill\" aria-hidden=\"true\" />\n </button>\n </OverlayTrigger>\n )}\n </div>\n <div class=\"d-none d-md-block\">\n <ColumnManager table={table} id=\"column-manager-button-wide\" />\n {columnManagerButtons}\n </div>\n </div>\n <div class=\"d-block d-md-none\">\n <ColumnManager table={table} id=\"column-manager-button-narrow\" />\n {columnManagerButtons}\n </div>\n <div class=\"flex-lg-grow-1 d-flex flex-row justify-content-end\">\n <div class=\"text-muted text-nowrap\">\n Showing {displayedCount} of {totalCount} {title.toLowerCase()}\n </div>\n </div>\n </div>\n <div class=\"flex-grow-1\">\n <TanstackTable table={table} title={title} {...tableOptions} />\n </div>\n </div>\n );\n}\n\nexport function TanstackTableEmptyState({\n iconName,\n children,\n}: {\n iconName: `bi-${string}`;\n children: ComponentChildren;\n}) {\n return (\n <div class=\"d-flex flex-column justify-content-center align-items-center text-muted\">\n <i class={clsx('bi', iconName, 'display-4 mb-2')} aria-hidden=\"true\" />\n <div>{children}</div>\n </div>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TanstackTableDownloadButton.d.ts","sourceRoot":"","sources":["../../src/components/TanstackTableDownloadButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAInD,MAAM,WAAW,gCAAgC,CAAC,YAAY;IAC5D,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACnF,WAAW,EAAE,MAAM,CAAC;CACrB;AACD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,EACxD,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,EAAE,gCAAgC,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"TanstackTableDownloadButton.d.ts","sourceRoot":"","sources":["../../src/components/TanstackTableDownloadButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAInD,MAAM,WAAW,gCAAgC,CAAC,YAAY;IAC5D,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACnF,WAAW,EAAE,MAAM,CAAC;CACrB;AACD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,EACxD,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,EAAE,gCAAgC,CAAC,YAAY,CAAC,yCA8GhD"}
|
|
@@ -15,6 +15,8 @@ export function TanstackTableDownloadButton({ table, filenameBase, mapRowToData,
|
|
|
15
15
|
const allRowsJSON = allRows.map(mapRowToData).filter((row) => row !== null);
|
|
16
16
|
const filteredRows = table.getRowModel().rows.map((row) => row.original);
|
|
17
17
|
const filteredRowsJSON = filteredRows.map(mapRowToData).filter((row) => row !== null);
|
|
18
|
+
const selectedRows = table.getSelectedRowModel().rows.map((row) => row.original);
|
|
19
|
+
const selectedRowsJSON = selectedRows.map(mapRowToData).filter((row) => row !== null);
|
|
18
20
|
function downloadJSONAsCSV(jsonRows, filename) {
|
|
19
21
|
if (jsonRows.length === 0) {
|
|
20
22
|
throw new Error('No rows to download');
|
|
@@ -23,6 +25,6 @@ export function TanstackTableDownloadButton({ table, filenameBase, mapRowToData,
|
|
|
23
25
|
const csvRows = jsonRows.map((row) => Object.values(row));
|
|
24
26
|
downloadAsCSV(header, csvRows, filename);
|
|
25
27
|
}
|
|
26
|
-
return (_jsxs("div", { class: "btn-group", children: [_jsxs("button", { type: "button", "data-bs-toggle": "dropdown", "aria-expanded": "false", "aria-haspopup": "true", "aria-label": `Download ${pluralLabel} data in various formats`, class: "btn btn-light btn-sm dropdown-toggle", children: [_jsx("i", { "aria-hidden": "true", class: "pe-2 bi bi-download" }), "Download"] }), _jsxs("ul", { class: "dropdown-menu", role: "menu", "aria-label": "Download options", children: [_jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download all ${pluralLabel} as CSV file`, disabled: allRowsJSON.length === 0, onClick: () => downloadJSONAsCSV(allRowsJSON, `${filenameBase}.csv`), children: ["All ", pluralLabel, " as CSV"] }) }), _jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download all ${pluralLabel} as JSON file`, disabled: allRowsJSON.length === 0, onClick: () => downloadAsJSON(allRowsJSON, `${filenameBase}.json`), children: ["All ", pluralLabel, " as JSON"] }) }), _jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download filtered ${pluralLabel} as CSV file`, disabled: filteredRowsJSON.length === 0, onClick: () => downloadJSONAsCSV(filteredRowsJSON, `${filenameBase}_filtered.csv`), children: ["Filtered ", pluralLabel, " as CSV"] }) }), _jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download filtered ${pluralLabel} as JSON file`, disabled: filteredRowsJSON.length === 0, onClick: () => downloadAsJSON(filteredRowsJSON, `${filenameBase}_filtered.json`), children: ["Filtered ", pluralLabel, " as JSON"] }) })] })] }));
|
|
28
|
+
return (_jsxs("div", { class: "btn-group", children: [_jsxs("button", { type: "button", "data-bs-toggle": "dropdown", "aria-expanded": "false", "aria-haspopup": "true", "aria-label": `Download ${pluralLabel} data in various formats`, class: "btn btn-light btn-sm dropdown-toggle", children: [_jsx("i", { "aria-hidden": "true", class: "pe-2 bi bi-download" }), _jsx("span", { class: "d-none d-sm-inline", children: "Download" })] }), _jsxs("ul", { class: "dropdown-menu", role: "menu", "aria-label": "Download options", children: [_jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download all ${pluralLabel} as CSV file`, disabled: allRowsJSON.length === 0, onClick: () => downloadJSONAsCSV(allRowsJSON, `${filenameBase}.csv`), children: ["All ", pluralLabel, " as CSV"] }) }), _jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download all ${pluralLabel} as JSON file`, disabled: allRowsJSON.length === 0, onClick: () => downloadAsJSON(allRowsJSON, `${filenameBase}.json`), children: ["All ", pluralLabel, " as JSON"] }) }), _jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download selected ${pluralLabel} as CSV file`, disabled: selectedRowsJSON.length === 0, onClick: () => downloadJSONAsCSV(selectedRowsJSON, `${filenameBase}_selected.csv`), children: ["Selected ", pluralLabel, " as CSV"] }) }), _jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download selected ${pluralLabel} as JSON file`, disabled: selectedRowsJSON.length === 0, onClick: () => downloadAsJSON(selectedRowsJSON, `${filenameBase}_selected.json`), children: ["Selected ", pluralLabel, " as JSON"] }) }), _jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download filtered ${pluralLabel} as CSV file`, disabled: filteredRowsJSON.length === 0, onClick: () => downloadJSONAsCSV(filteredRowsJSON, `${filenameBase}_filtered.csv`), children: ["Filtered ", pluralLabel, " as CSV"] }) }), _jsx("li", { role: "presentation", children: _jsxs("button", { class: "dropdown-item", type: "button", role: "menuitem", "aria-label": `Download filtered ${pluralLabel} as JSON file`, disabled: filteredRowsJSON.length === 0, onClick: () => downloadAsJSON(filteredRowsJSON, `${filenameBase}_filtered.json`), children: ["Filtered ", pluralLabel, " as JSON"] }) })] })] }));
|
|
27
29
|
}
|
|
28
30
|
//# sourceMappingURL=TanstackTableDownloadButton.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TanstackTableDownloadButton.js","sourceRoot":"","sources":["../../src/components/TanstackTableDownloadButton.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAQ5E;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CAAe,EACxD,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,WAAW,GACoC;IAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;IAC5E,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzE,MAAM,gBAAgB,GAAG,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;IAEtF,SAAS,iBAAiB,CACxB,QAAkD,EAClD,QAAgB;QAEhB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1D,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,CACL,eAAK,KAAK,EAAC,WAAW,aACpB,kBACE,IAAI,EAAC,QAAQ,oBACE,UAAU,mBACX,OAAO,mBACP,MAAM,gBACR,YAAY,WAAW,0BAA0B,EAC7D,KAAK,EAAC,sCAAsC,aAE5C,2BAAe,MAAM,EAAC,KAAK,EAAC,qBAAqB,GAAG,
|
|
1
|
+
{"version":3,"file":"TanstackTableDownloadButton.js","sourceRoot":"","sources":["../../src/components/TanstackTableDownloadButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { Table } from '@tanstack/react-table';\n\nimport { downloadAsCSV, downloadAsJSON } from '@prairielearn/browser-utils';\n\nexport interface TanstackTableDownloadButtonProps<RowDataModel> {\n table: Table<RowDataModel>;\n filenameBase: string;\n mapRowToData: (row: RowDataModel) => Record<string, string | number | null> | null;\n pluralLabel: string;\n}\n/**\n * @param params\n * @param params.pluralLabel - What you are downloading, e.g. \"students\"\n * @param params.table - The table model\n * @param params.filenameBase - The base filename for the downloads\n * @param params.mapRowToData - A function that maps a row to a record where the\n * keys are the column names, and the values are the cell values. The key order is important,\n * and should match the expected order of the columns in the CSV file. If the function returns null,\n * the row will be skipped.\n */\nexport function TanstackTableDownloadButton<RowDataModel>({\n table,\n filenameBase,\n mapRowToData,\n pluralLabel,\n}: TanstackTableDownloadButtonProps<RowDataModel>) {\n const allRows = table.getCoreRowModel().rows.map((row) => row.original);\n const allRowsJSON = allRows.map(mapRowToData).filter((row) => row !== null);\n const filteredRows = table.getRowModel().rows.map((row) => row.original);\n const filteredRowsJSON = filteredRows.map(mapRowToData).filter((row) => row !== null);\n const selectedRows = table.getSelectedRowModel().rows.map((row) => row.original);\n const selectedRowsJSON = selectedRows.map(mapRowToData).filter((row) => row !== null);\n\n function downloadJSONAsCSV(\n jsonRows: Record<string, string | number | null>[],\n filename: string,\n ): void {\n if (jsonRows.length === 0) {\n throw new Error('No rows to download');\n }\n\n const header = Object.keys(jsonRows[0]);\n const csvRows = jsonRows.map((row) => Object.values(row));\n downloadAsCSV(header, csvRows, filename);\n }\n\n return (\n <div class=\"btn-group\">\n <button\n type=\"button\"\n data-bs-toggle=\"dropdown\"\n aria-expanded=\"false\"\n aria-haspopup=\"true\"\n aria-label={`Download ${pluralLabel} data in various formats`}\n class=\"btn btn-light btn-sm dropdown-toggle\"\n >\n <i aria-hidden=\"true\" class=\"pe-2 bi bi-download\" />\n <span class=\"d-none d-sm-inline\">Download</span>\n </button>\n <ul class=\"dropdown-menu\" role=\"menu\" aria-label=\"Download options\">\n <li role=\"presentation\">\n <button\n class=\"dropdown-item\"\n type=\"button\"\n role=\"menuitem\"\n aria-label={`Download all ${pluralLabel} as CSV file`}\n disabled={allRowsJSON.length === 0}\n onClick={() => downloadJSONAsCSV(allRowsJSON, `${filenameBase}.csv`)}\n >\n All {pluralLabel} as CSV\n </button>\n </li>\n <li role=\"presentation\">\n <button\n class=\"dropdown-item\"\n type=\"button\"\n role=\"menuitem\"\n aria-label={`Download all ${pluralLabel} as JSON file`}\n disabled={allRowsJSON.length === 0}\n onClick={() => downloadAsJSON(allRowsJSON, `${filenameBase}.json`)}\n >\n All {pluralLabel} as JSON\n </button>\n </li>\n <li role=\"presentation\">\n <button\n class=\"dropdown-item\"\n type=\"button\"\n role=\"menuitem\"\n aria-label={`Download selected ${pluralLabel} as CSV file`}\n disabled={selectedRowsJSON.length === 0}\n onClick={() => downloadJSONAsCSV(selectedRowsJSON, `${filenameBase}_selected.csv`)}\n >\n Selected {pluralLabel} as CSV\n </button>\n </li>\n <li role=\"presentation\">\n <button\n class=\"dropdown-item\"\n type=\"button\"\n role=\"menuitem\"\n aria-label={`Download selected ${pluralLabel} as JSON file`}\n disabled={selectedRowsJSON.length === 0}\n onClick={() => downloadAsJSON(selectedRowsJSON, `${filenameBase}_selected.json`)}\n >\n Selected {pluralLabel} as JSON\n </button>\n </li>\n <li role=\"presentation\">\n <button\n class=\"dropdown-item\"\n type=\"button\"\n role=\"menuitem\"\n aria-label={`Download filtered ${pluralLabel} as CSV file`}\n disabled={filteredRowsJSON.length === 0}\n onClick={() => downloadJSONAsCSV(filteredRowsJSON, `${filenameBase}_filtered.csv`)}\n >\n Filtered {pluralLabel} as CSV\n </button>\n </li>\n <li role=\"presentation\">\n <button\n class=\"dropdown-item\"\n type=\"button\"\n role=\"menuitem\"\n aria-label={`Download filtered ${pluralLabel} as JSON file`}\n disabled={filteredRowsJSON.length === 0}\n onClick={() => downloadAsJSON(filteredRowsJSON, `${filenameBase}_filtered.json`)}\n >\n Filtered {pluralLabel} as JSON\n </button>\n </li>\n </ul>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Row, Table } from '@tanstack/react-table';
|
|
2
|
+
import { type MouseEvent } from 'preact/compat';
|
|
3
|
+
/**
|
|
4
|
+
* A hook that provides shift-click range selection functionality for table checkboxes.
|
|
5
|
+
* Use this hook in the parent component and pass the returned props to individual checkboxes.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* const { lastClickedRowIndex, createCheckboxProps } = useShiftClickCheckbox();
|
|
10
|
+
*
|
|
11
|
+
* // In your column definition:
|
|
12
|
+
* cell: ({ row, table }) => {
|
|
13
|
+
* return <input type="checkbox" {...createCheckboxProps(row, table)} />;
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function useShiftClickCheckbox<TData>(): {
|
|
18
|
+
lastClickedRowIndex: number | null;
|
|
19
|
+
setLastClickedRowIndex: import("original-preact/hooks").Dispatch<import("original-preact/hooks").StateUpdater<number | null>>;
|
|
20
|
+
createCheckboxProps: (row: Row<TData>, table: Table<TData>) => {
|
|
21
|
+
checked: boolean;
|
|
22
|
+
disabled: boolean;
|
|
23
|
+
onClick: (e: MouseEvent<HTMLInputElement>) => void;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=useShiftClickCheckbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useShiftClickCheckbox.d.ts","sourceRoot":"","sources":["../../src/components/useShiftClickCheckbox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,KAAK,UAAU,EAAyB,MAAM,eAAe,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,KAAK;;;+BAUjC,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC;;;qBACX,UAAU,CAAC,gBAAgB,CAAC;;EAsCzD"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useCallback, useState } from 'preact/compat';
|
|
2
|
+
/**
|
|
3
|
+
* A hook that provides shift-click range selection functionality for table checkboxes.
|
|
4
|
+
* Use this hook in the parent component and pass the returned props to individual checkboxes.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* const { lastClickedRowIndex, createCheckboxProps } = useShiftClickCheckbox();
|
|
9
|
+
*
|
|
10
|
+
* // In your column definition:
|
|
11
|
+
* cell: ({ row, table }) => {
|
|
12
|
+
* return <input type="checkbox" {...createCheckboxProps(row, table)} />;
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function useShiftClickCheckbox() {
|
|
17
|
+
const [lastClickedRowIndex, setLastClickedRowIndex] = useState(null);
|
|
18
|
+
/**
|
|
19
|
+
* Creates props for a checkbox that supports shift-click range selection.
|
|
20
|
+
* @param row - The TanStack Table row
|
|
21
|
+
* @param table - The TanStack Table instance
|
|
22
|
+
* @returns Props to spread on the checkbox input element
|
|
23
|
+
*/
|
|
24
|
+
const createCheckboxProps = useCallback((row, table) => {
|
|
25
|
+
const handleClick = (e) => {
|
|
26
|
+
if (e.shiftKey && lastClickedRowIndex !== null) {
|
|
27
|
+
// Shift-click: select range
|
|
28
|
+
const currentIndex = row.index;
|
|
29
|
+
const start = Math.min(lastClickedRowIndex, currentIndex);
|
|
30
|
+
const end = Math.max(lastClickedRowIndex, currentIndex);
|
|
31
|
+
// Get all rows in the range
|
|
32
|
+
const rows = table.getRowModel().rows;
|
|
33
|
+
const shouldSelect = !row.getIsSelected();
|
|
34
|
+
// Select or deselect all rows in the range
|
|
35
|
+
for (let i = start; i <= end; i++) {
|
|
36
|
+
if (rows[i]?.getCanSelect()) {
|
|
37
|
+
rows[i].toggleSelected(shouldSelect);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Normal click: toggle this row
|
|
43
|
+
row.getToggleSelectedHandler()(e);
|
|
44
|
+
}
|
|
45
|
+
setLastClickedRowIndex(row.index);
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
checked: row.getIsSelected(),
|
|
49
|
+
disabled: !row.getCanSelect(),
|
|
50
|
+
onClick: handleClick,
|
|
51
|
+
};
|
|
52
|
+
}, [lastClickedRowIndex]);
|
|
53
|
+
return {
|
|
54
|
+
lastClickedRowIndex,
|
|
55
|
+
setLastClickedRowIndex,
|
|
56
|
+
createCheckboxProps,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=useShiftClickCheckbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useShiftClickCheckbox.js","sourceRoot":"","sources":["../../src/components/useShiftClickCheckbox.tsx"],"names":[],"mappings":"AACA,OAAO,EAAmB,WAAW,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAEpF;;;;;OAKG;IACH,MAAM,mBAAmB,GAAG,WAAW,CACrC,CAAC,GAAe,EAAE,KAAmB,EAAE,EAAE;QACvC,MAAM,WAAW,GAAG,CAAC,CAA+B,EAAE,EAAE;YACtD,IAAI,CAAC,CAAC,QAAQ,IAAI,mBAAmB,KAAK,IAAI,EAAE,CAAC;gBAC/C,4BAA4B;gBAC5B,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC;gBAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;gBAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;gBAExD,4BAA4B;gBAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC;gBACtC,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBAE1C,2CAA2C;gBAC3C,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;oBAClC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,CAAC;wBAC5B,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;oBACvC,CAAC;gBACH,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,gCAAgC;gBAChC,GAAG,CAAC,wBAAwB,EAAE,CAAC,CAAC,CAAC,CAAC;YACpC,CAAC;YACD,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,GAAG,CAAC,aAAa,EAAE;YAC5B,QAAQ,EAAE,CAAC,GAAG,CAAC,YAAY,EAAE;YAC7B,OAAO,EAAE,WAAW;SACrB,CAAC;IACJ,CAAC,EACD,CAAC,mBAAmB,CAAC,CACtB,CAAC;IAEF,OAAO;QACL,mBAAmB;QACnB,sBAAsB;QACtB,mBAAmB;KACpB,CAAC;AACJ,CAAC","sourcesContent":["import type { Row, Table } from '@tanstack/react-table';\nimport { type MouseEvent, useCallback, useState } from 'preact/compat';\n\n/**\n * A hook that provides shift-click range selection functionality for table checkboxes.\n * Use this hook in the parent component and pass the returned props to individual checkboxes.\n *\n * @example\n * ```tsx\n * const { lastClickedRowIndex, createCheckboxProps } = useShiftClickCheckbox();\n *\n * // In your column definition:\n * cell: ({ row, table }) => {\n * return <input type=\"checkbox\" {...createCheckboxProps(row, table)} />;\n * }\n * ```\n */\nexport function useShiftClickCheckbox<TData>() {\n const [lastClickedRowIndex, setLastClickedRowIndex] = useState<number | null>(null);\n\n /**\n * Creates props for a checkbox that supports shift-click range selection.\n * @param row - The TanStack Table row\n * @param table - The TanStack Table instance\n * @returns Props to spread on the checkbox input element\n */\n const createCheckboxProps = useCallback(\n (row: Row<TData>, table: Table<TData>) => {\n const handleClick = (e: MouseEvent<HTMLInputElement>) => {\n if (e.shiftKey && lastClickedRowIndex !== null) {\n // Shift-click: select range\n const currentIndex = row.index;\n const start = Math.min(lastClickedRowIndex, currentIndex);\n const end = Math.max(lastClickedRowIndex, currentIndex);\n\n // Get all rows in the range\n const rows = table.getRowModel().rows;\n const shouldSelect = !row.getIsSelected();\n\n // Select or deselect all rows in the range\n for (let i = start; i <= end; i++) {\n if (rows[i]?.getCanSelect()) {\n rows[i].toggleSelected(shouldSelect);\n }\n }\n } else {\n // Normal click: toggle this row\n row.getToggleSelectedHandler()(e);\n }\n setLastClickedRowIndex(row.index);\n };\n\n return {\n checked: row.getIsSelected(),\n disabled: !row.getCanSelect(),\n onClick: handleClick,\n };\n },\n [lastClickedRowIndex],\n );\n\n return {\n lastClickedRowIndex,\n setLastClickedRowIndex,\n createCheckboxProps,\n };\n}\n"]}
|