@@ -104,43 +104,79 @@ function resolveUpdater<T>(updater: Updater<T>, current: T): T {
104104 return typeof updater === "function" ? ( updater as ( old : T ) => T ) ( current ) : updater ;
105105}
106106
107+ // ─── Flex column width distribution ──────────────────────────────────
108+
109+ function distributeFlexWidths < TRow > (
110+ sizes : Record < string , number > ,
111+ visibleColumns : readonly DataGridColumnDef < TRow > [ ] ,
112+ available : number ,
113+ ) : void {
114+ const flexCols = visibleColumns . filter ( ( c ) => c . flex != null && c . flex > 0 ) ;
115+ if ( flexCols . length === 0 || available <= 0 ) return ;
116+ const totalFlex = flexCols . reduce ( ( acc , c ) => acc + ( c . flex ?? 0 ) , 0 ) ;
117+ let remaining = available ;
118+ flexCols . forEach ( ( col , i ) => {
119+ const isLast = i === flexCols . length - 1 ;
120+ const share = isLast
121+ ? remaining
122+ : Math . floor ( available * ( ( col . flex ?? 0 ) / totalFlex ) ) ;
123+ const max = col . maxWidth ?? Infinity ;
124+ const add = Math . max ( 0 , Math . min ( share , max - sizes [ col . id ] ) ) ;
125+ sizes [ col . id ] += add ;
126+ remaining -= add ;
127+ } ) ;
128+ }
129+
107130// ─── Selection logic (with shift-range anchor) ───────────────────────
108131
109- function nextSelection (
132+ type SelectionInput = {
133+ current : DataGridSelectionModel ;
134+ rowId : RowId ;
135+ mode : "single" | "multiple" ;
136+ modifiers : { shift : boolean ; ctrl : boolean } ;
137+ allRowIds : readonly RowId [ ] ;
138+ } ;
139+
140+ function selectSingle ( current : DataGridSelectionModel , rowId : RowId ) : DataGridSelectionModel {
141+ const isSelected = current . selectedIds . has ( rowId ) ;
142+ return {
143+ selectedIds : isSelected ? new Set ( ) : new Set ( [ rowId ] ) ,
144+ anchorId : isSelected ? null : rowId ,
145+ } ;
146+ }
147+
148+ function selectRange (
110149 current : DataGridSelectionModel ,
111150 rowId : RowId ,
112- mode : "single" | "multiple" ,
113- shiftKey : boolean ,
114- ctrlKey : boolean ,
115151 allRowIds : readonly RowId [ ] ,
116- ) : DataGridSelectionModel {
117- if ( mode === "single" ) {
118- const isSelected = current . selectedIds . has ( rowId ) ;
119- return {
120- selectedIds : isSelected ? new Set ( ) : new Set ( [ rowId ] ) ,
121- anchorId : isSelected ? null : rowId ,
122- } ;
123- }
124- if ( shiftKey && current . anchorId != null ) {
125- const anchorIdx = allRowIds . indexOf ( current . anchorId ) ;
126- const currentIdx = allRowIds . indexOf ( rowId ) ;
127- if ( anchorIdx >= 0 && currentIdx >= 0 ) {
128- const start = Math . min ( anchorIdx , currentIdx ) ;
129- const end = Math . max ( anchorIdx , currentIdx ) ;
130- const next = ctrlKey ? new Set ( current . selectedIds ) : new Set < RowId > ( ) ;
131- for ( let i = start ; i <= end ; i ++ ) next . add ( allRowIds [ i ] ! ) ;
132- return { selectedIds : next , anchorId : current . anchorId } ;
133- }
134- }
135- if ( ctrlKey ) {
136- const next = new Set ( current . selectedIds ) ;
137- if ( next . has ( rowId ) ) {
138- next . delete ( rowId ) ;
139- } else {
140- next . add ( rowId ) ;
141- }
142- return { selectedIds : next , anchorId : rowId } ;
152+ additive : boolean ,
153+ ) : DataGridSelectionModel | null {
154+ if ( current . anchorId == null ) return null ;
155+ const anchorIdx = allRowIds . indexOf ( current . anchorId ) ;
156+ const currentIdx = allRowIds . indexOf ( rowId ) ;
157+ if ( anchorIdx < 0 || currentIdx < 0 ) return null ;
158+ const start = Math . min ( anchorIdx , currentIdx ) ;
159+ const end = Math . max ( anchorIdx , currentIdx ) ;
160+ const next = additive ? new Set ( current . selectedIds ) : new Set < RowId > ( ) ;
161+ for ( let i = start ; i <= end ; i ++ ) next . add ( allRowIds [ i ] ! ) ;
162+ return { selectedIds : next , anchorId : current . anchorId } ;
163+ }
164+
165+ function selectToggle ( current : DataGridSelectionModel , rowId : RowId ) : DataGridSelectionModel {
166+ const next = new Set ( current . selectedIds ) ;
167+ if ( next . has ( rowId ) ) next . delete ( rowId ) ;
168+ else next . add ( rowId ) ;
169+ return { selectedIds : next , anchorId : rowId } ;
170+ }
171+
172+ function nextSelection ( input : SelectionInput ) : DataGridSelectionModel {
173+ const { current, rowId, mode, modifiers, allRowIds } = input ;
174+ if ( mode === "single" ) return selectSingle ( current , rowId ) ;
175+ if ( modifiers . shift ) {
176+ const range = selectRange ( current , rowId , allRowIds , modifiers . ctrl ) ;
177+ if ( range != null ) return range ;
143178 }
179+ if ( modifiers . ctrl ) return selectToggle ( current , rowId ) ;
144180 return { selectedIds : new Set ( [ rowId ] ) , anchorId : rowId } ;
145181}
146182
@@ -614,7 +650,7 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
614650 id : col . id ,
615651 accessorFn : ( row ) => resolveColumnValue ( col , row ) ,
616652 header : typeof col . header === "string" ? col . header : col . id ,
617- size : col . width ?? 150 ,
653+ size : col . width ?? DEFAULT_COL_WIDTH ,
618654 minSize : getEffectiveMinWidth ( col ) ,
619655 maxSize : getEffectiveMaxWidth ( col ) ,
620656 enableSorting : col . sortable !== false ,
@@ -732,7 +768,7 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
732768 onColumnVisibilityChange : handleVisibilityChange ,
733769 onColumnOrderChange : handleColumnOrderChange ,
734770 onColumnPinningChange : handleColumnPinningChange ,
735- columnResizeMode : "onChange " ,
771+ columnResizeMode : "onEnd " ,
736772 enableRowSelection : selectionMode !== "none" ,
737773 enableMultiRowSelection : selectionMode === "multiple" ,
738774 enableColumnResizing : resizable ,
@@ -766,31 +802,23 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
766802 } , [ ] ) ;
767803
768804 // ── Column width CSS variables (TanStack pattern) ────────────
769- // Update on either columnSizing OR columnSizingInfo so resize-in-progress
770- // also reflows widths. Cells read via var(--col-X-size).
805+ // With `columnResizeMode: "onEnd"`, live drag width comes from deltaOffset; committed sizes update on pointer-up.
771806 const columnSizingInfo = table . getState ( ) . columnSizingInfo ;
772807 const columnSizes = useMemo < Record < string , number > > ( ( ) => {
773808 const sizes : Record < string , number > = { } ;
774809 let baseTotal = selectionMode !== "none" ? 44 : 0 ;
810+ const resizingId = columnSizingInfo . isResizingColumn || null ;
811+ const deltaOffset = columnSizingInfo . deltaOffset ?? 0 ;
775812 for ( const col of visibleColumns ) {
776- const s = table . getColumn ( col . id ) ?. getSize ( ) ?? col . width ?? DEFAULT_COL_WIDTH ;
777- sizes [ col . id ] = s ;
778- baseTotal += s ;
779- }
780- const flexCols = visibleColumns . filter ( ( c ) => c . flex != null && c . flex > 0 ) ;
781- if ( flexCols . length > 0 && containerWidth > baseTotal ) {
782- const totalFlex = flexCols . reduce ( ( acc , c ) => acc + ( c . flex ?? 0 ) , 0 ) ;
783- let remaining = containerWidth - baseTotal ;
784- flexCols . forEach ( ( col , i ) => {
785- const share = i === flexCols . length - 1
786- ? remaining
787- : Math . floor ( ( containerWidth - baseTotal ) * ( ( col . flex ?? 0 ) / totalFlex ) ) ;
788- const max = col . maxWidth ?? Infinity ;
789- const add = Math . max ( 0 , Math . min ( share , max - sizes [ col . id ] ) ) ;
790- sizes [ col . id ] += add ;
791- remaining -= add ;
792- } ) ;
813+ const tsCol = table . getColumn ( col . id ) ;
814+ const baseSize = tsCol ?. getSize ( ) ?? col . width ?? DEFAULT_COL_WIDTH ;
815+ const liveSize = resizingId === col . id
816+ ? clampColumnWidth ( col , baseSize + deltaOffset )
817+ : baseSize ;
818+ sizes [ col . id ] = liveSize ;
819+ baseTotal += liveSize ;
793820 }
821+ distributeFlexWidths ( sizes , visibleColumns , containerWidth - baseTotal ) ;
794822 return sizes ;
795823 } , [ visibleColumns , table , columnSizingInfo , state . columnWidths , containerWidth , selectionMode ] ) ;
796824
@@ -824,14 +852,13 @@ export function DataGrid<TRow>(props: DataGridProps<TRow>) {
824852 const handleRowClick = useCallback (
825853 ( row : TRow , rowId : RowId , event : React . MouseEvent ) => {
826854 if ( selectionMode !== "none" ) {
827- const next = nextSelection (
828- state . selection ,
855+ const next = nextSelection ( {
856+ current : state . selection ,
829857 rowId,
830- selectionMode ,
831- event . shiftKey ,
832- event . metaKey || event . ctrlKey ,
833- rowIds ,
834- ) ;
858+ mode : selectionMode ,
859+ modifiers : { shift : event . shiftKey , ctrl : event . metaKey || event . ctrlKey } ,
860+ allRowIds : rowIds ,
861+ } ) ;
835862 fireSelection ( next ) ;
836863 }
837864 onRowClick ?.( row , rowId , event ) ;
0 commit comments