Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export default defineConfig([
'@typescript-eslint/prefer-promise-reject-errors': 'off',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/restrict-template-expressions': 'off',
'@typescript-eslint/switch-exhaustiveness-check': ['error', { allowDefaultCaseForExhaustiveSwitch: false }],
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'off',
},
settings: { react: { version: 'detect' } },
Expand Down
2 changes: 1 addition & 1 deletion src/components/ColumnHeader/ColumnHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ export default function ColumnHeader({ columnIndex, columnName, columnConfig, ca
const { getHideColumn, showAllColumns } = useContext(ColumnVisibilityStatesContext)

const refCallback = useCallback((node: HTMLTableCellElement | null) => {
focusCellIfNeeded(node)
// set the current ref, it will be used to position the menu in handleMenuClick
ref.current = node
focusCellIfNeeded(node)
}, [focusCellIfNeeded])

const handleClick = useCallback(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ColumnMenu/ColumnMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function getSortDirection(direction?: Direction) {
return 'Ascending'
case 'descending':
return 'Descending'
default:
case undefined:
return 'No sort'
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/HighTable/HighTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ function createFilteredData(): DataFrame {
}

function createLargeData(): DataFrame {
const numRows = 777_000_000
// 1 peta rows (1 million billion, 10^15)
const numRows = 1_000_000_000_000_000
const columnDescriptors = ['ID1', 'LongString1', 'Value1', 'ID2', 'LongString2', 'Value2', 'ID3', 'LongString3', 'Value3', 'ID4', 'LongString4', 'Value4'].map(name => ({ name }))
function getCell({ row, column }: { row: number, column: string }): ResolvedValue | undefined {
return {
Expand Down
4 changes: 3 additions & 1 deletion src/components/HighTable/Slice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ export default function Slice({
event.preventDefault()
if (newRowIndex !== undefined) {
setRowIndex(newRowIndex)
scrollRowIntoView?.({ rowIndex: newRowIndex }) // ensure the cell is visible
}
// ensure the cell is visible (even if only horizontal scrolling is needed)
// TODO(SL): improve the name of scrollRowIntoView, because it can also (indirectly) scroll columns into view
scrollRowIntoView?.({ rowIndex: newRowIndex ?? rowIndex })
setShouldFocus(true)
}, [rowIndex, colCount, rowCount, setColIndex, setRowIndex, setShouldFocus, scrollRowIntoView])

Expand Down
3 changes: 2 additions & 1 deletion src/contexts/ScrollModeContext.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { createContext } from 'react'

export interface ScrollModeContextType {
scrollMode?: 'native' | 'virtual'
scrollMode?: 'native' | 'virtual' // it's only informative for now
canvasHeight?: number // total scrollable height
isScrolling?: boolean
sliceTop?: number // offset of the top of the slice from the top of the canvas
visibleRowsStart?: number // index of the first row visible in the viewport (inclusive). Indexes refer to the virtual table domain.
visibleRowsEnd?: number // index of the last row visible in the viewport (exclusive).
Expand Down
11 changes: 9 additions & 2 deletions src/helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,12 @@ export const ariaOffset = 2 // 1-based index, +1 for the header

// reference: https://meyerweb.com/eric/thoughts/2025/08/07/infinite-pixels/
// it seems to be 17,895,700 in Firefox, 33,554,400 in Chrome and 33,554,428 in Safari
// Disabled for now
export const maxElementHeight = Infinity
export const maxElementHeight = 8_000_000 // a safe maximum height for an element in the DOM

// 16,500px is ~0.2% of the canvas height for 8M px, it corresponds to 500 rows at 33px height.
// -> when scrolling with the mouse wheel, the change is local (< 16,500px)
// -> when scrolling with the scrollbar (drag/drop), or with the mouse wheel for a long time (> 500 rows), the change is global (> 0.2% of the scrollbar height)
// -> on mobile, swapping will also produce big jumps.
// TODO(SL): should we detect touch events and adapt the thresholds on mobile?
// TODO(SL): decrease/increase the threshold? make it configurable? or dependent on the number of rows, ie: a % of the scroll bar height?
export const largeScrollPx = 500 * rowHeight // px threshold to consider a scroll as "large"
Loading