Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b6233b5
simplify the table positioning (padding instead of absolute+top)
severo Dec 2, 2025
0cac77e
add comments, and move mock row label bar
severo Dec 2, 2025
8759ad7
rename scrollRef -> viewportRef
severo Dec 2, 2025
01b6228
add comment
severo Dec 2, 2025
07494f9
simplify positioning of the left mock bar
severo Dec 2, 2025
8c8625d
move the mock bar + add comments
severo Dec 2, 2025
2f59cb5
add comment
severo Dec 2, 2025
8ce5ca9
rename scroller -> viewport
severo Dec 2, 2025
5fb0527
simplify the condition
severo Dec 2, 2025
a53481d
rename: Part->Portion, client->viewport
severo Dec 2, 2025
07aa740
use a fixed scrolling canvas height
severo Dec 2, 2025
388cd8d
add two stories for big and small data
severo Dec 12, 2025
e2d2aa7
separate contexts/ and providers/
severo Dec 16, 2025
2433b00
sort the imports
severo Dec 16, 2025
96f0d1a
add new logic: viewport/canvas/rows slice/table slice
severo Dec 16, 2025
6522a09
remove comments
severo Dec 16, 2025
5b7a995
support numRows === 0
severo Dec 16, 2025
f9442f5
restore scroll with the keyboard
severo Dec 16, 2025
f02d1d9
reverse order of the providers to remove warning (setState in render)
severo Dec 16, 2025
7f1c3c5
include TableCornerProvider to get the left column width
severo Dec 16, 2025
44bd711
fix issue with ResizeObserver - we were limiting the interface on pur…
severo Dec 16, 2025
3688e9f
remove unwanted scroll events
severo Dec 16, 2025
15cb04a
let space for the header when scrolling upwards
severo Dec 17, 2025
25e4918
remove comments
severo Dec 17, 2025
6d217c7
Handle coarse/fine precisions
severo Dec 17, 2025
b8027a5
remove console
severo Dec 17, 2025
77b2fd7
remove console
severo Dec 17, 2025
cb91a98
scroll horizontally, once the vertical scroll is done
severo Dec 17, 2025
541bd04
throttle scroll events (useful?)
severo Dec 17, 2025
2522f24
only limit the canvas size for big tables
severo Dec 18, 2025
f26f546
lint
severo Dec 18, 2025
c92126b
fix
severo Dec 18, 2025
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
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ interface TableProps {
focus?: boolean // focus table on mount? (default true)
maxRowNumber?: number // maximum row number to display (for row headers). Useful for filtered data. If undefined, the number of rows in the data frame is applied.
orderBy?: OrderBy // order by column (if defined, the component order is controlled by the parent)
overscan?: number // number of rows to fetch outside of the viewport (default 20)
padding?: number // number of extra rows to render outside of the viewport (default 20)
padding?: number // number of extra rows to fetch and render outside of the viewport (default 20)
selection?: Selection // selection state (if defined, the component selection is controlled by the parent)
styled?: boolean // use styled component? (default true)
onColumnsVisibilityChange?: (columnVisibilityStates: Record<string, MaybeHiddenColumn>) => void // columns visibility change handler
Expand Down
19 changes: 9 additions & 10 deletions src/HighTable.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@

/* Note that this class cannot be easily overriden by custom CSS. It's not really an issue as its role is functional. */
.table-scroll {
flex: 1;
overflow: auto;
& > div {
position: relative;
}
overflow: auto;
/* avoid the row and column headers (sticky) to overlap the current navigation cell */
scroll-padding-inline-start: var(--row-number-width);
scroll-padding-block-start: var(--column-header-height);
}

/* the canvas */
& > div {
overflow-y: clip;
/* the children (table, and mock row labels) are positioned absolutely */
position: relative;
}
}
table {
position: absolute;
max-width: 100%;
overflow-x: auto;
}

/* cells */
Expand Down Expand Up @@ -207,7 +207,7 @@
.mock-row-label {
content: "";
position: absolute;
top: var(--mock-row-label-top, 0);
top: 0;
left: 0;
bottom: 0;
background: var(--mock-row-label-background, transparent);
Expand Down Expand Up @@ -647,7 +647,6 @@
/* mock row numbers */
/* Note that this class cannot be easily overriden by custom CSS. Use the variable to change the background. */
--mock-row-label-background: var(--row-number-background-color);
--mock-row-label-top: var(--top-border-height, 0);
}

@keyframes textshimmer {
Expand Down
44 changes: 44 additions & 0 deletions src/components/HighTable/HighTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,38 @@ function createFilteredData(): DataFrame {
return df
}

function createLargeData(): DataFrame {
const numRows = 777_000_000
const columnDescriptors = ['ID', 'Value'].map(name => ({ name }))
function getCell({ row, column }: { row: number, column: string }): ResolvedValue | undefined {
return {
value: column === 'ID'
? `row ${row}`
: column === 'Value'
? Math.floor(100 * random(135 + row))
: undefined,
}
}
const getRowNumber = createGetRowNumber({ numRows })
return { columnDescriptors, numRows, getCell, getRowNumber }
}

function createSmallData(): DataFrame {
const numRows = 8
const columnDescriptors = ['ID', 'Value'].map(name => ({ name }))
function getCell({ row, column }: { row: number, column: string }): ResolvedValue | undefined {
return {
value: column === 'ID'
? `row ${row}`
: column === 'Value'
? Math.floor(100 * random(135 + row))
: undefined,
}
}
const getRowNumber = createGetRowNumber({ numRows })
return { columnDescriptors, numRows, getCell, getRowNumber }
}

function CustomCellContent({ cell, row, col, stringify }: CellContentProps) {
return (
<span>
Expand Down Expand Up @@ -572,3 +604,15 @@ export const SortedVaryingData: Story = {
data: sortableDataFrame(createVaryingArrayDataFrame({ delay_ms: 200, maxRows: 20 })),
},
}

export const LargeData: Story = {
args: {
data: createLargeData(),
},
}

export const SmallData: Story = {
args: {
data: createSmallData(),
},
}
16 changes: 8 additions & 8 deletions src/components/HighTable/HighTable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ describe('HighTable', () => {
})
})

it('uses overscan option', async () => {
const { getByText } = render(<HighTable data={mockData} overscan={10} />)
it('uses padding option', async () => {
const { getByText } = render(<HighTable data={mockData} padding={10} />)
await waitFor(() => {
getByText('ID')
expect(mockData.getCell).toHaveBeenCalledWith({ row: 13, column: 'Age', orderBy: [] })
Expand Down Expand Up @@ -255,8 +255,8 @@ describe('with async data, HighTable', () => {
})

it('renders initial rows', async () => {
const defaultOverscan = 20
const rowEnd = defaultOverscan + 4
const defaultPadding = 20
const rowEnd = defaultPadding + 4
const asyncData = createAsyncDataFrame()
const { getByText } = render(<HighTable data={asyncData} />)
await waitFor(() => {
Expand All @@ -268,11 +268,11 @@ describe('with async data, HighTable', () => {
})
})

it('uses overscan option', async () => {
const overscan = 10
const rowEnd = overscan + 4
it('uses padding option', async () => {
const padding = 10
const rowEnd = padding + 4
const asyncData = createAsyncDataFrame()
const { getByText } = render(<HighTable data={asyncData} overscan={overscan} />)
const { getByText } = render(<HighTable data={asyncData} padding={padding} />)
await waitFor(() => {
getByText('ID')
expect(asyncData.fetch).toHaveBeenCalledExactlyOnceWith({ rowStart: 0, rowEnd, columns: ['ID', 'Name', 'Age'], orderBy: [], signal: expect.any(AbortSignal) })
Expand Down
Loading
Loading