@prairielearn/ui 1.3.0 → 1.4.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 +22 -0
- package/README.md +4 -2
- package/dist/components/CategoricalColumnFilter.d.ts +7 -12
- package/dist/components/CategoricalColumnFilter.d.ts.map +1 -1
- package/dist/components/CategoricalColumnFilter.js +15 -11
- package/dist/components/CategoricalColumnFilter.js.map +1 -1
- package/dist/components/ColumnManager.d.ts +6 -3
- package/dist/components/ColumnManager.d.ts.map +1 -1
- package/dist/components/ColumnManager.js +98 -18
- package/dist/components/ColumnManager.js.map +1 -1
- package/dist/components/MultiSelectColumnFilter.d.ts +8 -12
- package/dist/components/MultiSelectColumnFilter.d.ts.map +1 -1
- package/dist/components/MultiSelectColumnFilter.js +21 -13
- package/dist/components/MultiSelectColumnFilter.js.map +1 -1
- package/dist/components/NumericInputColumnFilter.d.ts +13 -13
- package/dist/components/NumericInputColumnFilter.d.ts.map +1 -1
- package/dist/components/NumericInputColumnFilter.js +44 -15
- package/dist/components/NumericInputColumnFilter.js.map +1 -1
- package/dist/components/NumericInputColumnFilter.test.d.ts +2 -0
- package/dist/components/NumericInputColumnFilter.test.d.ts.map +1 -0
- package/dist/components/NumericInputColumnFilter.test.js +90 -0
- package/dist/components/NumericInputColumnFilter.test.js.map +1 -0
- package/dist/components/OverlayTrigger.d.ts +78 -0
- package/dist/components/OverlayTrigger.d.ts.map +1 -0
- package/dist/components/OverlayTrigger.js +89 -0
- package/dist/components/OverlayTrigger.js.map +1 -0
- package/dist/components/TanstackTable.d.ts +15 -4
- package/dist/components/TanstackTable.d.ts.map +1 -1
- package/dist/components/TanstackTable.js +148 -197
- package/dist/components/TanstackTable.js.map +1 -1
- package/dist/components/TanstackTableDownloadButton.d.ts +4 -2
- package/dist/components/TanstackTableDownloadButton.d.ts.map +1 -1
- package/dist/components/TanstackTableDownloadButton.js +4 -3
- package/dist/components/TanstackTableDownloadButton.js.map +1 -1
- package/dist/components/TanstackTableHeaderCell.d.ts +13 -0
- package/dist/components/TanstackTableHeaderCell.d.ts.map +1 -0
- package/dist/components/TanstackTableHeaderCell.js +98 -0
- package/dist/components/TanstackTableHeaderCell.js.map +1 -0
- package/dist/components/{TanstackTable.css → styles.css} +11 -6
- package/dist/components/useAutoSizeColumns.d.ts +17 -0
- package/dist/components/useAutoSizeColumns.d.ts.map +1 -0
- package/dist/components/useAutoSizeColumns.js +99 -0
- package/dist/components/useAutoSizeColumns.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/react-table.d.ts +13 -0
- package/dist/react-table.d.ts.map +1 -0
- package/dist/react-table.js +3 -0
- package/dist/react-table.js.map +1 -0
- package/package.json +2 -2
- package/src/components/CategoricalColumnFilter.tsx +28 -28
- package/src/components/ColumnManager.tsx +222 -46
- package/src/components/MultiSelectColumnFilter.tsx +45 -32
- package/src/components/NumericInputColumnFilter.test.ts +67 -19
- package/src/components/NumericInputColumnFilter.tsx +102 -42
- package/src/components/OverlayTrigger.tsx +168 -0
- package/src/components/TanstackTable.tsx +315 -363
- package/src/components/TanstackTableDownloadButton.tsx +8 -5
- package/src/components/TanstackTableHeaderCell.tsx +207 -0
- package/src/components/{TanstackTable.css → styles.css} +11 -6
- package/src/components/useAutoSizeColumns.tsx +168 -0
- package/src/index.ts +5 -0
- package/src/react-table.ts +17 -0
- package/tsconfig.json +1 -2
|
@@ -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 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
|
+
{"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 } from 'preact/hooks';\nimport type { JSX } from 'preact/jsx-runtime';\nimport OverlayTrigger from 'react-bootstrap/OverlayTrigger';\nimport Tooltip from 'react-bootstrap/Tooltip';\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.columnManagerButtons - The buttons to display next to the column manager (View button)\n * @param params.columnManagerTopContent - Optional content to display at the top of the column manager (View) dropdown menu\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 singularLabel,\n pluralLabel,\n headerButtons,\n columnManagerButtons,\n columnManagerTopContent,\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 columnManagerButtons?: JSX.Element;\n columnManagerTopContent?: 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<\n TanstackTableDownloadButtonProps<RowDataModel>,\n 'table' | 'singularLabel' | 'pluralLabel'\n >;\n} & Omit<ComponentProps<'div'>, 'class'>) {\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={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={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-floating-icon\"\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-flex flex-wrap flex-row align-items-center gap-2\">\n <ColumnManager table={table} topContent={columnManagerTopContent} />\n {columnManagerButtons}\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"]}
|
|
@@ -3,11 +3,13 @@ export interface TanstackTableDownloadButtonProps<RowDataModel> {
|
|
|
3
3
|
table: Table<RowDataModel>;
|
|
4
4
|
filenameBase: string;
|
|
5
5
|
mapRowToData: (row: RowDataModel) => Record<string, string | number | null> | null;
|
|
6
|
+
singularLabel: string;
|
|
6
7
|
pluralLabel: string;
|
|
7
8
|
}
|
|
8
9
|
/**
|
|
9
10
|
* @param params
|
|
10
|
-
* @param params.
|
|
11
|
+
* @param params.singularLabel - The singular label for a single row in the table, e.g. "student"
|
|
12
|
+
* @param params.pluralLabel - The plural label for multiple rows in the table, e.g. "students"
|
|
11
13
|
* @param params.table - The table model
|
|
12
14
|
* @param params.filenameBase - The base filename for the downloads
|
|
13
15
|
* @param params.mapRowToData - A function that maps a row to a record where the
|
|
@@ -15,5 +17,5 @@ export interface TanstackTableDownloadButtonProps<RowDataModel> {
|
|
|
15
17
|
* and should match the expected order of the columns in the CSV file. If the function returns null,
|
|
16
18
|
* the row will be skipped.
|
|
17
19
|
*/
|
|
18
|
-
export declare function TanstackTableDownloadButton<RowDataModel>({ table, filenameBase, mapRowToData, pluralLabel, }: TanstackTableDownloadButtonProps<RowDataModel>): import("original-preact").JSX.Element;
|
|
20
|
+
export declare function TanstackTableDownloadButton<RowDataModel>({ table, filenameBase, mapRowToData, singularLabel, pluralLabel, }: TanstackTableDownloadButtonProps<RowDataModel>): import("original-preact").JSX.Element;
|
|
19
21
|
//# sourceMappingURL=TanstackTableDownloadButton.d.ts.map
|
|
@@ -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
|
|
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,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AACD;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,EACxD,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,WAAW,GACZ,EAAE,gCAAgC,CAAC,YAAY,CAAC,yCA8GhD"}
|
|
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "@prairielearn/preact-cjs/jsx-runtime
|
|
|
2
2
|
import { downloadAsCSV, downloadAsJSON } from '@prairielearn/browser-utils';
|
|
3
3
|
/**
|
|
4
4
|
* @param params
|
|
5
|
-
* @param params.
|
|
5
|
+
* @param params.singularLabel - The singular label for a single row in the table, e.g. "student"
|
|
6
|
+
* @param params.pluralLabel - The plural label for multiple rows in the table, e.g. "students"
|
|
6
7
|
* @param params.table - The table model
|
|
7
8
|
* @param params.filenameBase - The base filename for the downloads
|
|
8
9
|
* @param params.mapRowToData - A function that maps a row to a record where the
|
|
@@ -10,7 +11,7 @@ import { downloadAsCSV, downloadAsJSON } from '@prairielearn/browser-utils';
|
|
|
10
11
|
* and should match the expected order of the columns in the CSV file. If the function returns null,
|
|
11
12
|
* the row will be skipped.
|
|
12
13
|
*/
|
|
13
|
-
export function TanstackTableDownloadButton({ table, filenameBase, mapRowToData, pluralLabel, }) {
|
|
14
|
+
export function TanstackTableDownloadButton({ table, filenameBase, mapRowToData, singularLabel, pluralLabel, }) {
|
|
14
15
|
const allRows = table.getCoreRowModel().rows.map((row) => row.original);
|
|
15
16
|
const allRowsJSON = allRows.map(mapRowToData).filter((row) => row !== null);
|
|
16
17
|
const filteredRows = table.getRowModel().rows.map((row) => row.original);
|
|
@@ -25,6 +26,6 @@ export function TanstackTableDownloadButton({ table, filenameBase, mapRowToData,
|
|
|
25
26
|
const csvRows = jsonRows.map((row) => Object.values(row));
|
|
26
27
|
downloadAsCSV(header, csvRows, filename);
|
|
27
28
|
}
|
|
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"] }) })] })] }));
|
|
29
|
+
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 ", selectedRowsJSON.length === 1 ? singularLabel : 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 ", selectedRowsJSON.length === 1 ? singularLabel : 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 ", filteredRowsJSON.length === 1 ? singularLabel : 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 ", filteredRowsJSON.length === 1 ? singularLabel : pluralLabel, " as JSON"] }) })] })] }));
|
|
29
30
|
}
|
|
30
31
|
//# 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;
|
|
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 singularLabel: string;\n pluralLabel: string;\n}\n/**\n * @param params\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.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 singularLabel,\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 {selectedRowsJSON.length === 1 ? singularLabel : 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 {selectedRowsJSON.length === 1 ? singularLabel : 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 {filteredRowsJSON.length === 1 ? singularLabel : 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 {filteredRowsJSON.length === 1 ? singularLabel : pluralLabel} as JSON\n </button>\n </li>\n </ul>\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Header, Table } from '@tanstack/table-core';
|
|
2
|
+
import type { JSX } from 'preact/jsx-runtime';
|
|
3
|
+
export declare function TanstackTableHeaderCell<RowDataModel>({ header, filters, table, handleResizeEnd, isPinned, measurementMode, }: {
|
|
4
|
+
header: Header<RowDataModel, unknown>;
|
|
5
|
+
filters: Record<string, (props: {
|
|
6
|
+
header: Header<RowDataModel, unknown>;
|
|
7
|
+
}) => JSX.Element>;
|
|
8
|
+
table: Table<RowDataModel>;
|
|
9
|
+
handleResizeEnd?: () => void;
|
|
10
|
+
isPinned: 'left' | false;
|
|
11
|
+
measurementMode?: boolean;
|
|
12
|
+
}): JSX.Element;
|
|
13
|
+
//# sourceMappingURL=TanstackTableHeaderCell.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@prairielearn/preact-cjs/jsx-runtime";
|
|
2
|
+
import { flexRender } from '@tanstack/react-table';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
function SortIcon({ sortMethod }) {
|
|
5
|
+
if (sortMethod === 'asc') {
|
|
6
|
+
return _jsx("i", { class: "bi bi-sort-up-alt", "aria-hidden": "true" });
|
|
7
|
+
}
|
|
8
|
+
else if (sortMethod === 'desc') {
|
|
9
|
+
return _jsx("i", { class: "bi bi-sort-down", "aria-hidden": "true" });
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
return _jsx("i", { class: "bi bi-arrow-down-up opacity-75 text-muted", "aria-hidden": "true" });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function ResizeHandle({ header, setColumnSizing, onResizeEnd, }) {
|
|
16
|
+
const minSize = header.column.columnDef.minSize ?? 0;
|
|
17
|
+
const maxSize = header.column.columnDef.maxSize ?? 0;
|
|
18
|
+
const handleKeyDown = (e) => {
|
|
19
|
+
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
const currentSize = header.getSize();
|
|
22
|
+
const increment = e.shiftKey ? 20 : 5; // Larger increment with Shift key
|
|
23
|
+
const newSize = e.key === 'ArrowLeft'
|
|
24
|
+
? Math.max(minSize, currentSize - increment)
|
|
25
|
+
: Math.min(maxSize, currentSize + increment);
|
|
26
|
+
setColumnSizing((prevSizing) => ({
|
|
27
|
+
...prevSizing,
|
|
28
|
+
[header.column.id]: newSize,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
else if (e.key === 'Home') {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
header.column.resetSize();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const columnName = typeof header.column.columnDef.header === 'string'
|
|
37
|
+
? header.column.columnDef.header
|
|
38
|
+
: header.column.id;
|
|
39
|
+
return (_jsx("div", { class: "py-1 h-100", style: { position: 'absolute', right: 0, top: 0, width: '4px' }, children: _jsx("div", { role: "separator", "aria-label": `Resize '${columnName}' column`, "aria-valuetext": `${header.getSize()}px`, "aria-orientation": "vertical", "aria-valuemin": minSize, "aria-valuemax": maxSize, "aria-valuenow": header.getSize(),
|
|
40
|
+
// eslint-disable-next-line jsx-a11y-x/no-noninteractive-tabindex
|
|
41
|
+
tabIndex: 0, class: "h-100", style: {
|
|
42
|
+
background: header.column.getIsResizing() ? 'var(--bs-primary)' : 'var(--bs-gray-400)',
|
|
43
|
+
cursor: 'col-resize',
|
|
44
|
+
transition: 'background-color 0.2s',
|
|
45
|
+
}, onMouseDown: header.getResizeHandler(), onMouseUp: onResizeEnd, onTouchStart: header.getResizeHandler(), onTouchEnd: onResizeEnd, onKeyDown: handleKeyDown }) }));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Helper function to get aria-sort value
|
|
49
|
+
*/
|
|
50
|
+
function getAriaSort(sortDirection) {
|
|
51
|
+
switch (sortDirection) {
|
|
52
|
+
case 'asc':
|
|
53
|
+
return 'ascending';
|
|
54
|
+
case 'desc':
|
|
55
|
+
return 'descending';
|
|
56
|
+
default:
|
|
57
|
+
return 'none';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function TanstackTableHeaderCell({ header, filters, table, handleResizeEnd, isPinned, measurementMode = false, }) {
|
|
61
|
+
const sortDirection = header.column.getIsSorted();
|
|
62
|
+
const canSort = header.column.getCanSort();
|
|
63
|
+
const canFilter = header.column.getCanFilter();
|
|
64
|
+
const columnName = header.column.columnDef.meta?.label ??
|
|
65
|
+
(typeof header.column.columnDef.header === 'string'
|
|
66
|
+
? header.column.columnDef.header
|
|
67
|
+
: header.column.id);
|
|
68
|
+
// In measurement mode, we don't want to set the size of the header from tanstack.
|
|
69
|
+
const headerSize = measurementMode ? undefined : header.getSize();
|
|
70
|
+
const style = {
|
|
71
|
+
display: 'flex',
|
|
72
|
+
width: headerSize,
|
|
73
|
+
minWidth: 0,
|
|
74
|
+
maxWidth: headerSize,
|
|
75
|
+
flexShrink: 0,
|
|
76
|
+
position: isPinned === 'left' ? 'sticky' : 'relative',
|
|
77
|
+
top: 0,
|
|
78
|
+
zIndex: isPinned === 'left' ? 2 : 1,
|
|
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
|
+
};
|
|
82
|
+
const isNormalColumn = canSort || canFilter;
|
|
83
|
+
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: {
|
|
84
|
+
minWidth: 0,
|
|
85
|
+
}, children: [_jsxs("div", { class: clsx('text-nowrap text-start',
|
|
86
|
+
// e.g. checkboxes
|
|
87
|
+
!isNormalColumn && 'd-flex align-items-center justify-content-center'), style: {
|
|
88
|
+
minWidth: 0,
|
|
89
|
+
flex: '1 1 0%',
|
|
90
|
+
overflow: 'hidden',
|
|
91
|
+
textOverflow: 'ellipsis',
|
|
92
|
+
background: 'transparent',
|
|
93
|
+
border: 'none',
|
|
94
|
+
}, children: [header.isPlaceholder
|
|
95
|
+
? null
|
|
96
|
+
: 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", style: { flexShrink: 0 }, children: [canSort && (_jsx("button", { type: "button", class: "btn btn-link text-muted p-0", "aria-label": `Sort ${columnName.toLowerCase()}, current sort is ${getAriaSort(sortDirection)}`, title: `Sort ${columnName.toLowerCase()}`, onClick: header.column.getToggleSortingHandler(), children: _jsx(SortIcon, { sortMethod: sortDirection }) })), canFilter && filters[header.column.id]?.({ header })] }))] }), header.column.getCanResize() && (_jsx(ResizeHandle, { header: header, setColumnSizing: table.setColumnSizing, onResizeEnd: handleResizeEnd }))] }, header.id));
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=TanstackTableHeaderCell.js.map
|
|
@@ -0,0 +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,13 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
/* Global styles for the PrairieLearn UI components. These should be included in any
|
|
2
|
+
page that uses the PrairieLearn UI components, and class names should not be directly referenced by consumers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
body.pl-ui-no-user-select {
|
|
2
6
|
user-select: none;
|
|
3
7
|
-webkit-user-select: none;
|
|
4
8
|
}
|
|
5
9
|
|
|
6
|
-
.tanstack-table-search-input {
|
|
10
|
+
.pl-ui-tanstack-table-search-input {
|
|
7
11
|
padding-right: 2.5rem;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
|
-
.
|
|
14
|
+
.btn.btn-floating-icon {
|
|
11
15
|
position: absolute;
|
|
12
16
|
right: 0;
|
|
13
17
|
top: 50%;
|
|
@@ -19,18 +23,19 @@ body.no-user-select {
|
|
|
19
23
|
text-decoration: none;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
.
|
|
26
|
+
.btn.btn-floating-icon:hover {
|
|
23
27
|
opacity: 1;
|
|
24
28
|
color: var(--bs-secondary);
|
|
25
29
|
text-decoration: none;
|
|
26
30
|
}
|
|
27
31
|
|
|
28
|
-
.
|
|
32
|
+
.btn.btn-floating-icon:focus {
|
|
29
33
|
opacity: 1;
|
|
30
34
|
color: var(--bs-secondary);
|
|
31
35
|
text-decoration: none;
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
/* https://react-bootstrap.github.io/docs/getting-started/theming/#new-variants-and-sizes */
|
|
34
39
|
.btn.btn-tanstack-table {
|
|
35
40
|
--bs-btn-color: var(--bs-body-color);
|
|
36
41
|
--bs-btn-bg: var(--bs-input-bg);
|
|
@@ -48,6 +53,6 @@ body.no-user-select {
|
|
|
48
53
|
--bs-btn-disabled-border-color: var(--bs-border-color);
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
.tanstack-table-focusable-shadow:not(:focus-visible) {
|
|
56
|
+
:is(.btn.btn-tanstack-table, .pl-ui-tanstack-table-focusable-shadow):not(:focus-visible) {
|
|
52
57
|
box-shadow: var(--bs-box-shadow-sm);
|
|
53
58
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Header, Table } from '@tanstack/react-table';
|
|
2
|
+
import type { RefObject } from 'preact';
|
|
3
|
+
import type { JSX } from 'preact/jsx-runtime';
|
|
4
|
+
/**
|
|
5
|
+
* Custom hook that automatically measures and sets column widths based on header content.
|
|
6
|
+
* Only measures columns that have `meta: { autoSize: true }` and don't have explicit sizes set.
|
|
7
|
+
* User resizes are preserved.
|
|
8
|
+
*
|
|
9
|
+
* @param table - The TanStack Table instance
|
|
10
|
+
* @param tableRef - Ref to the table container element
|
|
11
|
+
* @param filters - Optional filters map for rendering filter components in measurement
|
|
12
|
+
* @returns A boolean indicating whether the initial measurement has completed
|
|
13
|
+
*/
|
|
14
|
+
export declare function useAutoSizeColumns<TData>(table: Table<TData>, tableRef: RefObject<HTMLDivElement>, filters?: Record<string, (props: {
|
|
15
|
+
header: Header<TData, unknown>;
|
|
16
|
+
}) => JSX.Element>): boolean;
|
|
17
|
+
//# sourceMappingURL=useAutoSizeColumns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAutoSizeColumns.d.ts","sourceRoot":"","sources":["../../src/components/useAutoSizeColumns.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,MAAM,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAkD9C;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EACtC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EACnB,QAAQ,EAAE,SAAS,CAAC,cAAc,CAAC,EACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;CAAE,KAAK,GAAG,CAAC,OAAO,CAAC,GACnF,OAAO,CAmGT"}
|