-
-
Notifications
You must be signed in to change notification settings - Fork 431
add MUI X #1171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
add MUI X #1171
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,205 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as React from 'react' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useEffect, useMemo, useRef } from 'react' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LayoutList, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useVirtualizer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type Virtualizer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@mui/x-virtualizer' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| markFirstPaint, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| markMountEnd, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| markMountStart, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| registerHarness, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '../lib/harness' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { makeDataset, type Item } from '../lib/dataset' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { ScenarioInput } from '../scenarios/types' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+3
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix import declarations to pass current ESLint checks. This import block violates Proposed fix import * as React from 'react'
import { useEffect, useMemo, useRef } from 'react'
import {
LayoutList,
useVirtualizer,
- type Virtualizer,
} from '`@mui/x-virtualizer`'
+import type { Virtualizer } from '`@mui/x-virtualizer`'
import {
markFirstPaint,
markMountEnd,
markMountStart,
registerHarness,
} from '../lib/harness'
-import { makeDataset, type Item } from '../lib/dataset'
+import { makeDataset } from '../lib/dataset'
+import type { Item } from '../lib/dataset'
import type { ScenarioInput } from '../scenarios/types'📝 Committable suggestion
Suggested change
🧰 Tools🪛 ESLint[error] 6-6: Member 'Virtualizer' of the import declaration should be sorted alphabetically. (sort-imports) [error] 6-6: Prefer using a top-level type-only import instead of inline type specifiers. (import/consistent-type-specifier-style) [error] 14-14: Member 'Item' of the import declaration should be sorted alphabetically. (sort-imports) [error] 14-14: Prefer using a top-level type-only import instead of inline type specifiers. (import/consistent-type-specifier-style) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface Props { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scenario: ScenarioInput | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // @mui/x-virtualizer is a grid-oriented engine. We adapt it to a single-column | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // list by setting columns to its default 1-column placeholder and rendering | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // each row as a plain block element. The engine still pays for column / | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // dimensions bookkeeping that the other libs don't — see README. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const VirtualizerContext = React.createContext<Virtualizer | null>(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ObserveRowHeightContext = React.createContext< | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ((node: HTMLElement, id: number) => (() => void) | undefined) | null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| >(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function MuiPage({ scenario }: Props) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const items = useMemo( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| makeDataset( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scenario.count, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scenario.dynamic, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scenario.action === 'jump-wide-variance-accuracy', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [scenario.count, scenario.dynamic, scenario.action], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rows = useMemo( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => items.map((it, i) => ({ id: i, model: it })), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [items], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const range = useMemo( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => ({ firstRowIndex: 0, lastRowIndex: rows.length }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [rows.length], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const containerRef = useRef<HTMLDivElement>(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const scrollerRef = useRef<HTMLDivElement>(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const refs = useMemo( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => ({ container: containerRef, scroller: scrollerRef }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const layoutRef = useRef<LayoutList | null>(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (layoutRef.current === null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| layoutRef.current = new LayoutList(refs) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const layout = layoutRef.current | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The virtualizer treats these as dependencies of internal effects (notably | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // dimensions.useRowsMeta), so unstable references trigger an infinite update | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // loop in dynamic mode and React unmounts the tree. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dimensions = useMemo( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => ({ rowHeight: scenario.itemSize }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [scenario.itemSize], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const virtualization = useMemo(() => ({}), []) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const getRowHeight = React.useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => 'auto' as const, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const renderRow = React.useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (params: { id: unknown; rowIndex: number; model: unknown }) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <MuiRow | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key={params.id as number} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id={params.id as number} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| index={params.rowIndex} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model={params.model as Item} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dynamic={scenario.dynamic} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| itemSize={scenario.itemSize} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [scenario.dynamic, scenario.itemSize], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const virtualizer = useVirtualizer({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| layout, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dimensions, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| virtualization, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rows, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| range, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rowCount: rows.length, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getRowHeight: scenario.dynamic ? getRowHeight : undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| renderRow, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // virtualizer.api is rebuilt every render, so wrap the observer in a stable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // callback backed by a ref. Rows depend on this callback in a useEffect — an | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // unstable observer would re-observe every render and storm storeRowHeightMeasurement. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const apiRef = useRef(virtualizer.api) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| apiRef.current = virtualizer.api | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const observeRowHeight = React.useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (node: HTMLElement, id: number) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| apiRef.current.rowsMeta.observeRowHeight(node, id), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| registerHarness({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getScrollContainer: () => scrollerRef.current, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scrollToIndex: (i, opts) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const scroller = scrollerRef.current | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!scroller) return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const state = virtualizer.store.state | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const positions = state.rowsMeta.positions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const targetTop = positions[i] ?? i * scenario.itemSize | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (opts?.align === 'end') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const entry = state.rowHeights.get(i) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rowH = entry?.content ?? scenario.itemSize | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scroller.scrollTop = Math.max( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| targetTop + rowH - scroller.clientHeight, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scroller.scrollTop = targetTop | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getTotalSize: () => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| virtualizer.store.state.dimensions.contentSize.height ?? 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isFullyMeasured: () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!scenario.dynamic) return true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ResizeObserver populates rowHeights as items enter the viewport. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return virtualizer.store.state.rowHeights.size >= 10 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| markMountEnd() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| markFirstPaint() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [virtualizer, scenario.dynamic, scenario.itemSize]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const containerProps = virtualizer.store.use( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LayoutList.selectors.containerProps, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const contentProps = virtualizer.store.use(LayoutList.selectors.contentProps) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const positionerProps = virtualizer.store.use( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LayoutList.selectors.positionerProps, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {...containerProps} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="scroll-host" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data-bench-scroll-host="mui-x" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div {...contentProps} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div {...positionerProps} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <VirtualizerContext.Provider value={virtualizer}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <ObserveRowHeightContext.Provider value={observeRowHeight}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <MuiListContent /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </ObserveRowHeightContext.Provider> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </VirtualizerContext.Provider> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const MuiListContent = React.memo(function MuiListContent() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const virtualizer = React.useContext(VirtualizerContext)! | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { getRows } = virtualizer.api.getters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return <>{getRows()}</> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface RowProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| index: number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model: Item | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dynamic: boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| itemSize: number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function MuiRow({ id, index, model, dynamic, itemSize }: RowProps) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const observeRowHeight = React.useContext(ObserveRowHeightContext) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const nodeRef = useRef<HTMLDivElement | null>(null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!dynamic || !nodeRef.current || !observeRowHeight) return undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return observeRowHeight(nodeRef.current, id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [observeRowHeight, dynamic, id]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ref={nodeRef} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data-index={index} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={'item ' + (index % 2 === 0 ? 'even' : '')} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| style={{ minHeight: dynamic ? undefined : itemSize }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {model.text} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function MuiPageRoot({ scenario }: Props) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| markMountStart() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return <MuiPage scenario={scenario} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep result sections consistent with the new five-library claim.
The intro says five libraries, but the “Latest results”/“Bottom line” content still reads as four-library output. Please regenerate or clearly label those sections to avoid misleading comparisons.
🤖 Prompt for AI Agents