@@ -726,192 +726,3 @@ export const EllipsisExamples: Story = {
726726 style : { width : 'min(100%, 300px)' } ,
727727 } ,
728728} ;
729-
730- // Bug #3: Keyboard navigation with End/Home fails on virtualized-out columns.
731- // Steps: 1) Click any cell in the first row. 2) Press End — focus should jump to the last column.
732- export const BugKeyboardNavVirtualizedColumns : Story = {
733- tags : [ 'excludeFromSidebar' ] ,
734- render ( args ) {
735- const manyColumns = useMemo < AnalyticalTableColumnDefinition [ ] > (
736- ( ) =>
737- Array . from ( { length : 30 } , ( _ , i ) => ( {
738- Header : `Col ${ i } ` ,
739- id : `col_${ i } ` ,
740- accessor : 'name' ,
741- width : 120 ,
742- Cell : ( { value } ) => `${ value } (${ i } )` ,
743- } ) ) ,
744- [ ] ,
745- ) ;
746- const data = useMemo ( ( ) => dataLarge . slice ( 0 , 50 ) , [ ] ) ;
747- return (
748- < AnalyticalTable
749- { ...args }
750- columns = { manyColumns }
751- data = { data }
752- scaleWidthMode = { AnalyticalTableScaleWidthMode . Default }
753- overscanCountHorizontal = { 2 }
754- visibleRows = { 8 }
755- header = "Bug #3: Press End/Home to navigate to first/last column"
756- style = { { width : '600px' } }
757- />
758- ) ;
759- } ,
760- } ;
761-
762- // Bug #13: Shift+Arrow keyboard resize produces NaN column width.
763- // Steps: 1) Focus any column header. 2) Press Shift+ArrowRight — column should grow by 16px.
764- export const BugKeyboardResizeNaN : Story = {
765- tags : [ 'excludeFromSidebar' ] ,
766- args : {
767- data : dataLarge . slice ( 0 , 10 ) ,
768- columns : [
769- { Header : 'Name' , accessor : 'name' , width : 200 } ,
770- { Header : 'Age' , accessor : 'age' , width : 150 } ,
771- { Header : 'Friend Name' , accessor : 'friend.name' , width : 200 } ,
772- { Header : 'Friend Age' , accessor : 'friend.age' , width : 150 } ,
773- ] ,
774- visibleRows : 5 ,
775- header : 'Bug #13: Focus a column header, press Shift+ArrowRight to resize' ,
776- } ,
777- } ;
778-
779- // Performance: selectedFlatRows useMemo regression test.
780- //
781- // 10,000 rows with selection enabled. onTableScroll updates parent state on every
782- // scroll frame, forcing re-renders where rows/selectedRowIds DON'T change.
783- // Without useMemo: each re-render iterates all 10k rows. With useMemo: O(1) cache hit.
784- //
785- // How to measure:
786- // 1. Open Chrome DevTools → Performance tab.
787- // 2. Click Record, scroll the table for ~3 seconds, stop recording.
788- // 3. Look at individual "render" flames in the "Main" thread.
789- // Without useMemo: useInstance calls show ~2-5ms of getRowIsSelected iteration.
790- // With useMemo: useInstance calls are <0.1ms (memoized).
791- // 4. Alternatively: DevTools → Performance → check "CPU 6x slowdown" to exaggerate.
792- //
793- // To toggle the fix: in useRowSelect.ts, remove/restore useMemo around selectedFlatRows.
794- export const PerfSelectedFlatRowsMemo : Story = {
795- tags : [ 'excludeFromSidebar' ] ,
796- render ( args ) {
797- const ROW_COUNT = 10_000 ;
798-
799- const columns = useMemo < AnalyticalTableColumnDefinition [ ] > (
800- ( ) => [
801- { Header : 'Row' , accessor : 'id' } ,
802- { Header : 'Name' , accessor : 'name' } ,
803- { Header : 'Value A' , accessor : 'a' } ,
804- { Header : 'Value B' , accessor : 'b' } ,
805- { Header : 'Value C' , accessor : 'c' } ,
806- ] ,
807- [ ] ,
808- ) ;
809-
810- const data = useMemo (
811- ( ) =>
812- Array . from ( { length : ROW_COUNT } , ( _ , i ) => ( {
813- id : i ,
814- name : `Row ${ i } ` ,
815- a : Math . round ( Math . random ( ) * 1000 ) ,
816- b : Math . round ( Math . random ( ) * 1000 ) ,
817- c : Math . round ( Math . random ( ) * 1000 ) ,
818- } ) ) ,
819- [ ] ,
820- ) ;
821-
822- // Updating state on every scroll forces a parent re-render → AnalyticalTable
823- // re-render → useInstance runs. rows and selectedRowIds haven't changed,
824- // so this isolates the useMemo vs. no-useMemo cost difference.
825- const [ scrollEvents , setScrollEvents ] = useState ( 0 ) ;
826- const onTableScroll = useCallback ( ( ) => {
827- setScrollEvents ( ( prev ) => prev + 1 ) ;
828- } , [ ] ) ;
829-
830- return (
831- < AnalyticalTable
832- { ...args }
833- columns = { columns }
834- data = { data }
835- selectionMode = { AnalyticalTableSelectionMode . Multiple }
836- onTableScroll = { onTableScroll }
837- visibleRows = { 15 }
838- header = { `${ ROW_COUNT . toLocaleString ( ) } rows — scroll events: ${ scrollEvents } ` }
839- />
840- ) ;
841- } ,
842- } ;
843-
844- // Bug #14: tableColResized gate permanently disables dynamic width recalculation.
845- // Steps: 1) Drag any column resizer to resize a column. 2) Click "Switch to Column Set B".
846- // Expected: New columns distribute evenly across the table width.
847- // Actual: All columns are stuck at 150px (decorateColumn default) because tableColResized blocks adjustColumnWidths.
848- export const BugRetainColumnWidthBlocksRecalculation : Story = {
849- tags : [ 'excludeFromSidebar' ] ,
850- render ( args ) {
851- const columnsA = useMemo < AnalyticalTableColumnDefinition [ ] > (
852- ( ) => [
853- { Header : 'Name' , accessor : 'name' } ,
854- { Header : 'Age' , accessor : 'age' } ,
855- { Header : 'Status' , accessor : 'status' } ,
856- ] ,
857- [ ] ,
858- ) ;
859-
860- const columnsB = useMemo < AnalyticalTableColumnDefinition [ ] > (
861- ( ) => [
862- { Header : 'Product' , accessor : 'product' } ,
863- { Header : 'Price' , accessor : 'price' } ,
864- { Header : 'Quantity' , accessor : 'qty' } ,
865- { Header : 'Category' , accessor : 'category' } ,
866- ] ,
867- [ ] ,
868- ) ;
869-
870- const dataA = useMemo (
871- ( ) =>
872- Array . from ( { length : 20 } , ( _ , i ) => ( {
873- name : `Person ${ i } ` ,
874- age : 20 + ( i % 40 ) ,
875- status : i % 2 === 0 ? 'Active' : 'Inactive' ,
876- } ) ) ,
877- [ ] ,
878- ) ;
879-
880- const dataB = useMemo (
881- ( ) =>
882- Array . from ( { length : 20 } , ( _ , i ) => ( {
883- product : `Product ${ i } ` ,
884- price : `$${ ( Math . random ( ) * 100 ) . toFixed ( 2 ) } ` ,
885- qty : Math . floor ( Math . random ( ) * 500 ) ,
886- category : [ 'Electronics' , 'Clothing' , 'Food' ] [ i % 3 ] ,
887- } ) ) ,
888- [ ] ,
889- ) ;
890-
891- const [ useSetB , setUseSetB ] = useState ( false ) ;
892-
893- return (
894- < FlexBox direction = { FlexBoxDirection . Column } style = { { gap : '1rem' } } >
895- < Text >
896- Bug: With retainColumnWidth, resize any column, then switch column set. New columns get 150px instead of
897- recalculating.
898- </ Text >
899- < Button
900- onClick = { ( ) => {
901- setUseSetB ( ( prev ) => ! prev ) ;
902- } }
903- >
904- { useSetB ? 'Switch to Column Set A (3 cols)' : 'Switch to Column Set B (4 cols)' }
905- </ Button >
906- < AnalyticalTable
907- { ...args }
908- columns = { useSetB ? columnsB : columnsA }
909- data = { useSetB ? dataB : dataA }
910- retainColumnWidth
911- scaleWidthMode = { AnalyticalTableScaleWidthMode . Default }
912- header = { `Column Set ${ useSetB ? 'B' : 'A' } — retainColumnWidth=true` }
913- />
914- </ FlexBox >
915- ) ;
916- } ,
917- } ;
0 commit comments