@prairielearn/ui 1.7.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @prairielearn/ui
2
2
 
3
+ ## 1.7.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 90c712d: Improve style of table when it is less than viewport width
8
+
3
9
  ## 1.7.0
4
10
 
5
11
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"TanstackTable.d.ts","sourceRoot":"","sources":["../../src/components/TanstackTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAQ,MAAM,EAAO,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAK9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAI/D,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,kCAAkC,CAAC;AAoE1C,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;IACzB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;CACpD;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,EAC1C,KAAK,EACL,KAAK,EACL,OAA4B,EAC5B,SAAc,EACd,cAAsC,EACtC,UAA8B,EAC9B,SAAS,GACV,EAAE,kBAAkB,CAAC,YAAY,CAAC,eA0VlC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,EAC9C,KAAK,EACL,KAAK,EACL,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,SAAS,EACT,GAAG,QAAQ,EACZ,EAAE;IACD,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAC5B,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;QACtB,UAAU,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;KAC1B,CAAC;IACF,YAAY,EAAE;QACZ,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,CAC1B,gCAAgC,CAAC,YAAY,CAAC,EAC9C,OAAO,GAAG,eAAe,GAAG,aAAa,CAC1C,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,eA+FvC;AAED,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,MAAM,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B,eAOA"}
1
+ {"version":3,"file":"TanstackTable.d.ts","sourceRoot":"","sources":["../../src/components/TanstackTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAQ,MAAM,EAAO,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAErE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAEhD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAK9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAI/D,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,kCAAkC,CAAC;AAoE1C,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;IACzB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;CACpD;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,EAC1C,KAAK,EACL,KAAK,EACL,OAA4B,EAC5B,SAAc,EACd,cAAsC,EACtC,UAA8B,EAC9B,SAAS,GACV,EAAE,kBAAkB,CAAC,YAAY,CAAC,eA0WlC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,EAC9C,KAAK,EACL,KAAK,EACL,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,SAAS,EACT,GAAG,QAAQ,EACZ,EAAE;IACD,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAC5B,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;QACtB,UAAU,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;KAC1B,CAAC;IACF,YAAY,EAAE;QACZ,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,CAC1B,gCAAgC,CAAC,YAAY,CAAC,EAC9C,OAAO,GAAG,eAAe,GAAG,aAAa,CAC1C,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,eA+FvC;AAED,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,MAAM,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B,eAOA"}
@@ -169,33 +169,29 @@ export function TanstackTable({ table, title, filters = DEFAULT_FILTER_MAP, rowH
169
169
  }, children: _jsx("div", { ref: tableRef, style: {
170
170
  position: 'relative',
171
171
  width: `max(${table.getTotalSize()}px, 100%)`,
172
- }, children: _jsxs("table", { class: "table table-hover mb-0", style: { display: 'grid', tableLayout: 'fixed' }, "aria-label": title, role: "grid", children: [_jsx("thead", { style: {
172
+ }, children: _jsxs("table", { class: "table table-hover mb-0", style: { display: 'grid', tableLayout: 'fixed' }, "aria-label": title, role: "grid", children: [_jsx("thead", { class: "position-sticky top-0 w-100 border-top", style: {
173
173
  display: 'grid',
174
- position: 'sticky',
175
- top: 0,
176
174
  zIndex: 1,
177
- }, children: _jsxs("tr", { style: { display: 'flex', width: `${table.getTotalSize()}px` }, children: [leftPinnedHeaders.map((header) => {
175
+ borderBottom: 'var(--bs-border-width) solid black',
176
+ }, children: _jsxs("tr", { class: "d-flex w-100", style: { minWidth: `${table.getTotalSize()}px` }, children: [leftPinnedHeaders.map((header) => {
178
177
  return (_jsx(TanstackTableHeaderCell, { header: header, filters: filters, table: table, handleResizeEnd: handleResizeEnd, isPinned: "left" }, header.id));
179
178
  }), virtualPaddingLeft ? (_jsx("th", { style: { display: 'flex', width: virtualPaddingLeft } })) : null, virtualColumns.map((virtualColumn) => {
180
179
  const header = centerHeaders[virtualColumn.index];
181
180
  if (!header)
182
181
  return null;
183
182
  return (_jsx(TanstackTableHeaderCell, { header: header, filters: filters, table: table, handleResizeEnd: handleResizeEnd, isPinned: false }, header.id));
184
- }), virtualPaddingRight ? (_jsx("th", { style: { display: 'flex', width: virtualPaddingRight } })) : null] }, leafHeaderGroup.id) }), _jsx("tbody", { style: {
183
+ }), virtualPaddingRight ? (_jsx("th", { style: { display: 'flex', width: virtualPaddingRight } })) : null, _jsx("th", { tabIndex: -1, class: "d-flex flex-grow-1 p-0", style: { minWidth: 0 }, "aria-hidden": "true" })] }, leafHeaderGroup.id) }), _jsx("tbody", { class: "position-relative w-100", style: {
185
184
  display: 'grid',
186
185
  height: `${rowVirtualizer.getTotalSize()}px`,
187
- position: 'relative',
188
186
  }, children: virtualRows.map((virtualRow) => {
189
187
  const row = rows[virtualRow.index];
190
188
  const rowIdx = virtualRow.index;
191
189
  const leftPinnedCells = row.getLeftVisibleCells();
192
190
  const centerCells = row.getCenterVisibleCells();
193
191
  let currentColIdx = 0;
194
- return (_jsxs("tr", { ref: (node) => rowVirtualizer.measureElement(node), "data-index": virtualRow.index, style: {
195
- display: 'flex',
196
- position: 'absolute',
192
+ return (_jsxs("tr", { ref: (node) => rowVirtualizer.measureElement(node), "data-index": virtualRow.index, class: "d-flex position-absolute w-100", style: {
197
193
  transform: `translateY(${virtualRow.start}px)`,
198
- width: `${table.getTotalSize()}px`,
194
+ minWidth: `${table.getTotalSize()}px`,
199
195
  }, children: [leftPinnedCells.map((cell) => {
200
196
  const colIdx = currentColIdx++;
201
197
  const canSort = cell.column.getCanSort();
@@ -211,7 +207,7 @@ export function TanstackTable({ table, title, filters = DEFAULT_FILTER_MAP, rowH
211
207
  const canFilter = cell.column.getCanFilter();
212
208
  const wrapText = cell.column.columnDef.meta?.wrapText ?? false;
213
209
  return (_jsx(TableCell, { cell: cell, rowIdx: rowIdx, colIdx: colIdx, canSort: canSort, canFilter: canFilter, wrapText: wrapText, handleGridKeyDown: handleGridKeyDown }, cell.id));
214
- }), virtualPaddingRight ? (_jsx("td", { style: { display: 'flex', width: virtualPaddingRight } })) : null] }, row.id));
210
+ }), virtualPaddingRight ? (_jsx("td", { style: { display: 'flex', width: virtualPaddingRight } })) : null, _jsx("td", { tabIndex: -1, class: "d-flex flex-grow-1 p-0", style: { minWidth: 0 }, "aria-hidden": "true" })] }, row.id));
215
211
  }) })] }) }) }), 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: {
216
212
  position: 'absolute',
217
213
  top: 0,
@@ -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 { useVirtualizer } from '@tanstack/react-virtual';\nimport type { Cell, Header, Row, Table } from '@tanstack/table-core';\nimport clsx from 'clsx';\nimport type { ComponentChildren } from 'preact';\nimport { useEffect, useMemo, useRef, useState } from 'preact/hooks';\nimport type { JSX } from 'preact/jsx-runtime';\nimport OverlayTrigger from 'react-bootstrap/OverlayTrigger';\nimport Tooltip from 'react-bootstrap/Tooltip';\nimport { useDebouncedCallback } from 'use-debounce';\n\nimport type { ComponentProps } from '@prairielearn/preact-cjs';\nimport { run } from '@prairielearn/run';\n\nimport { ColumnManager } from './ColumnManager.js';\nimport {\n TanstackTableDownloadButton,\n type TanstackTableDownloadButtonProps,\n} from './TanstackTableDownloadButton.js';\nimport { TanstackTableHeaderCell } from './TanstackTableHeaderCell.js';\nimport { useAutoSizeColumns } from './useAutoSizeColumns.js';\n\nfunction TableCell<RowDataModel>({\n cell,\n rowIdx,\n colIdx,\n canSort,\n canFilter,\n wrapText,\n handleGridKeyDown,\n}: {\n cell: Cell<RowDataModel, unknown>;\n rowIdx: number;\n colIdx: number;\n canSort: boolean;\n canFilter: boolean;\n wrapText: boolean;\n handleGridKeyDown: (e: KeyboardEvent, rowIdx: number, colIdx: number) => void;\n}) {\n return (\n <td\n key={cell.id}\n tabIndex={0}\n data-grid-cell-row={rowIdx}\n data-grid-cell-col={colIdx}\n class={clsx(!canSort && !canFilter && 'text-center')}\n style={{\n display: 'flex',\n width: cell.column.getSize(),\n minWidth: 0,\n maxWidth: cell.column.getSize(),\n flexShrink: 0,\n position: cell.column.getIsPinned() === 'left' ? 'sticky' : undefined,\n left: cell.column.getIsPinned() === 'left' ? cell.column.getStart() : undefined,\n verticalAlign: 'middle',\n }}\n onKeyDown={(e) => handleGridKeyDown(e, rowIdx, colIdx)}\n >\n <div\n style={{\n display: 'block',\n minWidth: 0,\n maxWidth: '100%',\n overflow: wrapText ? 'visible' : 'hidden',\n textOverflow: wrapText ? undefined : 'ellipsis',\n whiteSpace: wrapText ? 'normal' : 'nowrap',\n flex: '1 1 0%',\n width: 0, // Allow flex to control width, but start from 0\n }}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </div>\n </td>\n );\n}\n\nconst DefaultNoResultsState = (\n <TanstackTableEmptyState iconName=\"bi-search\">\n No results found matching your search criteria.\n </TanstackTableEmptyState>\n);\n\nconst DefaultEmptyState = (\n <TanstackTableEmptyState iconName=\"bi-eye-slash\">No results found.</TanstackTableEmptyState>\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 scrollRef?: React.RefObject<HTMLDivElement> | null;\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 * @param params.scrollRef - Optional ref that will be attached to the scroll container element.\n */\nexport function TanstackTable<RowDataModel>({\n table,\n title,\n filters = DEFAULT_FILTER_MAP,\n rowHeight = 42,\n noResultsState = DefaultNoResultsState,\n emptyState = DefaultEmptyState,\n scrollRef,\n}: TanstackTableProps<RowDataModel>) {\n const parentRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLDivElement>(null);\n const scrollContainerRef = scrollRef ?? parentRef;\n\n const rows = [...table.getTopRows(), ...table.getCenterRows()];\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => rowHeight,\n overscan: 10,\n measureElement: (el) => el?.getBoundingClientRect().height ?? rowHeight,\n });\n\n const visibleColumns = table.getVisibleLeafColumns();\n const centerColumns = visibleColumns.filter((col) => !col.getIsPinned());\n\n const columnVirtualizer = useVirtualizer({\n count: centerColumns.length,\n estimateSize: (index) => centerColumns[index]?.getSize(),\n // `useAutoSizeColumns` solves a different problem (happens once when the column set changes)\n // and we don't need to measure the cells themselves, so we can use the default estimateSize.\n getScrollElement: () => scrollContainerRef.current,\n horizontal: true,\n overscan: 3,\n });\n\n const virtualColumns = columnVirtualizer.getVirtualItems();\n\n const virtualPaddingLeft = run(() => {\n if (columnVirtualizer && virtualColumns?.length > 0) {\n return virtualColumns[0]?.start ?? 0;\n }\n return null;\n });\n\n const virtualPaddingRight = run(() => {\n if (columnVirtualizer && virtualColumns?.length > 0) {\n return (\n columnVirtualizer.getTotalSize() - (virtualColumns[virtualColumns.length - 1]?.end ?? 0)\n );\n }\n return null;\n });\n\n // Check if any column has wrapping enabled\n const hasWrappedColumns = table.getAllLeafColumns().some((col) => col.columnDef.meta?.wrapText);\n\n // Create callback for remeasuring after resize\n const handleResizeEnd = useMemo(() => {\n if (!hasWrappedColumns) return undefined;\n return () => rowVirtualizer.measure();\n }, [hasWrappedColumns, rowVirtualizer]);\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 // Only handle arrow keys if we're in the cell itself, not in an interactive element\n const target = e.target as HTMLElement;\n if (target.tagName === 'TD') {\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 const selector = `[data-grid-cell-row=\"${next.row}\"][data-grid-cell-col=\"${next.col}\"]`;\n const nextCell = tableRef.current?.querySelector(selector) as HTMLElement | null;\n nextCell?.focus();\n }\n };\n\n const virtualRows = rowVirtualizer.getVirtualItems();\n\n const headerGroups = table.getHeaderGroups();\n\n const leafHeaderGroup = headerGroups[headerGroups.length - 1];\n\n const leftPinnedHeaders = leafHeaderGroup.headers.filter(\n (header) => header.column.getIsPinned() === 'left',\n );\n const centerHeaders = leafHeaderGroup.headers.filter((header) => !header.column.getIsPinned());\n\n const isTableResizing = leafHeaderGroup.headers.some((header) => header.column.getIsResizing());\n\n // We toggle this here instead of in the parent since this component logically manages all UI for the table.\n useEffect(() => {\n document.body.classList.toggle('pl-ui-no-user-select', isTableResizing);\n }, [isTableResizing]);\n\n const hasAutoSized = useAutoSizeColumns(table, tableRef, filters);\n\n // Re-measure the virtualizer when auto-sizing completes\n useEffect(() => {\n if (hasAutoSized) {\n columnVirtualizer.measure();\n }\n }, [columnVirtualizer, hasAutoSized]);\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={scrollContainerRef}\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={{ display: 'grid', tableLayout: 'fixed' }}\n aria-label={title}\n role=\"grid\"\n >\n <thead\n style={{\n display: 'grid',\n position: 'sticky',\n top: 0,\n zIndex: 1,\n }}\n >\n <tr\n key={leafHeaderGroup.id}\n style={{ display: 'flex', width: `${table.getTotalSize()}px` }}\n >\n {/* Left pinned columns */}\n {leftPinnedHeaders.map((header) => {\n return (\n <TanstackTableHeaderCell\n key={header.id}\n header={header}\n filters={filters}\n table={table}\n handleResizeEnd={handleResizeEnd}\n isPinned=\"left\"\n />\n );\n })}\n\n {/* Virtual padding for left side of center columns */}\n {virtualPaddingLeft ? (\n <th style={{ display: 'flex', width: virtualPaddingLeft }} />\n ) : null}\n\n {/* Virtualized center columns */}\n {virtualColumns.map((virtualColumn) => {\n const header = centerHeaders[virtualColumn.index];\n if (!header) return null;\n\n return (\n <TanstackTableHeaderCell\n key={header.id}\n header={header}\n filters={filters}\n table={table}\n handleResizeEnd={handleResizeEnd}\n isPinned={false}\n />\n );\n })}\n\n {/* Virtual padding for right side of center columns */}\n {virtualPaddingRight ? (\n <th style={{ display: 'flex', width: virtualPaddingRight }} />\n ) : null}\n </tr>\n </thead>\n <tbody\n style={{\n display: 'grid',\n height: `${rowVirtualizer.getTotalSize()}px`,\n position: 'relative',\n }}\n >\n {virtualRows.map((virtualRow) => {\n const row = rows[virtualRow.index];\n const rowIdx = virtualRow.index;\n const leftPinnedCells = row.getLeftVisibleCells();\n const centerCells = row.getCenterVisibleCells();\n\n let currentColIdx = 0;\n\n return (\n <tr\n key={row.id}\n ref={(node) => rowVirtualizer.measureElement(node)}\n data-index={virtualRow.index}\n style={{\n display: 'flex',\n position: 'absolute',\n transform: `translateY(${virtualRow.start}px)`,\n width: `${table.getTotalSize()}px`,\n }}\n >\n {leftPinnedCells.map((cell) => {\n const colIdx = currentColIdx++;\n const canSort = cell.column.getCanSort();\n const canFilter = cell.column.getCanFilter();\n const wrapText = cell.column.columnDef.meta?.wrapText ?? false;\n\n return (\n <TableCell\n key={cell.id}\n cell={cell}\n rowIdx={rowIdx}\n colIdx={colIdx}\n canSort={canSort}\n canFilter={canFilter}\n wrapText={wrapText}\n handleGridKeyDown={handleGridKeyDown}\n />\n );\n })}\n\n {virtualPaddingLeft ? (\n <td style={{ display: 'flex', width: virtualPaddingLeft }} />\n ) : null}\n\n {virtualColumns.map((virtualColumn) => {\n const cell = centerCells[virtualColumn.index];\n if (!cell) return null;\n\n const colIdx = currentColIdx++;\n const canSort = cell.column.getCanSort();\n const canFilter = cell.column.getCanFilter();\n const wrapText = cell.column.columnDef.meta?.wrapText ?? false;\n\n return (\n <TableCell\n key={cell.id}\n cell={cell}\n rowIdx={rowIdx}\n colIdx={colIdx}\n canSort={canSort}\n canFilter={canFilter}\n wrapText={wrapText}\n handleGridKeyDown={handleGridKeyDown}\n />\n );\n })}\n\n {virtualPaddingRight ? (\n <td style={{ display: 'flex', width: virtualPaddingRight }} />\n ) : null}\n </tr>\n );\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.className - The class name to apply to the card\n * @param params.style - The style to apply to the card\n * @param params.singularLabel - The singular label for a single row in the table, e.g. \"student\"\n * @param params.pluralLabel - The plural label for multiple rows in the table, e.g. \"students\"\n * @param params.headerButtons - The buttons to display in the header\n * @param params.columnManager - Optional configuration for the column manager. See {@link ColumnManager} for more details.\n * @param params.columnManager.buttons - The buttons to display next to the column manager (View button)\n * @param params.columnManager.topContent - Optional content to display at the top of the column manager (View) dropdown menu\n * @param params.globalFilter - Configuration for the global filter\n * @param params.globalFilter.placeholder - Placeholder text for the search input\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 singularLabel,\n pluralLabel,\n headerButtons,\n columnManager,\n globalFilter,\n tableOptions,\n downloadButtonOptions,\n className,\n ...divProps\n}: {\n table: Table<RowDataModel>;\n title: string;\n singularLabel: string;\n pluralLabel: string;\n headerButtons?: JSX.Element;\n columnManager?: {\n buttons?: JSX.Element;\n topContent?: JSX.Element;\n };\n globalFilter: {\n placeholder: string;\n };\n tableOptions: Partial<Omit<TanstackTableProps<RowDataModel>, 'table'>>;\n downloadButtonOptions?: Omit<\n TanstackTableDownloadButtonProps<RowDataModel>,\n 'table' | 'singularLabel' | 'pluralLabel'\n > & { pluralLabel?: string; singularLabel?: string };\n} & Omit<ComponentProps<'div'>, 'class'>) {\n const searchInputRef = useRef<HTMLInputElement>(null);\n\n const [inputValue, setInputValue] = useState(\n () => (table.getState().globalFilter as string) ?? '',\n );\n\n // Debounce the filter update\n const debouncedSetFilter = useDebouncedCallback((value: string) => {\n table.setGlobalFilter(value);\n }, 150);\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={clsx('card d-flex flex-column', className)} {...divProps}>\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\n table={table}\n pluralLabel={pluralLabel}\n singularLabel={singularLabel}\n {...downloadButtonOptions}\n />\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=\"position-relative w-100\" style={{ maxWidth: 'min(400px, 100%)' }}>\n <input\n ref={searchInputRef}\n type=\"text\"\n class=\"form-control pl-ui-tanstack-table-search-input pl-ui-tanstack-table-focusable-shadow\"\n aria-label={globalFilter.placeholder}\n placeholder={globalFilter.placeholder}\n value={inputValue}\n autoComplete=\"off\"\n onInput={(e) => {\n if (!(e.target instanceof HTMLInputElement)) return;\n const value = e.target.value;\n setInputValue(value);\n debouncedSetFilter(value);\n }}\n />\n {inputValue && (\n <OverlayTrigger overlay={<Tooltip>Clear search</Tooltip>}>\n <button\n type=\"button\"\n class=\"btn btn-floating-icon\"\n aria-label=\"Clear search\"\n onClick={() => {\n setInputValue('');\n debouncedSetFilter.cancel();\n table.setGlobalFilter('');\n }}\n >\n <i class=\"bi bi-x-circle-fill\" aria-hidden=\"true\" />\n </button>\n </OverlayTrigger>\n )}\n </div>\n <div class=\"d-flex flex-wrap flex-row align-items-center gap-2\">\n <ColumnManager table={table} topContent={columnManager?.topContent} />\n {columnManager?.buttons}\n </div>\n <div class=\"ms-auto text-muted text-nowrap\">\n Showing {displayedCount} of {totalCount} {totalCount === 1 ? singularLabel : pluralLabel}\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
+ {"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 { useVirtualizer } from '@tanstack/react-virtual';\nimport type { Cell, Header, Row, Table } from '@tanstack/table-core';\nimport clsx from 'clsx';\nimport type { ComponentChildren } from 'preact';\nimport { useEffect, useMemo, useRef, useState } from 'preact/hooks';\nimport type { JSX } from 'preact/jsx-runtime';\nimport OverlayTrigger from 'react-bootstrap/OverlayTrigger';\nimport Tooltip from 'react-bootstrap/Tooltip';\nimport { useDebouncedCallback } from 'use-debounce';\n\nimport type { ComponentProps } from '@prairielearn/preact-cjs';\nimport { run } from '@prairielearn/run';\n\nimport { ColumnManager } from './ColumnManager.js';\nimport {\n TanstackTableDownloadButton,\n type TanstackTableDownloadButtonProps,\n} from './TanstackTableDownloadButton.js';\nimport { TanstackTableHeaderCell } from './TanstackTableHeaderCell.js';\nimport { useAutoSizeColumns } from './useAutoSizeColumns.js';\n\nfunction TableCell<RowDataModel>({\n cell,\n rowIdx,\n colIdx,\n canSort,\n canFilter,\n wrapText,\n handleGridKeyDown,\n}: {\n cell: Cell<RowDataModel, unknown>;\n rowIdx: number;\n colIdx: number;\n canSort: boolean;\n canFilter: boolean;\n wrapText: boolean;\n handleGridKeyDown: (e: KeyboardEvent, rowIdx: number, colIdx: number) => void;\n}) {\n return (\n <td\n key={cell.id}\n tabIndex={0}\n data-grid-cell-row={rowIdx}\n data-grid-cell-col={colIdx}\n class={clsx(!canSort && !canFilter && 'text-center')}\n style={{\n display: 'flex',\n width: cell.column.getSize(),\n minWidth: 0,\n maxWidth: cell.column.getSize(),\n flexShrink: 0,\n position: cell.column.getIsPinned() === 'left' ? 'sticky' : undefined,\n left: cell.column.getIsPinned() === 'left' ? cell.column.getStart() : undefined,\n verticalAlign: 'middle',\n }}\n onKeyDown={(e) => handleGridKeyDown(e, rowIdx, colIdx)}\n >\n <div\n style={{\n display: 'block',\n minWidth: 0,\n maxWidth: '100%',\n overflow: wrapText ? 'visible' : 'hidden',\n textOverflow: wrapText ? undefined : 'ellipsis',\n whiteSpace: wrapText ? 'normal' : 'nowrap',\n flex: '1 1 0%',\n width: 0, // Allow flex to control width, but start from 0\n }}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </div>\n </td>\n );\n}\n\nconst DefaultNoResultsState = (\n <TanstackTableEmptyState iconName=\"bi-search\">\n No results found matching your search criteria.\n </TanstackTableEmptyState>\n);\n\nconst DefaultEmptyState = (\n <TanstackTableEmptyState iconName=\"bi-eye-slash\">No results found.</TanstackTableEmptyState>\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 scrollRef?: React.RefObject<HTMLDivElement> | null;\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 * @param params.scrollRef - Optional ref that will be attached to the scroll container element.\n */\nexport function TanstackTable<RowDataModel>({\n table,\n title,\n filters = DEFAULT_FILTER_MAP,\n rowHeight = 42,\n noResultsState = DefaultNoResultsState,\n emptyState = DefaultEmptyState,\n scrollRef,\n}: TanstackTableProps<RowDataModel>) {\n const parentRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLDivElement>(null);\n const scrollContainerRef = scrollRef ?? parentRef;\n\n const rows = [...table.getTopRows(), ...table.getCenterRows()];\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => rowHeight,\n overscan: 10,\n measureElement: (el) => el?.getBoundingClientRect().height ?? rowHeight,\n });\n\n const visibleColumns = table.getVisibleLeafColumns();\n const centerColumns = visibleColumns.filter((col) => !col.getIsPinned());\n\n const columnVirtualizer = useVirtualizer({\n count: centerColumns.length,\n estimateSize: (index) => centerColumns[index]?.getSize(),\n // `useAutoSizeColumns` solves a different problem (happens once when the column set changes)\n // and we don't need to measure the cells themselves, so we can use the default estimateSize.\n getScrollElement: () => scrollContainerRef.current,\n horizontal: true,\n overscan: 3,\n });\n\n const virtualColumns = columnVirtualizer.getVirtualItems();\n\n const virtualPaddingLeft = run(() => {\n if (columnVirtualizer && virtualColumns?.length > 0) {\n return virtualColumns[0]?.start ?? 0;\n }\n return null;\n });\n\n const virtualPaddingRight = run(() => {\n if (columnVirtualizer && virtualColumns?.length > 0) {\n return (\n columnVirtualizer.getTotalSize() - (virtualColumns[virtualColumns.length - 1]?.end ?? 0)\n );\n }\n return null;\n });\n\n // Check if any column has wrapping enabled\n const hasWrappedColumns = table.getAllLeafColumns().some((col) => col.columnDef.meta?.wrapText);\n\n // Create callback for remeasuring after resize\n const handleResizeEnd = useMemo(() => {\n if (!hasWrappedColumns) return undefined;\n return () => rowVirtualizer.measure();\n }, [hasWrappedColumns, rowVirtualizer]);\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 // Only handle arrow keys if we're in the cell itself, not in an interactive element\n const target = e.target as HTMLElement;\n if (target.tagName === 'TD') {\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 const selector = `[data-grid-cell-row=\"${next.row}\"][data-grid-cell-col=\"${next.col}\"]`;\n const nextCell = tableRef.current?.querySelector(selector) as HTMLElement | null;\n nextCell?.focus();\n }\n };\n\n const virtualRows = rowVirtualizer.getVirtualItems();\n\n const headerGroups = table.getHeaderGroups();\n\n const leafHeaderGroup = headerGroups[headerGroups.length - 1];\n\n const leftPinnedHeaders = leafHeaderGroup.headers.filter(\n (header) => header.column.getIsPinned() === 'left',\n );\n const centerHeaders = leafHeaderGroup.headers.filter((header) => !header.column.getIsPinned());\n\n const isTableResizing = leafHeaderGroup.headers.some((header) => header.column.getIsResizing());\n\n // We toggle this here instead of in the parent since this component logically manages all UI for the table.\n useEffect(() => {\n document.body.classList.toggle('pl-ui-no-user-select', isTableResizing);\n }, [isTableResizing]);\n\n const hasAutoSized = useAutoSizeColumns(table, tableRef, filters);\n\n // Re-measure the virtualizer when auto-sizing completes\n useEffect(() => {\n if (hasAutoSized) {\n columnVirtualizer.measure();\n }\n }, [columnVirtualizer, hasAutoSized]);\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={scrollContainerRef}\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={{ display: 'grid', tableLayout: 'fixed' }}\n aria-label={title}\n role=\"grid\"\n >\n <thead\n class=\"position-sticky top-0 w-100 border-top\"\n style={{\n display: 'grid',\n zIndex: 1,\n borderBottom: 'var(--bs-border-width) solid black',\n }}\n >\n <tr\n key={leafHeaderGroup.id}\n class=\"d-flex w-100\"\n style={{ minWidth: `${table.getTotalSize()}px` }}\n >\n {/* Left pinned columns */}\n {leftPinnedHeaders.map((header) => {\n return (\n <TanstackTableHeaderCell\n key={header.id}\n header={header}\n filters={filters}\n table={table}\n handleResizeEnd={handleResizeEnd}\n isPinned=\"left\"\n />\n );\n })}\n\n {/* Virtual padding for left side of center columns */}\n {virtualPaddingLeft ? (\n <th style={{ display: 'flex', width: virtualPaddingLeft }} />\n ) : null}\n\n {/* Virtualized center columns */}\n {virtualColumns.map((virtualColumn) => {\n const header = centerHeaders[virtualColumn.index];\n if (!header) return null;\n\n return (\n <TanstackTableHeaderCell\n key={header.id}\n header={header}\n filters={filters}\n table={table}\n handleResizeEnd={handleResizeEnd}\n isPinned={false}\n />\n );\n })}\n\n {/* Virtual padding for right side of center columns */}\n {virtualPaddingRight ? (\n <th style={{ display: 'flex', width: virtualPaddingRight }} />\n ) : null}\n\n {/* Filler to span remaining width */}\n <th\n tabIndex={-1}\n class=\"d-flex flex-grow-1 p-0\"\n style={{ minWidth: 0 }}\n aria-hidden=\"true\"\n />\n </tr>\n </thead>\n <tbody\n class=\"position-relative w-100\"\n style={{\n display: 'grid',\n height: `${rowVirtualizer.getTotalSize()}px`,\n }}\n >\n {virtualRows.map((virtualRow) => {\n const row = rows[virtualRow.index];\n const rowIdx = virtualRow.index;\n const leftPinnedCells = row.getLeftVisibleCells();\n const centerCells = row.getCenterVisibleCells();\n\n let currentColIdx = 0;\n\n return (\n <tr\n key={row.id}\n ref={(node) => rowVirtualizer.measureElement(node)}\n data-index={virtualRow.index}\n class=\"d-flex position-absolute w-100\"\n style={{\n transform: `translateY(${virtualRow.start}px)`,\n minWidth: `${table.getTotalSize()}px`,\n }}\n >\n {leftPinnedCells.map((cell) => {\n const colIdx = currentColIdx++;\n const canSort = cell.column.getCanSort();\n const canFilter = cell.column.getCanFilter();\n const wrapText = cell.column.columnDef.meta?.wrapText ?? false;\n\n return (\n <TableCell\n key={cell.id}\n cell={cell}\n rowIdx={rowIdx}\n colIdx={colIdx}\n canSort={canSort}\n canFilter={canFilter}\n wrapText={wrapText}\n handleGridKeyDown={handleGridKeyDown}\n />\n );\n })}\n\n {virtualPaddingLeft ? (\n <td style={{ display: 'flex', width: virtualPaddingLeft }} />\n ) : null}\n\n {virtualColumns.map((virtualColumn) => {\n const cell = centerCells[virtualColumn.index];\n if (!cell) return null;\n\n const colIdx = currentColIdx++;\n const canSort = cell.column.getCanSort();\n const canFilter = cell.column.getCanFilter();\n const wrapText = cell.column.columnDef.meta?.wrapText ?? false;\n\n return (\n <TableCell\n key={cell.id}\n cell={cell}\n rowIdx={rowIdx}\n colIdx={colIdx}\n canSort={canSort}\n canFilter={canFilter}\n wrapText={wrapText}\n handleGridKeyDown={handleGridKeyDown}\n />\n );\n })}\n\n {virtualPaddingRight ? (\n <td style={{ display: 'flex', width: virtualPaddingRight }} />\n ) : null}\n\n {/* Filler to span remaining width */}\n <td\n tabIndex={-1}\n class=\"d-flex flex-grow-1 p-0\"\n style={{ minWidth: 0 }}\n aria-hidden=\"true\"\n />\n </tr>\n );\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.className - The class name to apply to the card\n * @param params.style - The style to apply to the card\n * @param params.singularLabel - The singular label for a single row in the table, e.g. \"student\"\n * @param params.pluralLabel - The plural label for multiple rows in the table, e.g. \"students\"\n * @param params.headerButtons - The buttons to display in the header\n * @param params.columnManager - Optional configuration for the column manager. See {@link ColumnManager} for more details.\n * @param params.columnManager.buttons - The buttons to display next to the column manager (View button)\n * @param params.columnManager.topContent - Optional content to display at the top of the column manager (View) dropdown menu\n * @param params.globalFilter - Configuration for the global filter\n * @param params.globalFilter.placeholder - Placeholder text for the search input\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 singularLabel,\n pluralLabel,\n headerButtons,\n columnManager,\n globalFilter,\n tableOptions,\n downloadButtonOptions,\n className,\n ...divProps\n}: {\n table: Table<RowDataModel>;\n title: string;\n singularLabel: string;\n pluralLabel: string;\n headerButtons?: JSX.Element;\n columnManager?: {\n buttons?: JSX.Element;\n topContent?: JSX.Element;\n };\n globalFilter: {\n placeholder: string;\n };\n tableOptions: Partial<Omit<TanstackTableProps<RowDataModel>, 'table'>>;\n downloadButtonOptions?: Omit<\n TanstackTableDownloadButtonProps<RowDataModel>,\n 'table' | 'singularLabel' | 'pluralLabel'\n > & { pluralLabel?: string; singularLabel?: string };\n} & Omit<ComponentProps<'div'>, 'class'>) {\n const searchInputRef = useRef<HTMLInputElement>(null);\n\n const [inputValue, setInputValue] = useState(\n () => (table.getState().globalFilter as string) ?? '',\n );\n\n // Debounce the filter update\n const debouncedSetFilter = useDebouncedCallback((value: string) => {\n table.setGlobalFilter(value);\n }, 150);\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={clsx('card d-flex flex-column', className)} {...divProps}>\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\n table={table}\n pluralLabel={pluralLabel}\n singularLabel={singularLabel}\n {...downloadButtonOptions}\n />\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=\"position-relative w-100\" style={{ maxWidth: 'min(400px, 100%)' }}>\n <input\n ref={searchInputRef}\n type=\"text\"\n class=\"form-control pl-ui-tanstack-table-search-input pl-ui-tanstack-table-focusable-shadow\"\n aria-label={globalFilter.placeholder}\n placeholder={globalFilter.placeholder}\n value={inputValue}\n autoComplete=\"off\"\n onInput={(e) => {\n if (!(e.target instanceof HTMLInputElement)) return;\n const value = e.target.value;\n setInputValue(value);\n debouncedSetFilter(value);\n }}\n />\n {inputValue && (\n <OverlayTrigger overlay={<Tooltip>Clear search</Tooltip>}>\n <button\n type=\"button\"\n class=\"btn btn-floating-icon\"\n aria-label=\"Clear search\"\n onClick={() => {\n setInputValue('');\n debouncedSetFilter.cancel();\n table.setGlobalFilter('');\n }}\n >\n <i class=\"bi bi-x-circle-fill\" aria-hidden=\"true\" />\n </button>\n </OverlayTrigger>\n )}\n </div>\n <div class=\"d-flex flex-wrap flex-row align-items-center gap-2\">\n <ColumnManager table={table} topContent={columnManager?.topContent} />\n {columnManager?.buttons}\n </div>\n <div class=\"ms-auto text-muted text-nowrap\">\n Showing {displayedCount} of {totalCount} {totalCount === 1 ? singularLabel : pluralLabel}\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":"TanstackTableHeaderCell.d.ts","sourceRoot":"","sources":["../../src/components/TanstackTableHeaderCell.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAiB,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAEzE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AA8F9C,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,EACpD,MAAM,EACN,OAAO,EACP,KAAK,EACL,eAAe,EACf,QAAQ,EACR,eAAuB,GACxB,EAAE;IACD,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,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;IAC3F,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,eA+FA"}
1
+ {"version":3,"file":"TanstackTableHeaderCell.d.ts","sourceRoot":"","sources":["../../src/components/TanstackTableHeaderCell.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAiB,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAEzE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AA8F9C,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,EACpD,MAAM,EACN,OAAO,EACP,KAAK,EACL,eAAe,EACf,QAAQ,EACR,eAAuB,GACxB,EAAE;IACD,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,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;IAC3F,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,eA6FA"}
@@ -77,7 +77,6 @@ export function TanstackTableHeaderCell({ header, filters, table, handleResizeEn
77
77
  top: 0,
78
78
  zIndex: isPinned === 'left' ? 2 : 1,
79
79
  left: isPinned === 'left' ? header.getStart() : undefined,
80
- 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)',
81
80
  };
82
81
  const isNormalColumn = canSort || canFilter;
83
82
  return (_jsxs("th", { "data-column-id": header.column.id, 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 flex-grow-1', isNormalColumn ? 'justify-content-between' : 'justify-content-center'), style: {
@@ -1 +1 @@
1
- {"version":3,"file":"TanstackTableHeaderCell.js","sourceRoot":"","sources":["../../src/components/TanstackTableHeaderCell.tsx"],"names":[],"mappings":"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","sourcesContent":["import { flexRender } from '@tanstack/react-table';\nimport type { Header, SortDirection, Table } from '@tanstack/table-core';\nimport clsx from 'clsx';\nimport type { JSX } from 'preact/jsx-runtime';\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 onResizeEnd,\n}: {\n header: Header<RowDataModel, unknown>;\n setColumnSizing: Table<RowDataModel>['setColumnSizing'];\n onResizeEnd?: () => void;\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 onMouseUp={onResizeEnd}\n onTouchStart={header.getResizeHandler()}\n onTouchEnd={onResizeEnd}\n onKeyDown={handleKeyDown}\n />\n </div>\n );\n}\n\n/**\n * Helper function to get aria-sort value\n */\nfunction 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\nexport function TanstackTableHeaderCell<RowDataModel>({\n header,\n filters,\n table,\n handleResizeEnd,\n isPinned,\n measurementMode = false,\n}: {\n header: Header<RowDataModel, unknown>;\n filters: Record<string, (props: { header: Header<RowDataModel, unknown> }) => JSX.Element>;\n table: Table<RowDataModel>;\n handleResizeEnd?: () => void;\n isPinned: 'left' | false;\n measurementMode?: boolean;\n}) {\n const sortDirection = header.column.getIsSorted();\n const canSort = header.column.getCanSort();\n const canFilter = header.column.getCanFilter();\n const columnName =\n header.column.columnDef.meta?.label ??\n (typeof header.column.columnDef.header === 'string'\n ? header.column.columnDef.header\n : header.column.id);\n\n // In measurement mode, we don't want to set the size of the header from tanstack.\n const headerSize = measurementMode ? undefined : header.getSize();\n const style: JSX.CSSProperties = {\n display: 'flex',\n width: headerSize,\n minWidth: 0,\n maxWidth: headerSize,\n flexShrink: 0,\n position: isPinned === 'left' ? 'sticky' : 'relative',\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 const isNormalColumn = canSort || canFilter;\n\n return (\n <th\n key={header.id}\n data-column-id={header.column.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 flex-grow-1',\n isNormalColumn ? 'justify-content-between' : 'justify-content-center',\n )}\n style={{\n minWidth: 0,\n }}\n >\n <div\n class={clsx(\n 'text-nowrap text-start',\n // e.g. checkboxes\n !isNormalColumn && 'd-flex align-items-center justify-content-center',\n )}\n style={{\n minWidth: 0,\n flex: '1 1 0%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n background: 'transparent',\n border: 'none',\n }}\n >\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n {canSort && (\n <span class=\"visually-hidden\">, {getAriaSort(sortDirection)}, click to sort</span>\n )}\n </div>\n\n {(canSort || canFilter) && (\n <div class=\"d-flex align-items-center\" style={{ flexShrink: 0 }}>\n {canSort && (\n <button\n type=\"button\"\n class=\"btn btn-link text-muted p-0\"\n aria-label={`Sort ${columnName.toLowerCase()}, current sort is ${getAriaSort(sortDirection)}`}\n title={`Sort ${columnName.toLowerCase()}`}\n onClick={header.column.getToggleSortingHandler()}\n >\n <SortIcon sortMethod={sortDirection} />\n </button>\n )}\n {canFilter && filters[header.column.id]?.({ header })}\n </div>\n )}\n </div>\n {header.column.getCanResize() && (\n <ResizeHandle\n header={header}\n setColumnSizing={table.setColumnSizing}\n onResizeEnd={handleResizeEnd}\n />\n )}\n </th>\n );\n}\n"]}
1
+ {"version":3,"file":"TanstackTableHeaderCell.js","sourceRoot":"","sources":["../../src/components/TanstackTableHeaderCell.tsx"],"names":[],"mappings":"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","sourcesContent":["import { flexRender } from '@tanstack/react-table';\nimport type { Header, SortDirection, Table } from '@tanstack/table-core';\nimport clsx from 'clsx';\nimport type { JSX } from 'preact/jsx-runtime';\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 onResizeEnd,\n}: {\n header: Header<RowDataModel, unknown>;\n setColumnSizing: Table<RowDataModel>['setColumnSizing'];\n onResizeEnd?: () => void;\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 onMouseUp={onResizeEnd}\n onTouchStart={header.getResizeHandler()}\n onTouchEnd={onResizeEnd}\n onKeyDown={handleKeyDown}\n />\n </div>\n );\n}\n\n/**\n * Helper function to get aria-sort value\n */\nfunction 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\nexport function TanstackTableHeaderCell<RowDataModel>({\n header,\n filters,\n table,\n handleResizeEnd,\n isPinned,\n measurementMode = false,\n}: {\n header: Header<RowDataModel, unknown>;\n filters: Record<string, (props: { header: Header<RowDataModel, unknown> }) => JSX.Element>;\n table: Table<RowDataModel>;\n handleResizeEnd?: () => void;\n isPinned: 'left' | false;\n measurementMode?: boolean;\n}) {\n const sortDirection = header.column.getIsSorted();\n const canSort = header.column.getCanSort();\n const canFilter = header.column.getCanFilter();\n const columnName =\n header.column.columnDef.meta?.label ??\n (typeof header.column.columnDef.header === 'string'\n ? header.column.columnDef.header\n : header.column.id);\n\n // In measurement mode, we don't want to set the size of the header from tanstack.\n const headerSize = measurementMode ? undefined : header.getSize();\n const style: JSX.CSSProperties = {\n display: 'flex',\n width: headerSize,\n minWidth: 0,\n maxWidth: headerSize,\n flexShrink: 0,\n position: isPinned === 'left' ? 'sticky' : 'relative',\n top: 0,\n zIndex: isPinned === 'left' ? 2 : 1,\n left: isPinned === 'left' ? header.getStart() : undefined,\n };\n\n const isNormalColumn = canSort || canFilter;\n\n return (\n <th\n key={header.id}\n data-column-id={header.column.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 flex-grow-1',\n isNormalColumn ? 'justify-content-between' : 'justify-content-center',\n )}\n style={{\n minWidth: 0,\n }}\n >\n <div\n class={clsx(\n 'text-nowrap text-start',\n // e.g. checkboxes\n !isNormalColumn && 'd-flex align-items-center justify-content-center',\n )}\n style={{\n minWidth: 0,\n flex: '1 1 0%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n background: 'transparent',\n border: 'none',\n }}\n >\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n {canSort && (\n <span class=\"visually-hidden\">, {getAriaSort(sortDirection)}, click to sort</span>\n )}\n </div>\n\n {(canSort || canFilter) && (\n <div class=\"d-flex align-items-center\" style={{ flexShrink: 0 }}>\n {canSort && (\n <button\n type=\"button\"\n class=\"btn btn-link text-muted p-0\"\n aria-label={`Sort ${columnName.toLowerCase()}, current sort is ${getAriaSort(sortDirection)}`}\n title={`Sort ${columnName.toLowerCase()}`}\n onClick={header.column.getToggleSortingHandler()}\n >\n <SortIcon sortMethod={sortDirection} />\n </button>\n )}\n {canFilter && filters[header.column.id]?.({ header })}\n </div>\n )}\n </div>\n {header.column.getCanResize() && (\n <ResizeHandle\n header={header}\n setColumnSizing={table.setColumnSizing}\n onResizeEnd={handleResizeEnd}\n />\n )}\n </th>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/ui",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -284,16 +284,17 @@ export function TanstackTable<RowDataModel>({
284
284
  role="grid"
285
285
  >
286
286
  <thead
287
+ class="position-sticky top-0 w-100 border-top"
287
288
  style={{
288
289
  display: 'grid',
289
- position: 'sticky',
290
- top: 0,
291
290
  zIndex: 1,
291
+ borderBottom: 'var(--bs-border-width) solid black',
292
292
  }}
293
293
  >
294
294
  <tr
295
295
  key={leafHeaderGroup.id}
296
- style={{ display: 'flex', width: `${table.getTotalSize()}px` }}
296
+ class="d-flex w-100"
297
+ style={{ minWidth: `${table.getTotalSize()}px` }}
297
298
  >
298
299
  {/* Left pinned columns */}
299
300
  {leftPinnedHeaders.map((header) => {
@@ -335,13 +336,21 @@ export function TanstackTable<RowDataModel>({
335
336
  {virtualPaddingRight ? (
336
337
  <th style={{ display: 'flex', width: virtualPaddingRight }} />
337
338
  ) : null}
339
+
340
+ {/* Filler to span remaining width */}
341
+ <th
342
+ tabIndex={-1}
343
+ class="d-flex flex-grow-1 p-0"
344
+ style={{ minWidth: 0 }}
345
+ aria-hidden="true"
346
+ />
338
347
  </tr>
339
348
  </thead>
340
349
  <tbody
350
+ class="position-relative w-100"
341
351
  style={{
342
352
  display: 'grid',
343
353
  height: `${rowVirtualizer.getTotalSize()}px`,
344
- position: 'relative',
345
354
  }}
346
355
  >
347
356
  {virtualRows.map((virtualRow) => {
@@ -357,11 +366,10 @@ export function TanstackTable<RowDataModel>({
357
366
  key={row.id}
358
367
  ref={(node) => rowVirtualizer.measureElement(node)}
359
368
  data-index={virtualRow.index}
369
+ class="d-flex position-absolute w-100"
360
370
  style={{
361
- display: 'flex',
362
- position: 'absolute',
363
371
  transform: `translateY(${virtualRow.start}px)`,
364
- width: `${table.getTotalSize()}px`,
372
+ minWidth: `${table.getTotalSize()}px`,
365
373
  }}
366
374
  >
367
375
  {leftPinnedCells.map((cell) => {
@@ -414,6 +422,14 @@ export function TanstackTable<RowDataModel>({
414
422
  {virtualPaddingRight ? (
415
423
  <td style={{ display: 'flex', width: virtualPaddingRight }} />
416
424
  ) : null}
425
+
426
+ {/* Filler to span remaining width */}
427
+ <td
428
+ tabIndex={-1}
429
+ class="d-flex flex-grow-1 p-0"
430
+ style={{ minWidth: 0 }}
431
+ aria-hidden="true"
432
+ />
417
433
  </tr>
418
434
  );
419
435
  })}
@@ -131,8 +131,6 @@ export function TanstackTableHeaderCell<RowDataModel>({
131
131
  top: 0,
132
132
  zIndex: isPinned === 'left' ? 2 : 1,
133
133
  left: isPinned === 'left' ? header.getStart() : undefined,
134
- boxShadow:
135
- '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)',
136
134
  };
137
135
 
138
136
  const isNormalColumn = canSort || canFilter;