@@ -218,6 +218,10 @@ export interface DataEditorProps extends Props, Pick<DataGridSearchProps, "image
218
218
* @group Editing
219
219
*/
220
220
readonly onRowAppended ?: ( ) => Promise < "top" | "bottom" | number | undefined > | void ;
221
+ /** Emitted whenever a column append operation is requested. Append location can be set in callback.
222
+ * @group Editing
223
+ */
224
+ readonly onColumnAppended ?: ( ) => Promise < "left" | "right" | number | undefined > | void ;
221
225
/** Emitted when a column header should show a context menu. Usually right click.
222
226
* @group Events
223
227
*/
@@ -705,6 +709,12 @@ export interface DataEditorRef {
705
709
* @returns A promise which waits for the append to complete.
706
710
*/
707
711
appendRow : ( col : number , openOverlay ?: boolean , behavior ?: ScrollBehavior ) => Promise < void > ;
712
+ /**
713
+ * Programatically appends a column.
714
+ * @param row The row index to focus in the new column.
715
+ * @returns A promise which waits for the append to complete.
716
+ */
717
+ appendColumn : ( row : number , openOverlay ?: boolean ) => Promise < void > ;
708
718
/**
709
719
* Triggers cells to redraw.
710
720
*/
@@ -744,7 +754,7 @@ const loadingCell: GridCell = {
744
754
allowOverlay : false ,
745
755
} ;
746
756
747
- const emptyGridSelection : GridSelection = {
757
+ export const emptyGridSelection : GridSelection = {
748
758
columns : CompactSelection . empty ( ) ,
749
759
rows : CompactSelection . empty ( ) ,
750
760
current : undefined ,
@@ -808,6 +818,7 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
808
818
keybindings : keybindingsIn ,
809
819
editOnType = true ,
810
820
onRowAppended,
821
+ onColumnAppended,
811
822
onColumnMoved,
812
823
validateCell : validateCellIn ,
813
824
highlightRegions : highlightRegionsIn ,
@@ -929,7 +940,7 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
929
940
const rowMarkerWidth = rowMarkerWidthRaw ?? ( rowsIn > 10_000 ? 48 : rowsIn > 1000 ? 44 : rowsIn > 100 ? 36 : 32 ) ;
930
941
const hasRowMarkers = rowMarkers !== "none" ;
931
942
const rowMarkerOffset = hasRowMarkers ? 1 : 0 ;
932
- const showTrailingBlankRow = onRowAppended !== undefined ;
943
+ const showTrailingBlankRow = trailingRowOptions !== undefined ;
933
944
const lastRowSticky = trailingRowOptions ?. sticky === true ;
934
945
935
946
const [ showSearchInner , setShowSearchInner ] = React . useState ( false ) ;
@@ -1649,10 +1660,16 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
1649
1660
1650
1661
const focusCallback = React . useRef ( focusOnRowFromTrailingBlankRow ) ;
1651
1662
const getCellContentRef = React . useRef ( getCellContent ) ;
1652
- const rowsRef = React . useRef ( rows ) ;
1663
+
1653
1664
focusCallback . current = focusOnRowFromTrailingBlankRow ;
1654
1665
getCellContentRef . current = getCellContent ;
1666
+
1667
+ const rowsRef = React . useRef ( rows ) ;
1655
1668
rowsRef . current = rows ;
1669
+
1670
+ const colsRef = React . useRef ( mangledCols . length ) ;
1671
+ colsRef . current = mangledCols . length ;
1672
+
1656
1673
const appendRow = React . useCallback (
1657
1674
async ( col : number , openOverlay : boolean = true , behavior ?: ScrollBehavior ) : Promise < void > => {
1658
1675
const c = mangledCols [ col ] ;
@@ -1710,6 +1727,57 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
1710
1727
[ mangledCols , onRowAppended , rowMarkerOffset , rows , setCurrent ]
1711
1728
) ;
1712
1729
1730
+ const appendColumn = React . useCallback (
1731
+ async ( row : number , openOverlay : boolean = true ) : Promise < void > => {
1732
+ const appendResult = onColumnAppended ?.( ) ;
1733
+
1734
+ let r : "left" | "right" | number | undefined = undefined ;
1735
+ let right = true ;
1736
+ if ( appendResult !== undefined ) {
1737
+ r = await appendResult ;
1738
+ if ( r === "left" ) right = false ;
1739
+ if ( typeof r === "number" ) right = false ;
1740
+ }
1741
+
1742
+ let backoff = 0 ;
1743
+ const doFocus = ( ) => {
1744
+ if ( colsRef . current <= mangledCols . length ) {
1745
+ if ( backoff < 500 ) {
1746
+ window . setTimeout ( doFocus , backoff ) ;
1747
+ }
1748
+ backoff = 50 + backoff * 2 ;
1749
+ return ;
1750
+ }
1751
+
1752
+ const col = typeof r === "number" ? r : right ? mangledCols . length : 0 ;
1753
+ scrollTo ( col - rowMarkerOffset , row ) ;
1754
+ setCurrent (
1755
+ {
1756
+ cell : [ col , row ] ,
1757
+ range : {
1758
+ x : col ,
1759
+ y : row ,
1760
+ width : 1 ,
1761
+ height : 1 ,
1762
+ } ,
1763
+ } ,
1764
+ false ,
1765
+ false ,
1766
+ "edit"
1767
+ ) ;
1768
+
1769
+ const cell = getCellContentRef . current ( [ col - rowMarkerOffset , row ] ) ;
1770
+ if ( cell . allowOverlay && isReadWriteCell ( cell ) && cell . readonly !== true && openOverlay ) {
1771
+ window . setTimeout ( ( ) => {
1772
+ focusCallback . current ( col , row ) ;
1773
+ } , 0 ) ;
1774
+ }
1775
+ } ;
1776
+ doFocus ( ) ;
1777
+ } ,
1778
+ [ mangledCols , onColumnAppended , rowMarkerOffset , scrollTo , setCurrent ]
1779
+ ) ;
1780
+
1713
1781
const getCustomNewRowTargetColumn = React . useCallback (
1714
1782
( col : number ) : number | undefined => {
1715
1783
const customTargetColumn =
@@ -2991,14 +3059,29 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
2991
3059
2992
3060
const [ movX , movY ] = movement ;
2993
3061
if ( gridSelection . current !== undefined && ( movX !== 0 || movY !== 0 ) ) {
2994
- const isEditingTrailingRow =
2995
- gridSelection . current . cell [ 1 ] === mangledRows - 1 && newValue !== undefined ;
2996
- updateSelectedCell (
2997
- clamp ( gridSelection . current . cell [ 0 ] + movX , 0 , mangledCols . length - 1 ) ,
2998
- clamp ( gridSelection . current . cell [ 1 ] + movY , 0 , mangledRows - 1 ) ,
2999
- isEditingTrailingRow ,
3000
- false
3001
- ) ;
3062
+ const isEditingLastRow = gridSelection . current . cell [ 1 ] === mangledRows - 1 && newValue !== undefined ;
3063
+ const isEditingLastCol =
3064
+ gridSelection . current . cell [ 0 ] === mangledCols . length - 1 && newValue !== undefined ;
3065
+ let updateSelected = true ;
3066
+ if ( isEditingLastRow && movY === 1 && onRowAppended !== undefined ) {
3067
+ updateSelected = false ;
3068
+ const col = gridSelection . current . cell [ 0 ] + movX ;
3069
+ const customTargetColumn = getCustomNewRowTargetColumn ( col ) ;
3070
+ void appendRow ( customTargetColumn ?? col , false ) ;
3071
+ }
3072
+ if ( isEditingLastCol && movX === 1 && onColumnAppended !== undefined ) {
3073
+ updateSelected = false ;
3074
+ const row = gridSelection . current . cell [ 1 ] + movY ;
3075
+ void appendColumn ( row , false ) ;
3076
+ }
3077
+ if ( updateSelected ) {
3078
+ updateSelectedCell (
3079
+ clamp ( gridSelection . current . cell [ 0 ] + movX , 0 , mangledCols . length - 1 ) ,
3080
+ clamp ( gridSelection . current . cell [ 1 ] + movY , 0 , mangledRows - 1 ) ,
3081
+ isEditingLastRow ,
3082
+ false
3083
+ ) ;
3084
+ }
3002
3085
}
3003
3086
onFinishedEditing ?.( newValue , movement ) ;
3004
3087
} ,
@@ -3011,6 +3094,11 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
3011
3094
mangledRows ,
3012
3095
updateSelectedCell ,
3013
3096
mangledCols . length ,
3097
+ appendRow ,
3098
+ appendColumn ,
3099
+ onRowAppended ,
3100
+ onColumnAppended ,
3101
+ getCustomNewRowTargetColumn ,
3014
3102
]
3015
3103
) ;
3016
3104
@@ -3862,6 +3950,7 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
3862
3950
forwardedRef ,
3863
3951
( ) => ( {
3864
3952
appendRow : ( col : number , openOverlay ?: boolean ) => appendRow ( col + rowMarkerOffset , openOverlay ) ,
3953
+ appendColumn : ( row : number , openOverlay ?: boolean ) => appendColumn ( row , openOverlay ) ,
3865
3954
updateCells : damageList => {
3866
3955
if ( rowMarkerOffset !== 0 ) {
3867
3956
damageList = damageList . map ( x => ( { cell : [ x . cell [ 0 ] + rowMarkerOffset , x . cell [ 1 ] ] } ) ) ;
@@ -3971,7 +4060,17 @@ const DataEditorImpl: React.ForwardRefRenderFunction<DataEditorRef, DataEditorPr
3971
4060
} ;
3972
4061
} ,
3973
4062
} ) ,
3974
- [ appendRow , normalSizeColumn , scrollRef , onCopy , onKeyDown , onPasteInternal , rowMarkerOffset , scrollTo ]
4063
+ [
4064
+ appendRow ,
4065
+ appendColumn ,
4066
+ normalSizeColumn ,
4067
+ scrollRef ,
4068
+ onCopy ,
4069
+ onKeyDown ,
4070
+ onPasteInternal ,
4071
+ rowMarkerOffset ,
4072
+ scrollTo ,
4073
+ ]
3975
4074
) ;
3976
4075
3977
4076
const [ selCol , selRow ] = currentCell ?? [ ] ;
0 commit comments