5.6 KiB
5.6 KiB
Tasks: enterprise-react-virtual
Change ID: enterprise-react-virtual
Package: @suaveplan/react-virtual
Target path: react/ui/react-virtual
Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin each) - 0.2 If any worktrees exist under
.claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - 0.3 Confirm the package set in
MANIFEST.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Scaffold
- Create directory tree per proposal layout.
- Write
package.jsonat0.1.0with"sideEffects": ["**/*.css"], exports map (top-level barrel + per-module subpaths:./core/virtual-engine/virtual-engine,./core/range-calculator/range-calculator,./hooks/use-virtual-list/use-virtual-list,./hooks/use-virtual-grid/use-virtual-grid,./hooks/use-virtual-scroll/use-virtual-scroll,./components/virtual-list/virtual-list,./components/virtual-grid/virtual-grid,./utils/resize-observer/resize-observer,./utils/scroll-utils/scroll-utils,./styles/virtual.css). dependencies:@suaveplan/error workspace:^,@suaveplan/types workspace:^,clsx catalog:ui,tailwind-merge catalog:ui,zod catalog:forms,@opentelemetry/api catalog:observability,tslib catalog:build.- Write
tsconfig.json,vitest.config.ts, scripts.
2. Error codes and types
- Define
VirtualErrorextendingSuaveplanError; codes:VIRTUAL_INVALID_CONFIG,VIRTUAL_SCROLL_FAILED. - Define all public types:
VirtualEngineConfig,VirtualEngineResult,VirtualItem,VisibleRange,SizeCache,SizeMode,ScrollDirection,ScrollAlignment,ScrollToIndexParams,ThrottleOptions,ResizeCallback, grid-axis types. - Write
VirtualEngineConfigSchemaZod schema; validate increateVirtualEngine.
3. Core engine (src/core/virtual-engine/)
- Implement
createVirtualEngine(config)— validates config, initialisesSizeCache, computes initialVirtualEngineResult. - Implement
calculateVirtualItems(engine, scrollOffset, containerSize)— returnsVirtualItem[]withindex,start,size,end,lane. Handles overscan. - Implement
buildVirtualItems,calculateVisibleRange,calculateScrollToOffset,createSizeCache,findIndexAtOffset,getItemOffset,getItemSize,setItemSize,getScrollDirection,getTotalSize. - Write
virtual-engine.test.ts(≤500 lines): fixed size, dynamic size, overscan, scroll direction, scroll-to-index, size cache mutation.{ timeout: 5000 }. - Write
virtual-engine.md(≥200 words).
4. Range calculator (src/core/range-calculator/)
- Implement
calculateGridRange,calculateGridDimensions,buildGridCells,findAxisIndex,getAxisOffset,getAxisTotalSize,resolveSizefor 2D grid axis math (rows + columns with mixed fixed/dynamic sizes). - Write
range-calculator.test.ts,range-calculator.md.
5. Hooks
useVirtualList
- Wraps engine +
useReffor container scroll; integratesSharedResizeObserverfor container size; returnsvirtualItems,totalSize,scrollToIndex. - Write
use-virtual-list.test.ts,use-virtual-list.md.
useVirtualGrid
- 2D binding: row + column axis,
scrollToCell(row, col). - Write
use-virtual-grid.test.ts,use-virtual-grid.md.
useVirtualScroll
- Scroll-offset observer only — RAF throttled; returns
scrollOffset,scrollDirection,isNearEnd. - Write
use-virtual-scroll.test.ts,use-virtual-scroll.md.
6. Components
VirtualList<T>
- Render-prop component wrapping
useVirtualList. ForwardsVirtualListHandleref withscrollToIndex. prefers-reduced-motionscroll behavior.- OTel
virtual.scrollspan event. - Write
virtual-list.test.tsx,virtual-list.stories.tsx(default, dynamic-sizes, large-dataset 100k, playground, a11y),virtual-list.md.
VirtualGrid<T>
- Render-prop component wrapping
useVirtualGrid. ForwardsVirtualGridHandle. - Write
virtual-grid.test.tsx,virtual-grid.stories.tsx,virtual-grid.md.
7. Utilities
src/utils/resize-observer/resize-observer.ts—SharedResizeObserverpooling (one observer per root),getSharedResizeObserver(),measureElement(),resetSharedResizeObserver(). Write test + md.src/utils/scroll-utils/scroll-utils.ts—throttle,throttleWithRaf,getScrollOffset,clampScrollOffset,scrollTo(respectsprefers-reduced-motion),isNearEnd. Write test + md.src/styles/virtual.css— positioning helpers (absolute container, transform translate3d items).
8. Integration and E2E
tests/integration.test.tsx—VirtualListwith 10k items: scroll offset updates virtual items,scrollToIndexsnaps.e2e/virtual.spec.ts— Playwright: render 100k-row list, verify only ~20 DOM nodes, scroll to bottom,scrollToIndex(5000)lands at correct position.
9. Verify and publish
bunx turbo lint typecheck test --filter=@suaveplan/react-virtual— green.bunx turbo test:coverage --filter=@suaveplan/react-virtual— 100%.bun scripts/publish.ts --package @suaveplan/react-virtual.- Archive change folder.