1515from reflex .utils .serializers import serializer
1616from reflex .vars import get_unique_variable_name
1717from reflex .vars .base import Var
18+ from reflex .vars .function import FunctionStringVar
1819from reflex .vars .sequence import ArrayVar
1920
2021
@@ -260,6 +261,12 @@ class DataEditor(NoSSRComponent):
260261 # Allow columns selections. ("none", "single", "multi")
261262 column_select : Var [Literal ["none" , "single" , "multi" ]]
262263
264+ # Allow range selections. ("none", "cell", "rect", "multi-cell", "multi-rect").
265+ range_select : Var [Literal ["none" , "cell" , "rect" , "multi-cell" , "multi-rect" ]]
266+
267+ # Allow row selections. ("none", "single", "multi").
268+ row_select : Var [Literal ["none" , "single" , "multi" ]]
269+
263270 # Prevent diagonal scrolling.
264271 prevent_diagonal_scrolling : Var [bool ]
265272
@@ -275,6 +282,18 @@ class DataEditor(NoSSRComponent):
275282 # Initial scroll offset on the vertical axis.
276283 scroll_offset_y : Var [int ]
277284
285+ # Controls which types of range selections can exist at the same time. ("exclusive", "mixed").
286+ range_selection_blending : Var [Literal ["exclusive" , "mixed" ]]
287+
288+ # Controls which types of column selections can exist at the same time. ("exclusive", "mixed").
289+ column_selection_blending : Var [Literal ["exclusive" , "mixed" ]]
290+
291+ # Controls which types of row selections can exist at the same time. ("exclusive", "mixed").
292+ row_selection_blending : Var [Literal ["exclusive" , "mixed" ]]
293+
294+ # Controls how spans are handled in selections. ("default", "allowPartial").
295+ span_range_behavior : Var [Literal ["default" , "allowPartial" ]]
296+
278297 # global theme
279298 theme : Var [DataEditorTheme | dict ]
280299
@@ -326,6 +345,12 @@ class DataEditor(NoSSRComponent):
326345 # Fired when a row is appended.
327346 on_row_appended : EventHandler [no_args_event_spec ]
328347
348+ # The current grid selection state (columns, rows, and current cell/range). Must be used when on_grid_selection_change is used otherwise updates will not be reflected in the grid.
349+ grid_selection : Var [GridSelection ]
350+
351+ # Fired when the grid selection changes. Will pass the current selection, the selected columns and the selected rows.
352+ on_grid_selection_change : EventHandler [passthrough_event_spec (GridSelection )]
353+
329354 # Fired when the selection is cleared.
330355 on_selection_cleared : EventHandler [no_args_event_spec ]
331356
@@ -342,12 +367,61 @@ def add_imports(self) -> ImportDict:
342367 return {}
343368 return {
344369 "" : f"{ format .format_library_name (self .library )} /dist/index.css" ,
345- self .library : "GridCellKind" ,
370+ self .library : [ "GridCellKind" , "CompactSelection" ] ,
346371 "$/utils/helpers/dataeditor.js" : ImportVar (
347372 tag = "formatDataEditorCells" , is_default = False , install = False
348373 ),
349374 }
350375
376+ def add_custom_code (self ) -> list [str ]:
377+ """Add custom code for reconstructing GridSelection with CompactSelection objects.
378+
379+ Note: When using on_grid_selection_change, Glide Data Grid will not update its internal selection state automatically. Instead,
380+ the grid_selection prop must be updated with a GridSelection object that has CompactSelection objects for the columns and rows properties.
381+ This function provides the necessary JavaScript code to reconstruct the GridSelection object from a dict representation.
382+
383+ Returns:
384+ JavaScript code to reconstruct GridSelection.
385+ """
386+ return [
387+ """
388+ function reconstructGridSelection(selection) {
389+ if (!selection || typeof selection !== 'object') {
390+ return undefined;
391+ }
392+
393+ const reconstructCompactSelection = (data) => {
394+ if (!data || !data.items || !Array.isArray(data.items)) {
395+ return CompactSelection.empty();
396+ }
397+
398+ const items = data.items;
399+ if (items.length === 0) {
400+ return CompactSelection.empty();
401+ }
402+
403+ let result = CompactSelection.empty();
404+
405+ // Items are stored as [start, end) ranges in CompactSelection internal format
406+ for (const item of items) {
407+ if (Array.isArray(item) && item.length === 2) {
408+ const [start, end] = item;
409+ result = result.add([start, end]);
410+ }
411+ }
412+
413+ return result;
414+ };
415+
416+ return {
417+ current: selection.current || undefined,
418+ columns: reconstructCompactSelection(selection.columns),
419+ rows: reconstructCompactSelection(selection.rows)
420+ };
421+ }
422+ """
423+ ]
424+
351425 def add_hooks (self ) -> list [str ]:
352426 """Get the hooks to render.
353427
@@ -429,6 +503,15 @@ def create(cls, *children, **props) -> Component:
429503 console .warn (
430504 "get_cell_content is not user configurable, the provided value will be discarded"
431505 )
506+
507+ # Apply the reconstruction function to grid_selection if it's a Var
508+ if (grid_selection := props .get ("grid_selection" )) is not None and isinstance (
509+ grid_selection , Var
510+ ):
511+ props ["grid_selection" ] = FunctionStringVar .create (
512+ "reconstructGridSelection"
513+ ).call (grid_selection )
514+
432515 grid = super ().create (* children , ** props )
433516 return Div .create (
434517 grid ,
0 commit comments